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