octeon_powvar.h revision 1.5 1 /* $NetBSD: octeon_powvar.h,v 1.5 2020/06/18 13:52:08 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 /* XXX */
54 struct octpow_softc {
55 device_t sc_dev;
56 bus_space_tag_t sc_regt;
57 bus_space_handle_t sc_regh;
58 int sc_port;
59 int sc_int_pc_base;
60 #ifdef CNMAC_DEBUG
61 struct evcnt sc_ev_powecciopcsrpend;
62 struct evcnt sc_ev_powecciopdbgpend;
63 struct evcnt sc_ev_powecciopaddwork;
64 struct evcnt sc_ev_powecciopillop;
65 struct evcnt sc_ev_poweccioppend24;
66 struct evcnt sc_ev_poweccioppend23;
67 struct evcnt sc_ev_poweccioppend22;
68 struct evcnt sc_ev_poweccioppend21;
69 struct evcnt sc_ev_poweccioptagnull;
70 struct evcnt sc_ev_poweccioptagnullnull;
71 struct evcnt sc_ev_powecciopordatom;
72 struct evcnt sc_ev_powecciopnull;
73 struct evcnt sc_ev_powecciopnullnull;
74 struct evcnt sc_ev_poweccrpe;
75 struct evcnt sc_ev_poweccsyn;
76 struct evcnt sc_ev_poweccdbe;
77 struct evcnt sc_ev_poweccsbe;
78 #endif
79 };
80
81 /* XXX */
82 struct octpow_attach_args {
83 int aa_port;
84 bus_space_tag_t aa_regt;
85 };
86
87 void octpow_config(struct octpow_softc *, int);
88 void *octpow_intr_establish(int, int,
89 void (*)(void *, uint64_t *),
90 void (*)(int *, int *, uint64_t, void *),
91 void *);
92 void octpow_error_int_enable(void *, int);
93 uint64_t octpow_error_int_summary(void *);
94 int octpow_ring_reduce(void *);
95 int octpow_ring_grow(void *);
96 int octpow_ring_size(void);
97 int octpow_ring_intr(void);
98
99 #define _POW_RD8(sc, off) \
100 bus_space_read_8((sc)->sc_regt, (sc)->sc_regh, (off))
101 #define _POW_WR8(sc, off, v) \
102 bus_space_write_8((sc)->sc_regt, (sc)->sc_regh, (off), (v))
103 #define _POW_GROUP_RD8(sc, pi, off) \
104 bus_space_read_8((sc)->sc_regt, (sc)->sc_regh, \
105 (off) + sizeof(uint64_t) * (pi)->pi_group)
106 #define _POW_GROUP_WR8(sc, pi, off, v) \
107 bus_space_write_8((sc)->sc_regt, (sc)->sc_regh, \
108 (off) + sizeof(uint64_t) * (pi)->pi_group, (v))
109
110 extern struct octpow_softc octpow_softc;
111
112 /* -------------------------------------------------------------------------- */
113
114 /* Load Operations */
115
116 /* GET_WORK Loads */
117
118 static __inline uint64_t
119 octpow_ops_get_work_load(
120 int wait) /* 0-1 */
121 {
122 uint64_t ptr =
123 OCTEON_ADDR_IO_DID(POW_MAJOR_DID, POW_OP_SUBDID_GET_WORK) |
124 (wait ? POW_GET_WORK_LOAD_WAIT : 0);
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 octpow_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 OCTEON_ADDR_IO_DID(POW_MAJOR_DID, POW_OP_SUBDID_STATUS_LOAD) |
149 __SHIFTIN(coreid, POW_STATUS_LOAD_COREID) |
150 __SHIFTIN(get_rev, POW_STATUS_LOAD_GET_REV) |
151 __SHIFTIN(get_cur, POW_STATUS_LOAD_GET_CUR) |
152 __SHIFTIN(get_wqp, POW_STATUS_LOAD_GET_WQP);
153
154 return octeon_xkphys_read_8(ptr);
155 }
156
157 /* POW Memory Loads */
158
159 /*
160 * a) get_des == 0, get_wqp == 0 (tag)
161 * b) get_des == 0, get_wqp == 1 (wqe)
162 * c) get_des == 1 (desched)
163 */
164
165 static __inline uint64_t
166 octpow_ops_pow_memory(
167 int index, /* 0-2047 */
168 int get_des, /* 0-1 */
169 int get_wqp) /* 0-1 */
170 {
171 uint64_t ptr =
172 OCTEON_ADDR_IO_DID(POW_MAJOR_DID, POW_OP_SUBDID_MEMORY_LOAD) |
173 __SHIFTIN(index, POW_MEMORY_LOAD_INDEX) |
174 __SHIFTIN(get_des, POW_MEMORY_LOAD_GET_DES) |
175 __SHIFTIN(get_wqp, POW_MEMORY_LOAD_GET_WQP);
176
177 return octeon_xkphys_read_8(ptr);
178 }
179
180 /* POW Index/Pointer Loads */
181
182 /*
183 * a) get_rmt == 0, get_des_get_tail == 0
184 * b) get_rmt == 0, get_des_get_tail == 1
185 * c) get_rmt == 1, get_des_get_tail == 0
186 * d) get_rmt == 1, get_des_get_tail == 1
187 */
188
189 static __inline uint64_t
190 octpow_ops_pow_idxptr(
191 int qosgrp, /* 0-7 */
192 int get_des_get_tail, /* 0-1 */
193 int get_rmt) /* 0-1 */
194 {
195 uint64_t ptr =
196 OCTEON_ADDR_IO_DID(POW_MAJOR_DID, POW_OP_SUBDID_IDXPTR_LOAD) |
197 __SHIFTIN(qosgrp, POW_IDXPTR_LOAD_QOSGRP) |
198 __SHIFTIN(get_des_get_tail, POW_IDXPTR_LOAD_GET_DES_GET_TAIL) |
199 __SHIFTIN(get_rmt, POW_IDXPTR_LOAD_GET_RMT);
200
201 return octeon_xkphys_read_8(ptr);
202 }
203
204 /* NULL_RD Loads */
205
206 static __inline uint64_t
207 octpow_ops_null_rd_load(void)
208 {
209 uint64_t ptr = OCTEON_ADDR_IO_DID(POW_MAJOR_DID, POW_OP_SUBDID_NULL_RD);
210
211 return octeon_xkphys_read_8(ptr);
212 }
213
214 /* IOBDMA Operations */
215
216 /* ``subdid'' values are inverted between ``get_work_addr'' and ``null_read_id'' */
217
218 /* The ``scraddr'' part is index in 8 byte words, not address. */
219
220 /* GET_WORK IOBDMAs */
221
222 static __inline void
223 octpow_ops_get_work_iobdma(
224 int scraddr, /* 0-2047 */
225 int wait) /* 0-1 */
226 {
227 /* ``scraddr'' part is index in 64-bit words, not address */
228 const int scrindex = scraddr / sizeof(uint64_t);
229
230 uint64_t value = IOBDMA_CREATE(POW_MAJOR_DID,
231 POW_IOBDMA_SUBDID_GET_WORK, scrindex, POW_IOBDMA_LEN,
232 wait ? POW_IOBDMA_GET_WORK_WAIT : 0);
233
234 octeon_iobdma_write_8(value);
235 }
236
237 /* NULL_RD IOBDMAs */
238
239 static __inline void
240 octpow_ops_null_rd_iobdma(
241 int scraddr) /* 0-2047 */
242 {
243 /* ``scraddr'' part is index in 64-bit words, not address */
244 const int scrindex = scraddr / sizeof(uint64_t);
245
246 uint64_t value = IOBDMA_CREATE(POW_MAJOR_DID,
247 POW_IOBDMA_SUBDID_NULL_RD, scrindex, POW_IOBDMA_LEN, 0);
248
249 octeon_iobdma_write_8(value);
250 }
251
252 /* Store Operations */
253
254 static __inline void
255 octpow_store(
256 int subdid, /* 0, 1, 3 */
257 uint64_t addr, /* 0-0x0000.000f.ffff.ffff */
258 int no_sched, /* 0, 1 */
259 int index, /* 0-8191 */
260 int op, /* 0-15 */
261 int qos, /* 0-7 */
262 int grp, /* 0-7 */
263 int type, /* 0-7 */
264 uint32_t tag) /* 0-0xffff.ffff */
265 {
266 /* Physical Address to Store to POW */
267 uint64_t ptr = OCTEON_ADDR_IO_DID(POW_MAJOR_DID, subdid) |
268 __SHIFTIN(addr, POW_PHY_ADDR_STORE_ADDR);
269
270 /* Store Data on Store to POW */
271 uint64_t args =
272 __SHIFTIN(no_sched, POW_STORE_DATA_NO_SCHED) |
273 __SHIFTIN(index, POW_STORE_DATA_INDEX) |
274 __SHIFTIN(op, POW_STORE_DATA_OP) |
275 __SHIFTIN(qos, POW_STORE_DATA_QOS) |
276 __SHIFTIN(grp, POW_STORE_DATA_GRP) |
277 __SHIFTIN(type, POW_STORE_DATA_TYPE) |
278 __SHIFTIN(tag, POW_STORE_DATA_TAG);
279
280 octeon_xkphys_write_8(ptr, args);
281 }
282
283 /* SWTAG */
284
285 static __inline void
286 octpow_ops_swtag(int type, uint32_t tag)
287 {
288
289 octpow_store(
290 POW_STORE_SUBDID_OTHER,
291 0, /* addr (not used for SWTAG) */
292 0, /* no_sched (not used for SWTAG) */
293 0, /* index (not used for SWTAG) */
294 POW_TAG_OP_SWTAG, /* op == SWTAG */
295 0, /* qos (not used for SWTAG) */
296 0, /* grp (not used for SWTAG) */
297 type,
298 tag);
299 /* switch to NULL completes immediately */
300 }
301
302 /* SWTAG_FULL */
303
304 static __inline void
305 octpow_ops_swtag_full(paddr_t addr, int grp, int type, uint32_t tag)
306 {
307
308 octpow_store(
309 POW_STORE_SUBDID_SWTAG_FULL,
310 addr,
311 0, /* no_sched (not used for SWTAG_FULL) */
312 0, /* index (not used for SWTAG_FULL) */
313 POW_TAG_OP_SWTAG_FULL, /* op == SWTAG_FULL */
314 0, /* qos (not used for SWTAG_FULL) */
315 grp,
316 type,
317 tag);
318 }
319
320 /* SWTAG_DESCHED */
321
322 static __inline void
323 octpow_ops_swtag_desched(int no_sched, int grp, int type, uint32_t tag)
324 {
325
326 octpow_store(
327 POW_STORE_SUBDID_DESCHED,
328 0, /* addr (not used for SWTAG_DESCHED) */
329 no_sched,
330 0, /* index (not used for SWTAG_DESCHED) */
331 POW_TAG_OP_SWTAG_DESCHED, /* op == SWTAG_DESCHED */
332 0, /* qos (not used for SWTAG_DESCHED) */
333 grp,
334 type,
335 tag);
336 }
337
338 /* DESCHED */
339
340 static __inline void
341 octpow_ops_desched(int no_sched)
342 {
343
344 octpow_store(
345 POW_STORE_SUBDID_DESCHED,
346 0, /* addr (not used for DESCHED) */
347 no_sched,
348 0, /* index (not used for DESCHED) */
349 POW_TAG_OP_DESCHED, /* op == DESCHED */
350 0, /* qos (not used for DESCHED) */
351 0, /* grp (not used for DESCHED) */
352 0, /* type (not used for DESCHED) */
353 0); /* tag (not used for DESCHED) */
354 }
355
356 /* ADDWQ */
357
358 static __inline void
359 octpow_ops_addwq(paddr_t addr, int qos, int grp, int type, uint32_t tag)
360 {
361
362 octpow_store(
363 POW_STORE_SUBDID_OTHER,
364 addr,
365 0, /* no_sched (not used for ADDWQ) */
366 0, /* index (not used for ADDWQ) */
367 POW_TAG_OP_ADDWQ, /* op == ADDWQ */
368 qos,
369 grp,
370 type,
371 tag);
372 }
373
374 /* UPD_WQP_GRP */
375
376 static __inline void
377 octpow_ops_upd_wqp_grp(paddr_t addr, int grp)
378 {
379
380 octpow_store(
381 POW_STORE_SUBDID_OTHER,
382 addr,
383 0, /* no_sched (not used for UPD_WQP_GRP) */
384 0, /* index (not used for UPD_WQP_GRP) */
385 POW_TAG_OP_UPD_WQP_GRP, /* op == UPD_WQP_GRP */
386 0, /* qos (not used for UPD_WQP_GRP) */
387 grp,
388 0, /* type (not used for UPD_WQP_GRP) */
389 0); /* tag (not used for UPD_WQP_GRP) */
390 }
391
392 /* CLR_NSCHED */
393
394 static __inline void
395 octpow_ops_clr_nsched(paddr_t addr, int index)
396 {
397
398 octpow_store(
399 POW_STORE_SUBDID_OTHER,
400 addr,
401 0, /* no_sched (not used for CLR_NSCHED) */
402 index,
403 POW_TAG_OP_CLR_NSCHED, /* op == CLR_NSCHED */
404 0, /* qos (not used for CLR_NSCHED) */
405 0, /* grp (not used for CLR_NSCHED) */
406 0, /* type (not used for CLR_NSCHED) */
407 0); /* tag (not used for CLR_NSCHED) */
408 }
409
410 /* NOP */
411
412 static __inline void
413 octpow_ops_nop(void)
414 {
415
416 octpow_store(
417 POW_STORE_SUBDID_OTHER,
418 0, /* addr (not used for NOP) */
419 0, /* no_sched (not used for NOP) */
420 0, /* index (not used for NOP) */
421 POW_TAG_OP_NOP, /* op == NOP */
422 0, /* qos (not used for NOP) */
423 0, /* grp (not used for NOP) */
424 0, /* type (not used for NOP) */
425 0); /* tag (not used for NOP) */
426 }
427
428 /* -------------------------------------------------------------------------- */
429
430 /*
431 * global functions
432 */
433 static __inline void
434 octpow_work_request_async(uint64_t scraddr, uint64_t wait)
435 {
436
437 octpow_ops_get_work_iobdma(scraddr, wait);
438 }
439
440 static __inline uint64_t *
441 octpow_work_response_async(uint64_t scraddr)
442 {
443 uint64_t result;
444
445 OCTEON_SYNCIOBDMA;
446 result = octeon_cvmseg_read_8(scraddr);
447
448 paddr_t addr = result & POW_IOBDMA_GET_WORK_RESULT_ADDR;
449
450 if (result & POW_IOBDMA_GET_WORK_RESULT_NO_WORK)
451 return NULL;
452 #ifdef __mips_n32
453 KASSERT(addr < MIPS_PHYS_MASK);
454 //if (addr < MIPS_PHYS_MASK)
455 return (uint64_t *)MIPS_PHYS_TO_KSEG0(addr);
456 #else
457 return (uint64_t *)MIPS_PHYS_TO_XKPHYS_CACHED(addr);
458 #endif
459 }
460
461 static __inline void
462 octpow_config_int_pc(struct octpow_softc *sc, int unit)
463 {
464 uint64_t wq_int_pc;
465 uint64_t pc_thr;
466 static uint64_t cpu_clock_hz;
467
468 if (cpu_clock_hz == 0)
469 cpu_clock_hz = curcpu()->ci_cpu_freq;
470
471 /* from SDK */
472 pc_thr = (cpu_clock_hz) / (unit * 16 * 256);
473
474 wq_int_pc = __SHIFTIN(pc_thr, POW_WQ_INT_PC_PC_THR);
475 _POW_WR8(sc, POW_WQ_INT_PC_OFFSET, wq_int_pc);
476 }
477
478 static __inline void
479 octpow_config_int_pc_rate(struct octpow_softc *sc, int rate)
480 {
481
482 octpow_config_int_pc(sc, sc->sc_int_pc_base / rate);
483 }
484
485 /* wait until ready */
486 static __inline void
487 octpow_tag_sw_wait(void)
488 {
489 __asm __volatile (
490 " .set push \n"
491 " .set noreorder \n"
492 " .set arch=octeon \n"
493 "1: rdhwr $2, $30 \n"
494 " beqz $2, 1b \n"
495 " nop \n"
496 " .set pop \n"
497 );
498 }
499
500 #endif /* _OCTEON_POWVAR_H_ */
501