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