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