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