1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2021 ARM Ltd 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 20 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 22 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 /* Arm CoreLink CMN-600 Coherent Mesh Network Driver */ 29 30 #include <sys/cdefs.h> 31 #include "opt_acpi.h" 32 33 #include <sys/param.h> 34 #include <sys/bus.h> 35 #include <sys/kernel.h> 36 #include <sys/malloc.h> 37 #include <sys/module.h> 38 #include <sys/proc.h> 39 #include <sys/rman.h> 40 #include <sys/smp.h> 41 #include <sys/sysctl.h> 42 43 #include <machine/bus.h> 44 #include <machine/cpu.h> 45 46 #include <contrib/dev/acpica/include/acpi.h> 47 #include <dev/acpica/acpivar.h> 48 49 #include <machine/cmn600_reg.h> 50 51 #define RD4(sc, r) bus_read_4((sc)->sc_res[0], (r)) 52 #define RD8(sc, r) bus_read_8((sc)->sc_res[0], (r)) 53 #define WR4(sc, r, v) bus_write_4((sc)->sc_res[0], (r), (v)) 54 #define WR8(sc, r, v) bus_write_8((sc)->sc_res[0], (r), (v)) 55 #define FLD(v, n) (((v) & n ## _MASK) >> n ## _SHIFT) 56 57 static char *cmn600_ids[] = { 58 "ARMHC600", 59 NULL 60 }; 61 62 static struct resource_spec cmn600_res_spec[] = { 63 { SYS_RES_MEMORY, 0, RF_ACTIVE }, 64 { SYS_RES_MEMORY, 1, RF_ACTIVE | RF_UNMAPPED | RF_OPTIONAL }, 65 { SYS_RES_IRQ, 0, RF_ACTIVE }, 66 { -1, 0 } 67 }; 68 69 struct cmn600_node; 70 71 typedef uint64_t (*nd_read_8_t)(struct cmn600_node *, uint32_t); 72 typedef uint32_t (*nd_read_4_t)(struct cmn600_node *, uint32_t); 73 typedef void (*nd_write_8_t)(struct cmn600_node *, uint32_t, uint64_t); 74 typedef void (*nd_write_4_t)(struct cmn600_node *, uint32_t, uint32_t); 75 76 struct cmn600_node { 77 struct cmn600_softc *sc; 78 off_t nd_offset; 79 int nd_type; 80 uint16_t nd_id; 81 uint16_t nd_logical_id; 82 uint8_t nd_x, nd_y, nd_port, nd_sub; 83 uint16_t nd_child_count; 84 uint32_t nd_paired; 85 struct cmn600_node *nd_parent; 86 nd_read_8_t nd_read8; 87 nd_read_4_t nd_read4; 88 nd_write_8_t nd_write8; 89 nd_write_4_t nd_write4; 90 struct cmn600_node **nd_children; 91 }; 92 93 struct cmn600_softc { 94 device_t sc_dev; 95 int sc_unit; 96 int sc_domain; 97 int sc_longid; 98 int sc_mesh_x; 99 int sc_mesh_y; 100 struct resource *sc_res[3]; 101 void *sc_ih; 102 int sc_r2; 103 int sc_rev; 104 struct cmn600_node *sc_rootnode; 105 struct cmn600_node *sc_dtcnode; 106 struct cmn600_node *sc_dvmnode; 107 struct cmn600_node *sc_xpnodes[64]; 108 int (*sc_pmu_ih)(struct trapframe *tf, int unit, int i); 109 }; 110 111 static struct cmn600_pmc cmn600_pmcs[CMN600_UNIT_MAX]; 112 static int cmn600_npmcs = 0; 113 114 static int cmn600_acpi_detach(device_t dev); 115 static int cmn600_intr(void *arg); 116 117 static void 118 cmn600_pmc_register(int unit, void *arg, int domain) 119 { 120 121 if (unit >= CMN600_UNIT_MAX) { 122 /* TODO */ 123 return; 124 } 125 126 cmn600_pmcs[unit].arg = arg; 127 cmn600_pmcs[unit].domain = domain; 128 cmn600_npmcs++; 129 } 130 131 static void 132 cmn600_pmc_unregister(int unit) 133 { 134 135 cmn600_pmcs[unit].arg = NULL; 136 cmn600_npmcs--; 137 } 138 139 int 140 cmn600_pmc_nunits(void) 141 { 142 143 return (cmn600_npmcs); 144 } 145 146 int 147 cmn600_pmc_getunit(int unit, void **arg, int *domain) 148 { 149 150 if (unit >= cmn600_npmcs) 151 return (EINVAL); 152 if (cmn600_pmcs[unit].arg == NULL) 153 return (EINVAL); 154 *arg = cmn600_pmcs[unit].arg; 155 *domain = cmn600_pmcs[unit].domain; 156 return (0); 157 } 158 159 int 160 pmu_cmn600_rev(void *arg) 161 { 162 struct cmn600_softc *sc; 163 164 sc = (struct cmn600_softc *)arg; 165 switch (sc->sc_rev) { 166 case 0x0: 167 return (0x100); 168 case 0x1: 169 return (0x101); 170 case 0x2: 171 return (0x102); 172 case 0x3: 173 return (0x103); 174 case 0x4: 175 return (0x200); 176 case 0x5: 177 return (0x300); 178 case 0x6: 179 return (0x301); 180 } 181 return (0x302); /* Unknown revision. */ 182 } 183 184 static uint64_t 185 cmn600_node_read8(struct cmn600_node *nd, uint32_t reg) 186 { 187 188 return (RD8(nd->sc, nd->nd_offset + reg)); 189 } 190 191 static void 192 cmn600_node_write8(struct cmn600_node *nd, uint32_t reg, uint64_t val) 193 { 194 195 WR8(nd->sc, nd->nd_offset + reg, val); 196 } 197 198 static uint32_t 199 cmn600_node_read4(struct cmn600_node *nd, uint32_t reg) 200 { 201 202 return (RD4(nd->sc, nd->nd_offset + reg)); 203 } 204 205 static void 206 cmn600_node_write4(struct cmn600_node *nd, uint32_t reg, uint32_t val) 207 { 208 209 WR4(nd->sc, nd->nd_offset + reg, val); 210 } 211 212 static const char * 213 cmn600_node_type_str(int type) 214 { 215 216 #define NAME_OF(t, n) case NODE_TYPE_ ## t: return n 217 switch (type) { 218 NAME_OF(INVALID, "<invalid node>"); 219 NAME_OF(DVM, "DVM"); 220 NAME_OF(CFG, "CFG"); 221 NAME_OF(DTC, "DTC"); 222 NAME_OF(HN_I, "HN-I"); 223 NAME_OF(HN_F, "HN-F"); 224 NAME_OF(XP, "XP"); 225 NAME_OF(SBSX, "SBSX"); 226 NAME_OF(RN_I, "RN-I"); 227 NAME_OF(RN_D, "RN-D"); 228 NAME_OF(RN_SAM, "RN-SAM"); 229 NAME_OF(CXRA, "CXRA"); 230 NAME_OF(CXHA, "CXHA"); 231 NAME_OF(CXLA, "CXLA"); 232 default: 233 return "<unknown node>"; 234 } 235 #undef NAME_OF 236 } 237 238 static const char * 239 cmn600_xpport_dev_type_str(uint8_t type) 240 { 241 242 #define NAME_OF(t, n) case POR_MXP_PX_INFO_DEV_TYPE_ ## t: return n 243 switch (type) { 244 NAME_OF(RN_I, "RN-I"); 245 NAME_OF(RN_D, "RN-D"); 246 NAME_OF(RN_F_CHIB, "RN-F CHIB"); 247 NAME_OF(RN_F_CHIB_ESAM, "RN-F CHIB ESAM"); 248 NAME_OF(RN_F_CHIA, "RN-F CHIA"); 249 NAME_OF(RN_F_CHIA_ESAM, "RN-F CHIA ESAM"); 250 NAME_OF(HN_T, "HN-T"); 251 NAME_OF(HN_I, "HN-I"); 252 NAME_OF(HN_D, "HN-D"); 253 NAME_OF(SN_F, "SN-F"); 254 NAME_OF(SBSX, "SBSX"); 255 NAME_OF(HN_F, "HN-F"); 256 NAME_OF(CXHA, "CXHA"); 257 NAME_OF(CXRA, "CXRA"); 258 NAME_OF(CXRH, "CXRH"); 259 default: 260 return "<unknown>"; 261 } 262 #undef NAME_OF 263 } 264 265 static void 266 cmn600_dump_node(struct cmn600_node *node, int lvl) 267 { 268 int i; 269 270 for (i = 0; i < lvl; i++) printf(" "); 271 printf("%s [%dx%d:%d:%d] id: 0x%x @0x%lx Logical Id: 0x%x", 272 cmn600_node_type_str(node->nd_type), node->nd_x, node->nd_y, 273 node->nd_port, node->nd_sub, node->nd_id, node->nd_offset, 274 node->nd_logical_id); 275 if (node->nd_child_count > 0) 276 printf(", Children: %d", node->nd_child_count); 277 printf("\n"); 278 if (node->nd_type == NODE_TYPE_XP) 279 printf("\tPort 0: %s\n\tPort 1: %s\n", 280 cmn600_xpport_dev_type_str(node->nd_read4(node, 281 POR_MXP_P0_INFO) & 0x1f), 282 cmn600_xpport_dev_type_str(node->nd_read4(node, 283 POR_MXP_P1_INFO) & 0x1f)); 284 } 285 286 static void 287 cmn600_dump_node_recursive(struct cmn600_node *node, int lvl) 288 { 289 int i; 290 291 cmn600_dump_node(node, lvl); 292 for (i = 0; i < node->nd_child_count; i++) { 293 cmn600_dump_node_recursive(node->nd_children[i], lvl + 1); 294 } 295 } 296 297 static void 298 cmn600_dump_nodes_tree(struct cmn600_softc *sc) 299 { 300 301 device_printf(sc->sc_dev, " nodes:\n"); 302 cmn600_dump_node_recursive(sc->sc_rootnode, 0); 303 } 304 305 static int 306 cmn600_sysctl_dump_nodes(SYSCTL_HANDLER_ARGS) 307 { 308 struct cmn600_softc *sc; 309 uint32_t val; 310 int err; 311 312 sc = (struct cmn600_softc *)arg1; 313 val = 0; 314 err = sysctl_handle_int(oidp, &val, 0, req); 315 316 if (err) 317 return (err); 318 319 if (val != 0) 320 cmn600_dump_nodes_tree(sc); 321 322 return (0); 323 } 324 325 static struct cmn600_node * 326 cmn600_create_node(struct cmn600_softc *sc, off_t node_offset, 327 struct cmn600_node *parent, int lvl) 328 { 329 struct cmn600_node *node; 330 off_t child_offset; 331 uint64_t val; 332 int i; 333 334 node = malloc(sizeof(struct cmn600_node), M_DEVBUF, M_WAITOK); 335 if (node == NULL) 336 return (NULL); 337 338 node->sc = sc; 339 node->nd_offset = node_offset; 340 node->nd_parent = parent; 341 node->nd_read4 = cmn600_node_read4; 342 node->nd_read8 = cmn600_node_read8; 343 node->nd_write4 = cmn600_node_write4; 344 node->nd_write8 = cmn600_node_write8; 345 346 val = node->nd_read8(node, POR_CFGM_NODE_INFO); 347 node->nd_type = FLD(val, POR_CFGM_NODE_INFO_NODE_TYPE); 348 node->nd_id = FLD(val, POR_CFGM_NODE_INFO_NODE_ID); 349 node->nd_logical_id = FLD(val, POR_CFGM_NODE_INFO_LOGICAL_ID); 350 351 val = node->nd_read8(node, POR_CFGM_CHILD_INFO); 352 node->nd_child_count = FLD(val, POR_CFGM_CHILD_INFO_CHILD_COUNT); 353 child_offset = FLD(val, POR_CFGM_CHILD_INFO_CHILD_PTR_OFFSET); 354 355 if (parent == NULL) { 356 /* Find XP node with Id 8. It has to be last in a row. */ 357 for (i = 0; i < node->nd_child_count; i++) { 358 val = node->nd_read8(node, child_offset + (i * 8)); 359 val &= POR_CFGM_CHILD_POINTER_BASE_MASK; 360 val = RD8(sc, val + POR_CFGM_NODE_INFO); 361 362 if (FLD(val, POR_CFGM_NODE_INFO_NODE_ID) != 8) 363 continue; 364 365 sc->sc_mesh_x = FLD(val, POR_CFGM_NODE_INFO_LOGICAL_ID); 366 sc->sc_mesh_y = node->nd_child_count / sc->sc_mesh_x; 367 if (bootverbose) 368 printf("Mesh width X/Y %d/%d\n", sc->sc_mesh_x, 369 sc->sc_mesh_y); 370 371 if ((sc->sc_mesh_x > 4) || (sc->sc_mesh_y > 4)) 372 sc->sc_longid = 1; 373 break; 374 } 375 376 val = node->nd_read8(node, POR_INFO_GLOBAL); 377 sc->sc_r2 = (val & POR_INFO_GLOBAL_R2_ENABLE) ? 1 : 0; 378 val = node->nd_read4(node, POR_CFGM_PERIPH_ID_2_PERIPH_ID_3); 379 sc->sc_rev = FLD(val, POR_CFGM_PERIPH_ID_2_REV); 380 if (bootverbose) 381 printf(" Rev: %d, R2_ENABLE = %s\n", sc->sc_rev, 382 sc->sc_r2 ? "true" : "false"); 383 } 384 node->nd_sub = FLD(node->nd_id, NODE_ID_SUB); 385 node->nd_port = FLD(node->nd_id, NODE_ID_PORT); 386 node->nd_paired = 0; 387 if (sc->sc_longid == 1) { 388 node->nd_x = FLD(node->nd_id, NODE_ID_X3B); 389 node->nd_y = FLD(node->nd_id, NODE_ID_Y3B); 390 } else { 391 node->nd_x = FLD(node->nd_id, NODE_ID_X2B); 392 node->nd_y = FLD(node->nd_id, NODE_ID_Y2B); 393 } 394 395 if (bootverbose) { 396 cmn600_dump_node(node, lvl); 397 } 398 399 node->nd_children = (struct cmn600_node **)mallocarray( 400 node->nd_child_count, sizeof(struct cmn600_node *), M_DEVBUF, 401 M_WAITOK); 402 if (node->nd_children == NULL) 403 goto FAIL; 404 for (i = 0; i < node->nd_child_count; i++) { 405 val = node->nd_read8(node, child_offset + (i * 8)); 406 node->nd_children[i] = cmn600_create_node(sc, val & 407 POR_CFGM_CHILD_POINTER_BASE_MASK, node, lvl + 1); 408 } 409 switch (node->nd_type) { 410 case NODE_TYPE_DTC: 411 sc->sc_dtcnode = node; 412 break; 413 case NODE_TYPE_DVM: 414 sc->sc_dvmnode = node; 415 break; 416 case NODE_TYPE_XP: 417 sc->sc_xpnodes[node->nd_id >> NODE_ID_X2B_SHIFT] = node; 418 break; 419 default: 420 break; 421 } 422 return (node); 423 FAIL: 424 free(node, M_DEVBUF); 425 return (NULL); 426 } 427 428 static void 429 cmn600_destroy_node(struct cmn600_node *node) 430 { 431 int i; 432 433 for (i = 0; i < node->nd_child_count; i++) { 434 if (node->nd_children[i] == NULL) 435 continue; 436 cmn600_destroy_node(node->nd_children[i]); 437 } 438 free(node->nd_children, M_DEVBUF); 439 free(node, M_DEVBUF); 440 } 441 442 static int 443 cmn600_find_node(struct cmn600_softc *sc, int node_id, int type, 444 struct cmn600_node **node) 445 { 446 struct cmn600_node *xp, *child; 447 uint8_t xp_xy; 448 int i; 449 450 switch (type) { 451 case NODE_TYPE_INVALID: 452 return (ENXIO); 453 case NODE_TYPE_CFG: 454 *node = sc->sc_rootnode; 455 return (0); 456 case NODE_TYPE_DTC: 457 *node = sc->sc_dtcnode; 458 return (0); 459 case NODE_TYPE_DVM: 460 *node = sc->sc_dvmnode; 461 return (0); 462 default: 463 break; 464 } 465 466 xp_xy = node_id >> NODE_ID_X2B_SHIFT; 467 if (xp_xy >= 64) 468 return (ENXIO); 469 if (sc->sc_xpnodes[xp_xy] == NULL) 470 return (ENOENT); 471 472 switch (type) { 473 case NODE_TYPE_XP: 474 *node = sc->sc_xpnodes[xp_xy]; 475 return (0); 476 default: 477 xp = sc->sc_xpnodes[xp_xy]; 478 for (i = 0; i < xp->nd_child_count; i++) { 479 child = xp->nd_children[i]; 480 if (child->nd_id == node_id && child->nd_type == type) { 481 *node = child; 482 return (0); 483 } 484 } 485 } 486 return (ENOENT); 487 } 488 489 int 490 pmu_cmn600_alloc_localpmc(void *arg, int nodeid, int node_type, int *counter) 491 { 492 struct cmn600_node *node; 493 struct cmn600_softc *sc; 494 uint32_t new, old; 495 int i, ret; 496 497 sc = (struct cmn600_softc *)arg; 498 switch (node_type) { 499 case NODE_TYPE_CXLA: 500 break; 501 default: 502 node_type = NODE_TYPE_XP; 503 /* Parent XP node has always zero port and device bits. */ 504 nodeid &= ~0x07; 505 } 506 ret = cmn600_find_node(sc, nodeid, node_type, &node); 507 if (ret != 0) 508 return (ret); 509 for (i = 0; i < 4; i++) { 510 new = old = node->nd_paired; 511 if (old == 0xf) 512 return (EBUSY); 513 if ((old & (1 << i)) != 0) 514 continue; 515 new |= 1 << i; 516 if (atomic_cmpset_32(&node->nd_paired, old, new) != 0) 517 break; 518 } 519 *counter = i; 520 return (0); 521 } 522 523 int 524 pmu_cmn600_free_localpmc(void *arg, int nodeid, int node_type, int counter) 525 { 526 struct cmn600_node *node; 527 struct cmn600_softc *sc; 528 uint32_t new, old; 529 int ret; 530 531 sc = (struct cmn600_softc *)arg; 532 switch (node_type) { 533 case NODE_TYPE_CXLA: 534 break; 535 default: 536 node_type = NODE_TYPE_XP; 537 } 538 ret = cmn600_find_node(sc, nodeid, node_type, &node); 539 if (ret != 0) 540 return (ret); 541 542 do { 543 new = old = node->nd_paired; 544 new &= ~(1 << counter); 545 } while (atomic_cmpset_32(&node->nd_paired, old, new) == 0); 546 return (0); 547 } 548 549 uint32_t 550 pmu_cmn600_rd4(void *arg, int nodeid, int node_type, off_t reg) 551 { 552 struct cmn600_node *node; 553 struct cmn600_softc *sc; 554 int ret; 555 556 sc = (struct cmn600_softc *)arg; 557 ret = cmn600_find_node(sc, nodeid, node_type, &node); 558 if (ret != 0) 559 return (UINT32_MAX); 560 return (cmn600_node_read4(node, reg)); 561 } 562 563 int 564 pmu_cmn600_wr4(void *arg, int nodeid, int node_type, off_t reg, uint32_t val) 565 { 566 struct cmn600_node *node; 567 struct cmn600_softc *sc; 568 int ret; 569 570 sc = (struct cmn600_softc *)arg; 571 ret = cmn600_find_node(sc, nodeid, node_type, &node); 572 if (ret != 0) 573 return (ret); 574 cmn600_node_write4(node, reg, val); 575 return (0); 576 } 577 578 uint64_t 579 pmu_cmn600_rd8(void *arg, int nodeid, int node_type, off_t reg) 580 { 581 struct cmn600_node *node; 582 struct cmn600_softc *sc; 583 int ret; 584 585 sc = (struct cmn600_softc *)arg; 586 ret = cmn600_find_node(sc, nodeid, node_type, &node); 587 if (ret != 0) 588 return (UINT64_MAX); 589 return (cmn600_node_read8(node, reg)); 590 } 591 592 int 593 pmu_cmn600_wr8(void *arg, int nodeid, int node_type, off_t reg, uint64_t val) 594 { 595 struct cmn600_node *node; 596 struct cmn600_softc *sc; 597 int ret; 598 599 sc = (struct cmn600_softc *)arg; 600 ret = cmn600_find_node(sc, nodeid, node_type, &node); 601 if (ret != 0) 602 return (ret); 603 cmn600_node_write8(node, reg, val); 604 return (0); 605 } 606 607 int 608 pmu_cmn600_set8(void *arg, int nodeid, int node_type, off_t reg, uint64_t val) 609 { 610 struct cmn600_node *node; 611 struct cmn600_softc *sc; 612 int ret; 613 614 sc = (struct cmn600_softc *)arg; 615 ret = cmn600_find_node(sc, nodeid, node_type, &node); 616 if (ret != 0) 617 return (ret); 618 cmn600_node_write8(node, reg, cmn600_node_read8(node, reg) | val); 619 return (0); 620 } 621 622 int 623 pmu_cmn600_clr8(void *arg, int nodeid, int node_type, off_t reg, uint64_t val) 624 { 625 struct cmn600_node *node; 626 struct cmn600_softc *sc; 627 int ret; 628 629 sc = (struct cmn600_softc *)arg; 630 ret = cmn600_find_node(sc, nodeid, node_type, &node); 631 if (ret != 0) 632 return (ret); 633 cmn600_node_write8(node, reg, cmn600_node_read8(node, reg) & ~val); 634 return (0); 635 } 636 637 int 638 pmu_cmn600_md8(void *arg, int nodeid, int node_type, off_t reg, uint64_t mask, 639 uint64_t val) 640 { 641 struct cmn600_node *node; 642 struct cmn600_softc *sc; 643 int ret; 644 645 sc = (struct cmn600_softc *)arg; 646 ret = cmn600_find_node(sc, nodeid, node_type, &node); 647 if (ret != 0) 648 return (ret); 649 cmn600_node_write8(node, reg, (cmn600_node_read8(node, reg) & ~mask) | 650 val); 651 return (0); 652 } 653 654 static int 655 cmn600_acpi_probe(device_t dev) 656 { 657 int err; 658 659 err = ACPI_ID_PROBE(device_get_parent(dev), dev, cmn600_ids, NULL); 660 if (err <= 0) 661 device_set_desc(dev, "Arm CoreLink CMN-600 Coherent Mesh Network"); 662 663 return (err); 664 } 665 666 static int 667 cmn600_acpi_attach(device_t dev) 668 { 669 struct sysctl_ctx_list *ctx; 670 struct sysctl_oid_list *child; 671 struct cmn600_softc *sc; 672 int cpu, domain, i, u; 673 const char *dname; 674 rman_res_t count, periph_base, rootnode_base; 675 struct cmn600_node *node; 676 677 dname = device_get_name(dev); 678 sc = device_get_softc(dev); 679 sc->sc_dev = dev; 680 u = device_get_unit(dev); 681 sc->sc_unit = u; 682 domain = 0; 683 684 if ((resource_int_value(dname, u, "domain", &domain) == 0 || 685 bus_get_domain(dev, &domain) == 0) && domain < MAXMEMDOM) { 686 sc->sc_domain = domain; 687 } 688 if (domain == -1) /* NUMA not supported. Use single domain. */ 689 domain = 0; 690 sc->sc_domain = domain; 691 device_printf(dev, "domain=%d\n", sc->sc_domain); 692 693 cpu = CPU_FFS(&cpuset_domain[domain]) - 1; 694 695 i = bus_alloc_resources(dev, cmn600_res_spec, sc->sc_res); 696 if (i != 0) { 697 device_printf(dev, "cannot allocate resources for device (%d)\n", 698 i); 699 return (i); 700 } 701 702 bus_get_resource(dev, cmn600_res_spec[0].type, cmn600_res_spec[0].rid, 703 &periph_base, &count); 704 bus_get_resource(dev, cmn600_res_spec[1].type, cmn600_res_spec[1].rid, 705 &rootnode_base, &count); 706 rootnode_base -= periph_base; 707 if (bootverbose) 708 printf("ROOTNODE at %lx x %lx\n", rootnode_base, count); 709 710 sc->sc_rootnode = cmn600_create_node(sc, rootnode_base, NULL, 0); 711 ctx = device_get_sysctl_ctx(sc->sc_dev); 712 713 child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->sc_dev)); 714 SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "dump_nodes", CTLTYPE_INT | 715 CTLFLAG_RW | CTLFLAG_NEEDGIANT, sc, 0, cmn600_sysctl_dump_nodes, 716 "U", "Dump CMN-600 nodes tree"); 717 718 node = sc->sc_dtcnode; 719 if (node == NULL) 720 return (ENXIO); 721 722 cmn600_pmc_register(sc->sc_unit, (void *)sc, domain); 723 724 node->nd_write8(node, POR_DT_PMCR, 0); 725 node->nd_write8(node, POR_DT_PMOVSR_CLR, POR_DT_PMOVSR_ALL); 726 node->nd_write8(node, POR_DT_PMCR, POR_DT_PMCR_OVFL_INTR_EN); 727 node->nd_write8(node, POR_DT_DTC_CTL, POR_DT_DTC_CTL_DT_EN); 728 729 if (bus_setup_intr(dev, sc->sc_res[2], INTR_TYPE_MISC | INTR_MPSAFE, 730 cmn600_intr, NULL, sc, &sc->sc_ih)) { 731 bus_release_resources(dev, cmn600_res_spec, sc->sc_res); 732 device_printf(dev, "cannot setup interrupt handler\n"); 733 cmn600_acpi_detach(dev); 734 return (ENXIO); 735 } 736 if (bus_bind_intr(dev, sc->sc_res[2], cpu)) { 737 bus_teardown_intr(dev, sc->sc_res[2], sc->sc_ih); 738 bus_release_resources(dev, cmn600_res_spec, sc->sc_res); 739 device_printf(dev, "cannot setup interrupt handler\n"); 740 cmn600_acpi_detach(dev); 741 return (ENXIO); 742 } 743 return (0); 744 } 745 746 static int 747 cmn600_acpi_detach(device_t dev) 748 { 749 struct cmn600_softc *sc; 750 struct cmn600_node *node; 751 752 sc = device_get_softc(dev); 753 if (sc->sc_res[2] != NULL) { 754 bus_teardown_intr(dev, sc->sc_res[2], sc->sc_ih); 755 } 756 757 node = sc->sc_dtcnode; 758 node->nd_write4(node, POR_DT_DTC_CTL, 759 node->nd_read4(node, POR_DT_DTC_CTL) & ~POR_DT_DTC_CTL_DT_EN); 760 node->nd_write8(node, POR_DT_PMOVSR_CLR, POR_DT_PMOVSR_ALL); 761 762 cmn600_pmc_unregister(sc->sc_unit); 763 cmn600_destroy_node(sc->sc_rootnode); 764 bus_release_resources(dev, cmn600_res_spec, sc->sc_res); 765 766 return (0); 767 } 768 769 int 770 cmn600_pmu_intr_cb(void *arg, int (*handler)(struct trapframe *tf, int unit, 771 int i)) 772 { 773 struct cmn600_softc *sc; 774 775 sc = (struct cmn600_softc *) arg; 776 sc->sc_pmu_ih = handler; 777 return (0); 778 } 779 780 static int 781 cmn600_intr(void *arg) 782 { 783 struct cmn600_node *node; 784 struct cmn600_softc *sc; 785 struct trapframe *tf; 786 uint64_t mask, ready, val; 787 int i; 788 789 tf = PCPU_GET(curthread)->td_intr_frame; 790 sc = (struct cmn600_softc *) arg; 791 node = sc->sc_dtcnode; 792 val = node->nd_read8(node, POR_DT_PMOVSR); 793 if (val & POR_DT_PMOVSR_CYCLE_COUNTER) 794 node->nd_write8(node, POR_DT_PMOVSR_CLR, 795 POR_DT_PMOVSR_CYCLE_COUNTER); 796 if (val & POR_DT_PMOVSR_EVENT_COUNTERS) { 797 for (ready = 0, i = 0; i < 8; i++) { 798 mask = 1 << i; 799 if ((val & mask) == 0) 800 continue; 801 if (sc->sc_pmu_ih != NULL) 802 sc->sc_pmu_ih(tf, sc->sc_unit, i); 803 ready |= mask; 804 805 } 806 node->nd_write8(node, POR_DT_PMOVSR_CLR, ready); 807 } 808 809 return (FILTER_HANDLED); 810 } 811 812 static device_method_t cmn600_acpi_methods[] = { 813 /* Device interface */ 814 DEVMETHOD(device_probe, cmn600_acpi_probe), 815 DEVMETHOD(device_attach, cmn600_acpi_attach), 816 DEVMETHOD(device_detach, cmn600_acpi_detach), 817 818 /* End */ 819 DEVMETHOD_END 820 }; 821 822 static driver_t cmn600_acpi_driver = { 823 "cmn600", 824 cmn600_acpi_methods, 825 sizeof(struct cmn600_softc), 826 }; 827 828 DRIVER_MODULE(cmn600, acpi, cmn600_acpi_driver, 0, 0); 829 MODULE_VERSION(cmn600, 1); 830