1 /* $OpenBSD: cn30xxpow.c,v 1.8 2016/07/10 10:18:58 visa 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 #include <sys/param.h> 30 #include <sys/systm.h> 31 #include <sys/types.h> 32 #include <sys/kernel.h> /* hz */ 33 #include <sys/malloc.h> 34 35 #include <machine/bus.h> 36 #include <machine/octeonvar.h> 37 38 #include <octeon/dev/iobusvar.h> 39 #include <octeon/dev/cn30xxciureg.h> /* XXX */ 40 #include <octeon/dev/cn30xxpowreg.h> 41 #include <octeon/dev/cn30xxpowvar.h> 42 43 extern int ipflow_fastforward_disable_flags; 44 45 struct cn30xxpow_intr_handle { 46 void *pi_ih; 47 struct cn30xxpow_softc *pi_sc; 48 int pi_group; 49 void (*pi_cb)(void *, uint64_t *); 50 void *pi_data; 51 52 #ifdef OCTEON_ETH_DEBUG 53 #define _EV_PER_N 32 /* XXX */ 54 #define _EV_IVAL_N 32 /* XXX */ 55 int pi_first; 56 struct timeval pi_last; 57 #endif 58 }; 59 60 void cn30xxpow_bootstrap(struct octeon_config *); 61 62 #ifdef OCTEON_ETH_DEBUG 63 void cn30xxpow_intr_rml(void *); 64 65 void cn30xxpow_intr_debug_init(struct cn30xxpow_intr_handle *, int); 66 void cn30xxpow_intr_work_debug_ival(struct cn30xxpow_softc *, 67 struct cn30xxpow_intr_handle *); 68 #endif 69 void cn30xxpow_init(struct cn30xxpow_softc *); 70 void cn30xxpow_init_regs(struct cn30xxpow_softc *); 71 int cn30xxpow_tag_sw_poll(void); 72 void cn30xxpow_tag_sw_wait(void); 73 void cn30xxpow_config_int_pc(struct cn30xxpow_softc *, int); 74 void cn30xxpow_config_int(struct cn30xxpow_softc *, int, 75 uint64_t, uint64_t, uint64_t); 76 void cn30xxpow_intr_work(struct cn30xxpow_softc *, 77 struct cn30xxpow_intr_handle *, int); 78 int cn30xxpow_intr(void *); 79 80 #ifdef OCTEON_ETH_DEBUG 81 void cn30xxpow_dump(void); 82 #endif 83 84 /* XXX */ 85 struct cn30xxpow_softc cn30xxpow_softc; 86 87 #ifdef OCTEON_ETH_DEBUG 88 struct cn30xxpow_softc *__cn30xxpow_softc; 89 #endif 90 91 /* 92 * XXX: parameter tuning is needed: see files.octeon 93 */ 94 #ifndef OCTEON_ETH_RING_MAX 95 #define OCTEON_ETH_RING_MAX 512 96 #endif 97 #ifndef OCTEON_ETH_RING_MIN 98 #define OCTEON_ETH_RING_MIN 1 99 #endif 100 101 #ifdef OCTEON_ETH_INTR_FEEDBACK_RING 102 int max_recv_cnt = OCTEON_ETH_RING_MAX; 103 int min_recv_cnt = OCTEON_ETH_RING_MIN; 104 int recv_cnt = OCTEON_ETH_RING_MIN; 105 int int_rate = 1; 106 #else 107 /* infinity */ 108 int max_recv_cnt = 0; 109 int min_recv_cnt = 0; 110 int recv_cnt = 0; 111 #endif 112 113 /* -------------------------------------------------------------------------- */ 114 115 /* ---- operation primitive functions */ 116 117 /* 5.11.1 Load Operations */ 118 119 /* 5.11.2 IOBDMA Operations */ 120 121 /* 5.11.3 Store Operations */ 122 123 /* -------------------------------------------------------------------------- */ 124 125 /* ---- utility functions */ 126 127 void 128 cn30xxpow_work_request_async(uint64_t scraddr, uint64_t wait) 129 { 130 cn30xxpow_ops_get_work_iobdma(scraddr, wait); 131 } 132 133 uint64_t * 134 cn30xxpow_work_response_async(uint64_t scraddr) 135 { 136 uint64_t result; 137 138 octeon_synciobdma(); 139 result = octeon_cvmseg_read_8(scraddr); 140 141 return (result & POW_IOBDMA_GET_WORK_RESULT_NO_WORK) ? 142 NULL : 143 (uint64_t *)PHYS_TO_XKPHYS( 144 result & POW_IOBDMA_GET_WORK_RESULT_ADDR, CCA_CACHED); 145 } 146 147 /* ---- status by coreid */ 148 149 static inline uint64_t 150 cn30xxpow_status_by_coreid_pend_tag(int coreid) 151 { 152 return cn30xxpow_ops_pow_status(coreid, 0, 0, 0); 153 } 154 155 static inline uint64_t 156 cn30xxpow_status_by_coreid_pend_wqp(int coreid) 157 { 158 return cn30xxpow_ops_pow_status(coreid, 0, 0, 1); 159 } 160 161 static inline uint64_t 162 cn30xxpow_status_by_coreid_cur_tag_next(int coreid) 163 { 164 return cn30xxpow_ops_pow_status(coreid, 0, 1, 0); 165 } 166 167 static inline uint64_t 168 cn30xxpow_status_by_coreid_cur_tag_prev(int coreid) 169 { 170 return cn30xxpow_ops_pow_status(coreid, 1, 1, 0); 171 } 172 173 static inline uint64_t 174 cn30xxpow_status_by_coreid_cur_wqp_next(int coreid) 175 { 176 return cn30xxpow_ops_pow_status(coreid, 0, 1, 1); 177 } 178 179 static inline uint64_t 180 cn30xxpow_status_by_coreid_cur_wqp_prev(int coreid) 181 { 182 return cn30xxpow_ops_pow_status(coreid, 1, 1, 1); 183 } 184 185 /* ---- status by index */ 186 187 static inline uint64_t 188 cn30xxpow_status_by_index_tag(int index) 189 { 190 return cn30xxpow_ops_pow_memory(index, 0, 0); 191 } 192 193 static inline uint64_t 194 cn30xxpow_status_by_index_wqp(int index) 195 { 196 return cn30xxpow_ops_pow_memory(index, 0, 1); 197 } 198 199 static inline uint64_t 200 cn30xxpow_status_by_index_desched(int index) 201 { 202 return cn30xxpow_ops_pow_memory(index, 1, 0); 203 } 204 205 /* ---- status by qos level */ 206 207 static inline uint64_t 208 cn30xxpow_status_by_qos_free_loc(int qos) 209 { 210 return cn30xxpow_ops_pow_idxptr(qos, 0, 0); 211 } 212 213 /* ---- status by desched group */ 214 215 static inline uint64_t 216 cn30xxpow_status_by_grp_nosched_des(int grp) 217 { 218 return cn30xxpow_ops_pow_idxptr(grp, 0, 1); 219 } 220 221 /* ---- status by memory input queue */ 222 223 static inline uint64_t 224 cn30xxpow_status_by_queue_remote_head(int queue) 225 { 226 return cn30xxpow_ops_pow_idxptr(queue, 1, 0); 227 } 228 229 static inline uint64_t 230 cn30xxpow_status_by_queue_remote_tail(int queue) 231 { 232 return cn30xxpow_ops_pow_idxptr(queue, 1, 0); 233 } 234 235 /* ---- tag switch */ 236 237 /* 238 * "RDHWR rt, $30" returns: 239 * 0 => pending bit is set 240 * 1 => pending bit is clear 241 */ 242 243 /* return 1 if pending bit is clear (ready) */ 244 int 245 cn30xxpow_tag_sw_poll(void) 246 { 247 uint64_t result; 248 249 __asm volatile ( 250 " .set push \n" 251 " .set noreorder \n" 252 " .set arch=mips64r2 \n" 253 " rdhwr %[result], $30 \n" 254 " .set pop \n" 255 : [result]"=r"(result) 256 ); 257 return (int)result; 258 } 259 260 void 261 cn30xxpow_tag_sw_wait(void) 262 { 263 264 while (cn30xxpow_tag_sw_poll() == 0) 265 continue; 266 } 267 268 /* -------------------------------------------------------------------------- */ 269 270 /* ---- initialization and configuration */ 271 272 void 273 cn30xxpow_bootstrap(struct octeon_config *mcp) 274 { 275 struct cn30xxpow_softc *sc = &cn30xxpow_softc; 276 277 sc->sc_regt = mcp->mc_iobus_bust; 278 /* XXX */ 279 280 cn30xxpow_init(sc); 281 282 #ifdef OCTEON_ETH_DEBUG 283 __cn30xxpow_softc = sc; 284 #endif 285 286 } 287 288 void 289 cn30xxpow_config_int(struct cn30xxpow_softc *sc, int group, 290 uint64_t tc_thr, uint64_t ds_thr, uint64_t iq_thr) 291 { 292 uint64_t wq_int_thr; 293 294 wq_int_thr = 295 POW_WQ_INT_THRX_TC_EN | 296 (tc_thr << POW_WQ_INT_THRX_TC_THR_SHIFT) | 297 (ds_thr << POW_WQ_INT_THRX_DS_THR_SHIFT) | 298 (iq_thr << POW_WQ_INT_THRX_IQ_THR_SHIFT); 299 _POW_WR8(sc, POW_WQ_INT_THR0_OFFSET + (group * 8), wq_int_thr); 300 } 301 302 /* 303 * interrupt threshold configuration 304 * 305 * => DS / IQ 306 * => ... 307 * => time counter threshold 308 * => unit is 1msec 309 * => each group can set timeout 310 * => temporary disable bit 311 * => use CIU generic timer 312 */ 313 314 void 315 cn30xxpow_config(struct cn30xxpow_softc *sc, int group) 316 { 317 318 cn30xxpow_config_int(sc, group, 319 0x0f, /* TC */ 320 0x00, /* DS */ 321 0x00); /* IQ */ 322 } 323 324 void * 325 cn30xxpow_intr_establish(int group, int level, 326 void (*cb)(void *, uint64_t *), void (*fcb)(int*, int *, uint64_t, void *), 327 void *data, char *what) 328 { 329 struct cn30xxpow_intr_handle *pow_ih; 330 331 KASSERT(group >= 0); 332 KASSERT(group < 16); 333 334 pow_ih = malloc(sizeof(*pow_ih), M_DEVBUF, M_NOWAIT); 335 KASSERT(pow_ih != NULL); /* XXX handle failure */ 336 337 pow_ih->pi_ih = octeon_intr_establish( 338 ffs64(CIU_INTX_SUM0_WORKQ_0) - 1 + group, 339 level, 340 cn30xxpow_intr, pow_ih, what); 341 KASSERT(pow_ih->pi_ih != NULL); 342 343 pow_ih->pi_sc = &cn30xxpow_softc; /* XXX */ 344 pow_ih->pi_group = group; 345 pow_ih->pi_cb = cb; 346 pow_ih->pi_data = data; 347 348 #ifdef OCTEON_ETH_DEBUG 349 cn30xxpow_intr_debug_init(pow_ih, group); 350 #endif 351 return pow_ih; 352 } 353 354 #ifdef OCTEON_ETH_DEBUG 355 356 void 357 cn30xxpow_intr_debug_init(struct cn30xxpow_intr_handle *pow_ih, int group) 358 { 359 pow_ih->pi_first = 1; 360 361 } 362 #endif 363 364 void 365 cn30xxpow_init(struct cn30xxpow_softc *sc) 366 { 367 cn30xxpow_init_regs(sc); 368 369 sc->sc_int_pc_base = 10000; 370 cn30xxpow_config_int_pc(sc, sc->sc_int_pc_base); 371 372 #ifdef OCTEON_ETH_DEBUG 373 cn30xxpow_error_int_enable(sc, 1); 374 #endif 375 } 376 377 void 378 cn30xxpow_init_regs(struct cn30xxpow_softc *sc) 379 { 380 int status; 381 382 status = bus_space_map(sc->sc_regt, POW_BASE, POW_SIZE, 0, 383 &sc->sc_regh); 384 if (status != 0) 385 panic("can't map %s space", "pow register"); 386 387 #ifdef OCTEON_ETH_DEBUG 388 _POW_WR8(sc, POW_ECC_ERR_OFFSET, 389 POW_ECC_ERR_IOP_IE | POW_ECC_ERR_RPE_IE | 390 POW_ECC_ERR_DBE_IE | POW_ECC_ERR_SBE_IE); 391 #endif 392 } 393 394 /* -------------------------------------------------------------------------- */ 395 396 /* ---- interrupt handling */ 397 398 #ifdef OCTEON_ETH_DEBUG 399 void 400 cn30xxpow_intr_work_debug_ival(struct cn30xxpow_softc *sc, 401 struct cn30xxpow_intr_handle *pow_ih) 402 { 403 struct timeval now; 404 struct timeval ival; 405 406 microtime(&now); 407 if (__predict_false(pow_ih->pi_first == 1)) { 408 pow_ih->pi_first = 0; 409 goto stat_done; 410 } 411 timersub(&now, &pow_ih->pi_last, &ival); 412 if (ival.tv_sec != 0) 413 goto stat_done; /* XXX */ 414 415 stat_done: 416 pow_ih->pi_last = now; /* struct copy */ 417 } 418 #endif 419 420 #ifdef OCTEON_ETH_DEBUG 421 #define _POW_INTR_WORK_DEBUG_IVAL(sc, ih) \ 422 cn30xxpow_intr_work_debug_ival((sc), (ih)) 423 #else 424 #define _POW_INTR_WORK_DEBUG_IVAL(sc, ih) \ 425 do {} while (0) 426 #endif 427 428 /* 429 * Interrupt handling by fixed count. 430 * 431 * XXX the fixed count (MAX_RX_CNT) could be changed dynamically? 432 * 433 * XXX this does not utilize "tag switch" very well 434 */ 435 /* 436 * usually all packet recieve 437 */ 438 #define MAX_RX_CNT 0x7fffffff 439 440 void 441 cn30xxpow_intr_work(struct cn30xxpow_softc *sc, 442 struct cn30xxpow_intr_handle *pow_ih, int max_recv_cnt) 443 { 444 uint64_t *work; 445 uint64_t count = 0; 446 int recv_cnt = MAX_RX_CNT; 447 448 /* s = splhigh(); */ 449 _POW_WR8(sc, POW_PP_GRP_MSK0_OFFSET, 1ULL << pow_ih->pi_group); 450 451 if (max_recv_cnt > 0) 452 recv_cnt = max_recv_cnt - 1; 453 454 _POW_INTR_WORK_DEBUG_IVAL(sc, pow_ih); 455 456 cn30xxpow_tag_sw_wait(); 457 cn30xxpow_work_request_async(OCTEON_CVMSEG_OFFSET(csm_pow_intr), 458 POW_NO_WAIT); 459 460 for (count = 0; count < recv_cnt; count++) { 461 work = (uint64_t *)cn30xxpow_work_response_async( 462 OCTEON_CVMSEG_OFFSET(csm_pow_intr)); 463 if (work == NULL) 464 goto done; 465 cn30xxpow_tag_sw_wait(); 466 cn30xxpow_work_request_async( 467 OCTEON_CVMSEG_OFFSET(csm_pow_intr), POW_NO_WAIT); 468 (*pow_ih->pi_cb)(pow_ih->pi_data, work); 469 } 470 471 work = (uint64_t *)cn30xxpow_work_response_async( 472 OCTEON_CVMSEG_OFFSET(csm_pow_intr)); 473 if (work == NULL) 474 goto done; 475 476 (*pow_ih->pi_cb)(pow_ih->pi_data, work); 477 count++; 478 479 done: 480 ; 481 /* KASSERT(work == NULL); */ 482 /* KASSERT(count > 0); */ 483 484 /* _POW_WR8(sc, POW_PP_GRP, 0)ULL; */ 485 /* splx(s); */ 486 } 487 488 int 489 cn30xxpow_intr(void *data) 490 { 491 struct cn30xxpow_intr_handle *pow_ih = data; 492 struct cn30xxpow_softc *sc = pow_ih->pi_sc; 493 uint64_t wq_int_mask = 0x1ULL << pow_ih->pi_group; 494 495 #if 0 496 if (ipflow_fastforward_disable_flags == 0) 497 cn30xxpow_intr_work(sc, pow_ih, -1); 498 else 499 cn30xxpow_intr_work(sc, pow_ih, recv_cnt); 500 #else 501 cn30xxpow_intr_work(sc, pow_ih, recv_cnt); 502 #endif 503 504 _POW_WR8(sc, POW_WQ_INT_OFFSET, wq_int_mask << POW_WQ_INT_WQ_INT_SHIFT); 505 return 1; 506 } 507 508 /* -------------------------------------------------------------------------- */ 509 510 /* ---- debug configuration */ 511 512 #ifdef OCTEON_ETH_DEBUG 513 514 void 515 cn30xxpow_error_int_enable(void *data, int enable) 516 { 517 struct cn30xxpow_softc *sc = data; 518 uint64_t pow_error_int_xxx; 519 520 pow_error_int_xxx = 521 POW_ECC_ERR_IOP | POW_ECC_ERR_RPE | 522 POW_ECC_ERR_DBE | POW_ECC_ERR_SBE; 523 _POW_WR8(sc, POW_ECC_ERR_OFFSET, pow_error_int_xxx); 524 _POW_WR8(sc, POW_ECC_ERR_OFFSET, enable ? pow_error_int_xxx : 0); 525 } 526 527 uint64_t 528 cn30xxpow_error_int_summary(void *data) 529 { 530 struct cn30xxpow_softc *sc = data; 531 uint64_t summary; 532 533 summary = _POW_RD8(sc, POW_ECC_ERR_OFFSET); 534 _POW_WR8(sc, POW_ECC_ERR_OFFSET, summary); 535 return summary; 536 } 537 538 #endif 539 540 /* -------------------------------------------------------------------------- */ 541 542 /* ---- debug counter */ 543 544 #ifdef OCTEON_ETH_DEBUG 545 int cn30xxpow_intr_rml_verbose; 546 547 void 548 cn30xxpow_intr_rml(void *arg) 549 { 550 struct cn30xxpow_softc *sc; 551 uint64_t reg; 552 553 sc = __cn30xxpow_softc; 554 KASSERT(sc != NULL); 555 reg = cn30xxpow_error_int_summary(sc); 556 if (cn30xxpow_intr_rml_verbose) 557 printf("%s: POW_ECC_ERR=0x%016llx\n", __func__, reg); 558 } 559 #endif 560 561 /* -------------------------------------------------------------------------- */ 562 563 /* ---- debug dump */ 564 565 #ifdef OCTEON_ETH_DEBUG 566 567 void cn30xxpow_dump_reg(void); 568 void cn30xxpow_dump_ops(void); 569 570 void 571 cn30xxpow_dump(void) 572 { 573 cn30xxpow_dump_reg(); 574 cn30xxpow_dump_ops(); 575 } 576 577 /* ---- register dump */ 578 579 struct cn30xxpow_dump_reg_entry { 580 const char *name; 581 size_t offset; 582 }; 583 584 #define _ENTRY(x) { #x, x##_OFFSET } 585 #define _ENTRY_0_7(x) \ 586 _ENTRY(x## 0), _ENTRY(x## 1), _ENTRY(x## 2), _ENTRY(x## 3), \ 587 _ENTRY(x## 4), _ENTRY(x## 5), _ENTRY(x## 6), _ENTRY(x## 7) 588 #define _ENTRY_0_15(x) \ 589 _ENTRY(x## 0), _ENTRY(x## 1), _ENTRY(x## 2), _ENTRY(x## 3), \ 590 _ENTRY(x## 4), _ENTRY(x## 5), _ENTRY(x## 6), _ENTRY(x## 7), \ 591 _ENTRY(x## 8), _ENTRY(x## 9), _ENTRY(x##10), _ENTRY(x##11), \ 592 _ENTRY(x##12), _ENTRY(x##13), _ENTRY(x##14), _ENTRY(x##15) 593 594 const struct cn30xxpow_dump_reg_entry cn30xxpow_dump_reg_entries[] = { 595 _ENTRY (POW_PP_GRP_MSK0), 596 _ENTRY (POW_PP_GRP_MSK1), 597 _ENTRY_0_15 (POW_WQ_INT_THR), 598 _ENTRY_0_15 (POW_WQ_INT_CNT), 599 _ENTRY_0_7 (POW_QOS_THR), 600 _ENTRY_0_7 (POW_QOS_RND), 601 _ENTRY (POW_WQ_INT), 602 _ENTRY (POW_WQ_INT_PC), 603 _ENTRY (POW_NW_TIM), 604 _ENTRY (POW_ECC_ERR), 605 _ENTRY (POW_NOS_CNT), 606 _ENTRY_0_15 (POW_WS_PC), 607 _ENTRY_0_7 (POW_WA_PC), 608 _ENTRY_0_7 (POW_IQ_CNT), 609 _ENTRY (POW_WA_COM_PC), 610 _ENTRY (POW_IQ_COM_CNT), 611 _ENTRY (POW_TS_PC), 612 _ENTRY (POW_DS_PC), 613 _ENTRY (POW_BIST_STAT) 614 }; 615 616 #undef _ENTRY 617 618 void 619 cn30xxpow_dump_reg(void) 620 { 621 struct cn30xxpow_softc *sc = __cn30xxpow_softc; 622 const struct cn30xxpow_dump_reg_entry *entry; 623 uint64_t tmp; 624 int i; 625 626 for (i = 0; i < (int)nitems(cn30xxpow_dump_reg_entries); i++) { 627 entry = &cn30xxpow_dump_reg_entries[i]; 628 tmp = _POW_RD8(sc, entry->offset); 629 printf("\t%-24s: %16llx\n", entry->name, tmp); 630 } 631 } 632 633 /* ---- operations dump */ 634 635 struct cn30xxpow_dump_ops_entry { 636 const char *name; 637 uint64_t (*func)(int); 638 }; 639 640 void cn30xxpow_dump_ops_coreid(int); 641 void cn30xxpow_dump_ops_index(int); 642 void cn30xxpow_dump_ops_qos(int); 643 void cn30xxpow_dump_ops_grp(int); 644 void cn30xxpow_dump_ops_queue(int); 645 void cn30xxpow_dump_ops_common(const struct cn30xxpow_dump_ops_entry *, 646 size_t, const char *, int); 647 648 #define _ENTRY_COMMON(name, prefix, x, y) \ 649 { #name "_" #x, cn30xxpow_status_by_##name##_##x } 650 651 const struct cn30xxpow_dump_ops_entry cn30xxpow_dump_ops_coreid_entries[] = { 652 #define _ENTRY(x, y) _ENTRY_COMMON(coreid, POW_STATUS_LOAD_RESULT, x, y) 653 _ENTRY(pend_tag, PEND_TAG), 654 _ENTRY(pend_wqp, PEND_WQP), 655 _ENTRY(cur_tag_next, CUR_TAG_NEXT), 656 _ENTRY(cur_tag_prev, CUR_TAG_PREV), 657 _ENTRY(cur_wqp_next, CUR_WQP_NEXT), 658 _ENTRY(cur_wqp_prev, CUR_WQP_PREV) 659 #undef _ENTRY 660 }; 661 662 const struct cn30xxpow_dump_ops_entry cn30xxpow_dump_ops_index_entries[] = { 663 #define _ENTRY(x, y) _ENTRY_COMMON(index, POW_MEMORY_LOAD_RESULT, x, y) 664 _ENTRY(tag, TAG), 665 _ENTRY(wqp, WQP), 666 _ENTRY(desched, DESCHED) 667 #undef _ENTRY 668 }; 669 670 const struct cn30xxpow_dump_ops_entry cn30xxpow_dump_ops_qos_entries[] = { 671 #define _ENTRY(x, y) _ENTRY_COMMON(qos, POW_IDXPTR_LOAD_RESULT_QOS, x, y) 672 _ENTRY(free_loc, FREE_LOC) 673 #undef _ENTRY 674 }; 675 676 const struct cn30xxpow_dump_ops_entry cn30xxpow_dump_ops_grp_entries[] = { 677 #define _ENTRY(x, y) _ENTRY_COMMON(grp, POW_IDXPTR_LOAD_RESULT_GRP, x, y) 678 _ENTRY(nosched_des, NOSCHED_DES) 679 #undef _ENTRY 680 }; 681 682 const struct cn30xxpow_dump_ops_entry cn30xxpow_dump_ops_queue_entries[] = { 683 #define _ENTRY(x, y) _ENTRY_COMMON(queue, POW_IDXPTR_LOAD_RESULT_QUEUE, x, y) 684 _ENTRY(remote_head, REMOTE_HEAD), 685 _ENTRY(remote_tail, REMOTE_TAIL) 686 #undef _ENTRY 687 }; 688 689 void 690 cn30xxpow_dump_ops(void) 691 { 692 int i; 693 694 /* XXX */ 695 for (i = 0; i < 2/* XXX */; i++) 696 cn30xxpow_dump_ops_coreid(i); 697 698 /* XXX */ 699 cn30xxpow_dump_ops_index(0); 700 701 for (i = 0; i < 8; i++) 702 cn30xxpow_dump_ops_qos(i); 703 704 for (i = 0; i < 16; i++) 705 cn30xxpow_dump_ops_grp(i); 706 707 for (i = 0; i < 16; i++) 708 cn30xxpow_dump_ops_queue(i); 709 } 710 711 void 712 cn30xxpow_dump_ops_coreid(int coreid) 713 { 714 cn30xxpow_dump_ops_common(cn30xxpow_dump_ops_coreid_entries, 715 nitems(cn30xxpow_dump_ops_coreid_entries), "coreid", coreid); 716 } 717 718 void 719 cn30xxpow_dump_ops_index(int index) 720 { 721 cn30xxpow_dump_ops_common(cn30xxpow_dump_ops_index_entries, 722 nitems(cn30xxpow_dump_ops_index_entries), "index", index); 723 } 724 725 void 726 cn30xxpow_dump_ops_qos(int qos) 727 { 728 cn30xxpow_dump_ops_common(cn30xxpow_dump_ops_qos_entries, 729 nitems(cn30xxpow_dump_ops_qos_entries), "qos", qos); 730 } 731 732 void 733 cn30xxpow_dump_ops_grp(int grp) 734 { 735 cn30xxpow_dump_ops_common(cn30xxpow_dump_ops_grp_entries, 736 nitems(cn30xxpow_dump_ops_grp_entries), "grp", grp); 737 } 738 739 void 740 cn30xxpow_dump_ops_queue(int queue) 741 { 742 cn30xxpow_dump_ops_common(cn30xxpow_dump_ops_queue_entries, 743 nitems(cn30xxpow_dump_ops_queue_entries), "queue", queue); 744 } 745 746 void 747 cn30xxpow_dump_ops_common(const struct cn30xxpow_dump_ops_entry *entries, 748 size_t nentries, const char *by_what, int arg) 749 { 750 const struct cn30xxpow_dump_ops_entry *entry; 751 uint64_t tmp; 752 int i; 753 754 printf("%s=%d\n", by_what, arg); 755 for (i = 0; i < (int)nentries; i++) { 756 entry = &entries[i]; 757 tmp = (*entry->func)(arg); 758 printf("\t%-24s: %16llx\n", entry->name, tmp); 759 } 760 } 761 762 #endif 763 764 /* -------------------------------------------------------------------------- */ 765 766 /* ---- test */ 767 768 #ifdef OCTEON_POW_TEST 769 /* 770 * Standalone test entries; meant to be called from ddb. 771 */ 772 773 void cn30xxpow_test(void); 774 void cn30xxpow_test_dump_wqe(paddr_t); 775 776 void cn30xxpow_test_1(void); 777 778 struct test_wqe { 779 uint64_t word0; 780 uint64_t word1; 781 uint64_t word2; 782 uint64_t word3; 783 } __packed; 784 struct test_wqe test_wqe; 785 786 void 787 cn30xxpow_test(void) 788 { 789 cn30xxpow_test_1(); 790 } 791 792 void 793 cn30xxpow_test_1(void) 794 { 795 struct test_wqe *wqe = &test_wqe; 796 int qos, grp, queue, tt; 797 uint32_t tag; 798 paddr_t ptr; 799 800 qos = 7; /* XXX */ 801 grp = queue = 15; /* XXX */ 802 tt = POW_TAG_TYPE_ORDERED; /* XXX */ 803 tag = UINT32_C(0x01234567); /* XXX */ 804 805 /* => make sure that the queue is empty */ 806 807 cn30xxpow_dump_ops_qos(qos); 808 cn30xxpow_dump_ops_grp(grp); 809 printf("\n"); 810 811 /* 812 * Initialize WQE. 813 * 814 * word0:next is used by hardware. 815 * 816 * word1:qos, word1:grp, word1:tt, word1:tag must match with arguments 817 * of the following ADDWQ transaction. 818 */ 819 820 (void)memset(wqe, 0, sizeof(*wqe)); 821 wqe->word0 = 822 __BITS64_SET(POW_WQE_WORD0_NEXT, 0); 823 wqe->word1 = 824 __BITS64_SET(POW_WQE_WORD1_QOS, qos) | 825 __BITS64_SET(POW_WQE_WORD1_GRP, grp) | 826 __BITS64_SET(POW_WQE_WORD1_TT, tt) | 827 __BITS64_SET(POW_WQE_WORD1_TAG, tag); 828 829 printf("calling ADDWQ\n"); 830 cn30xxpow_ops_addwq(MIPS_KSEG0_TO_PHYS(wqe), qos, grp, tt, tag); 831 832 cn30xxpow_dump_ops_qos(qos); 833 cn30xxpow_dump_ops_grp(grp); 834 printf("\n"); 835 836 /* => make sure that a WQE is added to the queue */ 837 838 printf("calling GET_WORK_LOAD\n"); 839 ptr = cn30xxpow_ops_get_work_load(0); 840 841 cn30xxpow_dump_ops_qos(qos); 842 cn30xxpow_dump_ops_grp(grp); 843 printf("\n"); 844 845 cn30xxpow_test_dump_wqe(ptr); 846 847 /* => make sure that the WQE is in-flight (and scheduled) */ 848 849 printf("calling SWTAG(NULL)\n"); 850 cn30xxpow_ops_swtag(POW_TAG_TYPE_NULL, tag); 851 852 cn30xxpow_dump_ops_qos(qos); 853 cn30xxpow_dump_ops_grp(grp); 854 printf("\n"); 855 856 /* => make sure that the WQE is un-scheduled (completed) */ 857 } 858 859 void 860 cn30xxpow_test_dump_wqe(paddr_t ptr) 861 { 862 uint64_t word0, word1; 863 864 printf("wqe\n"); 865 866 word0 = *(uint64_t *)PHYS_TO_XKPHYS(ptr, CCA_CACHED); 867 printf("\t%-24s: %16llx\n", "word0", word0); 868 869 word1 = *(uint64_t *)PHYS_TO_XKPHYS(ptr + 8, CCA_CACHED); 870 printf("\t%-24s: %16llx\n", "word1", word1); 871 } 872 #endif 873