xref: /netbsd-src/sys/arch/mips/cavium/dev/octeon_powvar.h (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
1 /*	$NetBSD: octeon_powvar.h,v 1.3 2018/04/19 21:50:06 christos 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 #define POW_TAG_TYPE_ORDERED	0
35 #define POW_TAG_TYPE_ATOMIC	1
36 #define POW_TAG_TYPE_NULL	2
37 #define POW_TAG_TYPE_NULL_NULL	3
38 
39 #define POW_TAG_OP_SWTAG		0
40 #define POW_TAG_OP_SWTAG_FULL		1
41 #define POW_TAG_OP_SWTAG_DESCHED	2
42 #define POW_TAG_OP_DESCHED		3
43 #define POW_TAG_OP_ADDWQ		4
44 #define POW_TAG_OP_UPD_WQP_GRP		5
45 #define POW_TAG_OP_CLR_NSCHED		7
46 #define POW_TAG_OP_NOP			15
47 
48 #define POW_WAIT	1
49 #define POW_NO_WAIT	0
50 
51 /* XXX */
52 struct octeon_pow_softc {
53 	device_t		sc_dev;
54 	bus_space_tag_t		sc_regt;
55 	bus_space_handle_t	sc_regh;
56 	int			sc_port;
57 	int			sc_int_pc_base;
58 #ifdef OCTEON_ETH_DEBUG
59 	struct evcnt		sc_ev_powecciopcsrpend;
60 	struct evcnt		sc_ev_powecciopdbgpend;
61 	struct evcnt		sc_ev_powecciopaddwork;
62 	struct evcnt		sc_ev_powecciopillop;
63 	struct evcnt		sc_ev_poweccioppend24;
64 	struct evcnt		sc_ev_poweccioppend23;
65 	struct evcnt		sc_ev_poweccioppend22;
66 	struct evcnt		sc_ev_poweccioppend21;
67 	struct evcnt		sc_ev_poweccioptagnull;
68 	struct evcnt		sc_ev_poweccioptagnullnull;
69 	struct evcnt		sc_ev_powecciopordatom;
70 	struct evcnt		sc_ev_powecciopnull;
71 	struct evcnt		sc_ev_powecciopnullnull;
72 	struct evcnt		sc_ev_poweccrpe;
73 	struct evcnt		sc_ev_poweccsyn;
74 	struct evcnt		sc_ev_poweccdbe;
75 	struct evcnt		sc_ev_poweccsbe;
76 #endif
77 };
78 
79 /* XXX */
80 struct octeon_pow_attach_args {
81 	int			aa_port;
82 	bus_space_tag_t		aa_regt;
83 };
84 
85 void			octeon_pow_config(struct octeon_pow_softc *, int);
86 void			*octeon_pow_intr_establish(int, int,
87 			    void (*)(void *, uint64_t *),
88 			    void (*)(int *, int *, uint64_t, void *),
89 			    void *);
90 void			octeon_pow_error_int_enable(void *, int);
91 uint64_t		octeon_pow_error_int_summary(void *);
92 int			octeon_pow_ring_reduce(void *);
93 int			octeon_pow_ring_grow(void *);
94 int			octeon_pow_ring_size(void);
95 int			octeon_pow_ring_intr(void);
96 
97 #define	_POW_RD8(sc, off) \
98 	bus_space_read_8((sc)->sc_regt, (sc)->sc_regh, (off))
99 #define	_POW_WR8(sc, off, v) \
100 	bus_space_write_8((sc)->sc_regt, (sc)->sc_regh, (off), (v))
101 #define	_POW_GROUP_RD8(sc, pi, off) \
102 	bus_space_read_8((sc)->sc_regt, (sc)->sc_regh, \
103 	    (off) + sizeof(uint64_t) * (pi)->pi_group)
104 #define	_POW_GROUP_WR8(sc, pi, off, v) \
105 	bus_space_write_8((sc)->sc_regt, (sc)->sc_regh, \
106 	    (off) + sizeof(uint64_t) * (pi)->pi_group, (v))
107 
108 extern struct octeon_pow_softc	octeon_pow_softc;
109 
110 /* -------------------------------------------------------------------------- */
111 
112 /* Load Operations */
113 
114 /* GET_WORK Loads */
115 
116 static __inline uint64_t
117 octeon_pow_ops_get_work_load(
118 	int wait)			/* 0-1 */
119 {
120 	uint64_t ptr =
121 	    POW_OPERATION_BASE_IO_BIT |
122 	    __BITS64_SET(POW_OPERATION_BASE_MAJOR_DID, 0x0c) |
123 	    __BITS64_SET(POW_OPERATION_BASE_SUB_DID, 0x00) |
124 	    __BITS64_SET(POW_GET_WORK_LOAD_WAIT, wait);
125 
126 	return octeon_xkphys_read_8(ptr);
127 }
128 
129 /* POW Status Loads */
130 
131 /*
132  * a) get_cur == 0, get_wqp == 0 (pend_tag)
133  * b) get_cur == 0, get_wqp == 1 (pend_wqp)
134  * c) get_cur == 1, get_wqp == 0, get_rev == 0 (cur_tag_next)
135  * d) get_cur == 1, get_wqp == 0, get_rev == 1 (cur_tag_prev)
136  * e) get_cur == 1, get_wqp == 1, get_rev == 0 (cur_wqp_next)
137  * f) get_cur == 1, get_wqp == 1, get_rev == 1 (cur_wqp_prev)
138  */
139 
140 static __inline uint64_t
141 octeon_pow_ops_pow_status(
142 	int coreid,			/* 0-15 */
143 	int get_rev,			/* 0-1 */
144 	int get_cur,			/* 0-1 */
145 	int get_wqp)			/* 0-1 */
146 {
147 	uint64_t ptr =
148 	    POW_OPERATION_BASE_IO_BIT |
149 	    __BITS64_SET(POW_OPERATION_BASE_MAJOR_DID, 0x0c) |
150 	    __BITS64_SET(POW_OPERATION_BASE_SUB_DID, 0x01) |
151 	    __BITS64_SET(POW_STATUS_LOAD_COREID, coreid) |
152 	    __BITS64_SET(POW_STATUS_LOAD_GET_REV, get_rev) |
153 	    __BITS64_SET(POW_STATUS_LOAD_GET_CUR, get_cur) |
154 	    __BITS64_SET(POW_STATUS_LOAD_GET_WQP, get_wqp);
155 
156 	return octeon_xkphys_read_8(ptr);
157 }
158 
159 /* POW Memory Loads */
160 
161 /*
162  * a) get_des == 0, get_wqp == 0 (tag)
163  * b) get_des == 0, get_wqp == 1 (wqe)
164  * c) get_des == 1 (desched)
165  */
166 
167 static __inline uint64_t
168 octeon_pow_ops_pow_memory(
169 	int index,			/* 0-2047 */
170 	int get_des,			/* 0-1 */
171 	int get_wqp)			/* 0-1 */
172 {
173 	uint64_t ptr =
174 	    POW_OPERATION_BASE_IO_BIT |
175 	    __BITS64_SET(POW_OPERATION_BASE_MAJOR_DID, 0x0c) |
176 	    __BITS64_SET(POW_OPERATION_BASE_SUB_DID, 0x02) |
177 	    __BITS64_SET(POW_MEMORY_LOAD_INDEX, index) |
178 	    __BITS64_SET(POW_MEMORY_LOAD_GET_DES, get_des) |
179 	    __BITS64_SET(POW_MEMORY_LOAD_GET_WQP, get_wqp);
180 
181 	return octeon_xkphys_read_8(ptr);
182 }
183 
184 /* POW Index/Pointer Loads */
185 
186 /*
187  * a) get_rmt == 0, get_des_get_tail == 0
188  * b) get_rmt == 0, get_des_get_tail == 1
189  * c) get_rmt == 1, get_des_get_tail == 0
190  * d) get_rmt == 1, get_des_get_tail == 1
191  */
192 
193 static __inline uint64_t
194 octeon_pow_ops_pow_idxptr(
195 	int qosgrp,			/* 0-7 */
196 	int get_des_get_tail,		/* 0-1 */
197 	int get_rmt)			/* 0-1 */
198 {
199 	uint64_t ptr =
200 	    POW_OPERATION_BASE_IO_BIT |
201 	    __BITS64_SET(POW_OPERATION_BASE_MAJOR_DID, 0x0c) |
202 	    __BITS64_SET(POW_OPERATION_BASE_SUB_DID, 0x03) |
203 	    __BITS64_SET(POW_IDXPTR_LOAD_QOSGRP, qosgrp) |
204 	    __BITS64_SET(POW_IDXPTR_LOAD_GET_DES_GET_TAIL, get_des_get_tail) |
205 	    __BITS64_SET(POW_IDXPTR_LOAD_GET_RMT, get_rmt);
206 
207 	return octeon_xkphys_read_8(ptr);
208 }
209 
210 /* NULL_RD Loads */
211 
212 static __inline uint64_t
213 octeon_pow_ops_null_rd_load(void)
214 {
215 	uint64_t ptr =
216 	    POW_OPERATION_BASE_IO_BIT |
217 	    __BITS64_SET(POW_OPERATION_BASE_MAJOR_DID, 0x0c) |
218 	    __BITS64_SET(POW_OPERATION_BASE_SUB_DID, 0x04);
219 
220 	return octeon_xkphys_read_8(ptr);
221 }
222 
223 /* IOBDMA Operations */
224 
225 /* ``subdid'' values are inverted between ``get_work_addr'' and ``null_read_id'' */
226 
227 /* The ``scraddr'' part is index in 8 byte words, not address. */
228 
229 /* GET_WORK IOBDMAs */
230 
231 static __inline void
232 octeon_pow_ops_get_work_iobdma(
233 	int scraddr,			/* 0-2047 */
234 	int wait)			/* 0-1 */
235 {
236  	/* ``scraddr'' part is index in 64-bit words, not address */
237 	const int scrindex = scraddr / sizeof(uint64_t);
238 
239         uint64_t args =
240              __BITS64_SET(POW_IOBDMA_GET_WORK_WAIT, wait);
241         uint64_t value =
242             __BITS64_SET(POW_IOBDMA_BASE_SCRADDR, scrindex) |
243             __BITS64_SET(POW_IOBDMA_BASE_LEN, 0x01) |
244             __BITS64_SET(POW_IOBDMA_BASE_MAJOR_DID, 0x0c) |
245             __BITS64_SET(POW_IOBDMA_BASE_SUB_DID, 0x00) |
246             __BITS64_SET(POW_IOBDMA_BASE_39_0, args);
247 
248         octeon_iobdma_write_8(value);
249 }
250 
251 /* NULL_RD IOBDMAs */
252 
253 static __inline void
254 octeon_pow_ops_null_rd_iobdma(
255 	int scraddr)			/* 0-2047 */
256 {
257  	/* ``scraddr'' part is index in 64-bit words, not address */
258 	const int scrindex = scraddr / sizeof(uint64_t);
259 
260         uint64_t value =
261             __BITS64_SET(POW_IOBDMA_BASE_SCRADDR, scrindex) |
262             __BITS64_SET(POW_IOBDMA_BASE_LEN, 0x01) |
263             __BITS64_SET(POW_IOBDMA_BASE_MAJOR_DID, 0x0c) |
264             __BITS64_SET(POW_IOBDMA_BASE_SUB_DID, 0x04) |
265             __BITS64_SET(POW_IOBDMA_BASE_39_0, 0);
266 
267         octeon_iobdma_write_8(value);
268 }
269 
270 /* Store Operations */
271 
272 static __inline void
273 octeon_pow_store(
274 	int subdid,			/* 0, 1, 3 */
275 	uint64_t addr,			/* 0-0x0000.000f.ffff.ffff */
276 	int no_sched,			/* 0, 1 */
277 	int index,			/* 0-8191 */
278 	int op,				/* 0-15 */
279 	int qos,			/* 0-7 */
280 	int grp,			/* 0-7 */
281 	int type,			/* 0-7 */
282 	uint32_t tag)			/* 0-0xffff.ffff */
283 {
284 	/* Physical Address to Store to POW */
285 	uint64_t ptr =
286 	    POW_OPERATION_BASE_IO_BIT |
287 	    __BITS64_SET(POW_OPERATION_BASE_MAJOR_DID, 0x0c) |
288 	    __BITS64_SET(POW_OPERATION_BASE_SUB_DID, subdid) |
289 	    __BITS64_SET(POW_PHY_ADDR_STORE_ADDR, addr);
290 
291 	/* Store Data on Store to POW */
292 	uint64_t args =
293 	    __BITS64_SET(POW_STORE_DATA_NO_SCHED, no_sched) |
294 	    __BITS64_SET(POW_STORE_DATA_INDEX, index) |
295 	    __BITS64_SET(POW_STORE_DATA_OP, op) |
296 	    __BITS64_SET(POW_STORE_DATA_QOS, qos) |
297 	    __BITS64_SET(POW_STORE_DATA_GRP, grp) |
298 	    __BITS64_SET(POW_STORE_DATA_TYPE, type) |
299 	    __BITS64_SET(POW_STORE_DATA_TAG, tag);
300 
301 	octeon_xkphys_write_8(ptr, args);
302 }
303 
304 /* SWTAG */
305 
306 static __inline void
307 octeon_pow_ops_swtag(int type, uint32_t tag)
308 {
309 	octeon_pow_store(
310 		1,			/* subdid == 1 */
311 		0, 			/* addr (not used for SWTAG) */
312 		0,			/* no_sched (not used for SWTAG) */
313 		0,			/* index (not used for SWTAG) */
314 		POW_TAG_OP_SWTAG,	/* op == SWTAG */
315 		0,			/* qos (not used for SWTAG) */
316 		0,			/* grp (not used for SWTAG) */
317 		type,
318 		tag);
319 	/* switch to NULL completes immediately */
320 }
321 
322 /* SWTAG_FULL */
323 
324 static __inline void
325 octeon_pow_ops_swtag_full(paddr_t addr, int grp, int type, uint32_t tag)
326 {
327 	octeon_pow_store(
328 		0,			/* subdid == 0 */
329 		addr,
330 		0,			/* no_sched (not used for SWTAG_FULL) */
331 		0,			/* index (not used for SWTAG_FULL) */
332 		POW_TAG_OP_SWTAG_FULL,	/* op == SWTAG_FULL */
333 		0,			/* qos (not used for SWTAG_FULL) */
334 		grp,
335 		type,
336 		tag);
337 }
338 
339 /* SWTAG_DESCHED */
340 
341 static __inline void
342 octeon_pow_ops_swtag_desched(int no_sched, int grp, int type, uint32_t tag)
343 {
344 	octeon_pow_store(
345 		3,			/* subdid == 3 */
346 		0,			/* addr (not used for SWTAG_DESCHED) */
347 		no_sched,
348 		0,			/* index (not used for SWTAG_DESCHED) */
349 		POW_TAG_OP_SWTAG_DESCHED, /* op == SWTAG_DESCHED */
350 		0,			/* qos (not used for SWTAG_DESCHED) */
351 		grp,
352 		type,
353 		tag);
354 }
355 
356 /* DESCHED */
357 
358 static __inline void
359 octeon_pow_ops_desched(int no_sched)
360 {
361 	octeon_pow_store(
362 		3,			/* subdid == 3 */
363 		0,			/* addr (not used for DESCHED) */
364 		no_sched,
365 		0,			/* index (not used for DESCHED) */
366 		POW_TAG_OP_DESCHED,	/* op == DESCHED */
367 		0,			/* qos (not used for DESCHED) */
368 		0,			/* grp (not used for DESCHED) */
369 		0,			/* type (not used for DESCHED) */
370 		0);			/* tag (not used for DESCHED) */
371 }
372 
373 /* ADDWQ */
374 
375 static __inline void
376 octeon_pow_ops_addwq(paddr_t addr, int qos, int grp, int type, uint32_t tag)
377 {
378 	octeon_pow_store(
379 		1,			/* subdid == 1 */
380 		addr,
381 		0,			/* no_sched (not used for ADDWQ) */
382 		0,			/* index (not used for ADDWQ) */
383 		POW_TAG_OP_ADDWQ,	/* op == ADDWQ */
384 		qos,
385 		grp,
386 		type,
387 		tag);
388 }
389 
390 /* UPD_WQP_GRP */
391 
392 static __inline void
393 octeon_pow_ops_upd_wqp_grp(paddr_t addr, int grp)
394 {
395 	octeon_pow_store(
396 		1,			/* subdid == 1 */
397 		addr,
398 		0,			/* no_sched (not used for UPD_WQP_GRP) */
399 		0,			/* index (not used for UPD_WQP_GRP) */
400 		POW_TAG_OP_UPD_WQP_GRP,	/* op == UPD_WQP_GRP */
401 		0,			/* qos (not used for UPD_WQP_GRP) */
402 		grp,
403 		0,			/* type (not used for UPD_WQP_GRP) */
404 		0);			/* tag (not used for UPD_WQP_GRP) */
405 }
406 
407 /* CLR_NSCHED */
408 
409 static __inline void
410 octeon_pow_ops_clr_nsched(paddr_t addr, int index)
411 {
412 	octeon_pow_store(
413 		1,			/* subdid == 1 */
414 		addr,
415 		0,			/* no_sched (not used for CLR_NSCHED) */
416 		index,
417 		POW_TAG_OP_CLR_NSCHED,	/* op == CLR_NSCHED */
418 		0,			/* qos (not used for CLR_NSCHED) */
419 		0,			/* grp (not used for CLR_NSCHED) */
420 		0,			/* type (not used for CLR_NSCHED) */
421 		0);			/* tag (not used for CLR_NSCHED) */
422 }
423 
424 /* NOP */
425 
426 static __inline void
427 octeon_pow_ops_nop(void)
428 {
429 	octeon_pow_store(
430 		1,			/* subdid == 1 */
431 		0,			/* addr (not used for NOP) */
432 		0,			/* no_sched (not used for NOP) */
433 		0,			/* index (not used for NOP) */
434 		POW_TAG_OP_NOP,		/* op == NOP */
435 		0,			/* qos (not used for NOP) */
436 		0,			/* grp (not used for NOP) */
437 		0,			/* type (not used for NOP) */
438 		0);			/* tag (not used for NOP) */
439 }
440 
441 /* -------------------------------------------------------------------------- */
442 
443 /*
444  * global functions
445  */
446 static __inline void
447 octeon_pow_work_request_async(uint64_t scraddr, uint64_t wait)
448 {
449         octeon_pow_ops_get_work_iobdma(scraddr, wait);
450 }
451 
452 static __inline uint64_t *
453 octeon_pow_work_response_async(uint64_t scraddr)
454 {
455 	uint64_t result;
456 
457 	OCTEON_SYNCIOBDMA;
458 	result = octeon_cvmseg_read_8(scraddr);
459 
460 	paddr_t addr = result & POW_IOBDMA_GET_WORK_RESULT_ADDR;
461 
462 	if (result & POW_IOBDMA_GET_WORK_RESULT_NO_WORK)
463 	    return NULL;
464 #ifdef __mips_n32
465 	KASSERT(addr < MIPS_PHYS_MASK);
466 	//if (addr < MIPS_PHYS_MASK)
467 		return (uint64_t *)MIPS_PHYS_TO_KSEG0(addr);
468 #else
469 	return (uint64_t *)MIPS_PHYS_TO_XKPHYS_CACHED(addr);
470 #endif
471 }
472 
473 static __inline void
474 octeon_pow_config_int_pc(struct octeon_pow_softc *sc, int unit)
475 {
476 	uint64_t wq_int_pc;
477 	uint64_t pc_thr;
478 	static uint64_t cpu_clock_hz;
479 
480 	if (cpu_clock_hz == 0)
481 		cpu_clock_hz  = curcpu()->ci_cpu_freq;
482 
483 	/* from SDK */
484 	pc_thr = (cpu_clock_hz) / (unit * 16 * 256);
485 
486 	wq_int_pc = pc_thr << POW_WQ_INT_PC_PC_THR_SHIFT;
487 	_POW_WR8(sc, POW_WQ_INT_PC_OFFSET, wq_int_pc);
488 }
489 
490 static __inline void
491 octeon_pow_config_int_pc_rate(struct octeon_pow_softc *sc, int rate)
492 {
493 	octeon_pow_config_int_pc(sc, sc->sc_int_pc_base / rate);
494 }
495 
496 /* wait until ready */
497 static __inline void
498 octeon_pow_tag_sw_wait(void)
499 {
500 	__asm __volatile (
501 		"	.set	push		\n"
502 		"	.set	noreorder	\n"
503 		"	.set	arch=octeon	\n"
504 		"1:	rdhwr	$2, $30		\n"
505 		"	beqz	$2, 1b		\n"
506 		"	 nop			\n"
507 		"	.set	pop		\n"
508 	);
509 }
510 
511 #endif /* _OCTEON_POWVAR_H_ */
512