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