2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2021 ARM Ltd
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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
30 /* Arm CoreLink CMN-600 Coherent Mesh Network Driver */
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
37 #include <sys/param.h>
39 #include <sys/kernel.h>
40 #include <sys/malloc.h>
41 #include <sys/module.h>
45 #include <sys/sysctl.h>
47 #include <machine/bus.h>
48 #include <machine/cpu.h>
50 #include <contrib/dev/acpica/include/acpi.h>
51 #include <dev/acpica/acpivar.h>
53 #include <machine/cmn600_reg.h>
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)
61 static char *cmn600_ids[] = {
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 },
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);
81 struct cmn600_softc *sc;
85 uint16_t nd_logical_id;
86 uint8_t nd_x, nd_y, nd_port, nd_sub;
87 uint16_t nd_child_count;
89 struct cmn600_node *nd_parent;
92 nd_write_8_t nd_write8;
93 nd_write_4_t nd_write4;
94 struct cmn600_node **nd_children;
104 struct resource *sc_res[3];
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);
115 static struct cmn600_pmc cmn600_pmcs[CMN600_UNIT_MAX];
116 static int cmn600_npmcs = 0;
118 static int cmn600_acpi_detach(device_t dev);
119 static int cmn600_intr(void *arg);
122 cmn600_pmc_register(int unit, void *arg, int domain)
125 if (unit >= CMN600_UNIT_MAX) {
130 cmn600_pmcs[unit].arg = arg;
131 cmn600_pmcs[unit].domain = domain;
136 cmn600_pmc_unregister(int unit)
139 cmn600_pmcs[unit].arg = NULL;
144 cmn600_pmc_nunits(void)
147 return (cmn600_npmcs);
151 cmn600_pmc_getunit(int unit, void **arg, int *domain)
154 if (unit >= cmn600_npmcs)
156 if (cmn600_pmcs[unit].arg == NULL)
158 *arg = cmn600_pmcs[unit].arg;
159 *domain = cmn600_pmcs[unit].domain;
164 pmu_cmn600_rev(void *arg)
166 struct cmn600_softc *sc;
168 sc = (struct cmn600_softc *)arg;
169 switch (sc->sc_rev) {
185 return (0x302); /* Unknown revision. */
189 cmn600_node_read8(struct cmn600_node *nd, uint32_t reg)
192 return (RD8(nd->sc, nd->nd_offset + reg));
196 cmn600_node_write8(struct cmn600_node *nd, uint32_t reg, uint64_t val)
199 WR8(nd->sc, nd->nd_offset + reg, val);
203 cmn600_node_read4(struct cmn600_node *nd, uint32_t reg)
206 return (RD4(nd->sc, nd->nd_offset + reg));
210 cmn600_node_write4(struct cmn600_node *nd, uint32_t reg, uint32_t val)
213 WR4(nd->sc, nd->nd_offset + reg, val);
217 cmn600_node_type_str(int type)
220 #define NAME_OF(t, n) case NODE_TYPE_ ## t: return n
222 NAME_OF(INVALID, "<invalid node>");
226 NAME_OF(HN_I, "HN-I");
227 NAME_OF(HN_F, "HN-F");
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");
237 return "<unknown node>";
243 cmn600_xpport_dev_type_str(uint8_t type)
246 #define NAME_OF(t, n) case POR_MXP_PX_INFO_DEV_TYPE_ ## t: return n
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");
270 cmn600_dump_node(struct cmn600_node *node, int lvl)
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);
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));
291 cmn600_dump_node_recursive(struct cmn600_node *node, int lvl)
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);
302 cmn600_dump_nodes_tree(struct cmn600_softc *sc)
305 device_printf(sc->sc_dev, " nodes:\n");
306 cmn600_dump_node_recursive(sc->sc_rootnode, 0);
310 cmn600_sysctl_dump_nodes(SYSCTL_HANDLER_ARGS)
312 struct cmn600_softc *sc;
316 sc = (struct cmn600_softc *)arg1;
318 err = sysctl_handle_int(oidp, &val, 0, req);
324 cmn600_dump_nodes_tree(sc);
329 static struct cmn600_node *
330 cmn600_create_node(struct cmn600_softc *sc, off_t node_offset,
331 struct cmn600_node *parent, int lvl)
333 struct cmn600_node *node;
338 node = malloc(sizeof(struct cmn600_node), M_DEVBUF, M_WAITOK);
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;
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);
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);
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);
366 if (FLD(val, POR_CFGM_NODE_INFO_NODE_ID) != 8)
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;
372 printf("Mesh width X/Y %d/%d\n", sc->sc_mesh_x,
375 if ((sc->sc_mesh_x > 4) || (sc->sc_mesh_y > 4))
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);
385 printf(" Rev: %d, R2_ENABLE = %s\n", sc->sc_rev,
386 sc->sc_r2 ? "true" : "false");
388 node->nd_sub = FLD(node->nd_id, NODE_ID_SUB);
389 node->nd_port = FLD(node->nd_id, NODE_ID_PORT);
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);
395 node->nd_x = FLD(node->nd_id, NODE_ID_X2B);
396 node->nd_y = FLD(node->nd_id, NODE_ID_Y2B);
400 cmn600_dump_node(node, lvl);
403 node->nd_children = (struct cmn600_node **)mallocarray(
404 node->nd_child_count, sizeof(struct cmn600_node *), M_DEVBUF,
406 if (node->nd_children == NULL)
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);
413 switch (node->nd_type) {
415 sc->sc_dtcnode = node;
418 sc->sc_dvmnode = node;
421 sc->sc_xpnodes[node->nd_id >> NODE_ID_X2B_SHIFT] = node;
428 free(node, M_DEVBUF);
433 cmn600_destroy_node(struct cmn600_node *node)
437 for (i = 0; i < node->nd_child_count; i++) {
438 if (node->nd_children[i] == NULL)
440 cmn600_destroy_node(node->nd_children[i]);
442 free(node->nd_children, M_DEVBUF);
443 free(node, M_DEVBUF);
447 cmn600_find_node(struct cmn600_softc *sc, int node_id, int type,
448 struct cmn600_node **node)
450 struct cmn600_node *xp, *child;
455 case NODE_TYPE_INVALID:
458 *node = sc->sc_rootnode;
461 *node = sc->sc_dtcnode;
464 *node = sc->sc_dvmnode;
470 xp_xy = node_id >> NODE_ID_X2B_SHIFT;
473 if (sc->sc_xpnodes[xp_xy] == NULL)
478 *node = sc->sc_xpnodes[xp_xy];
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) {
494 pmu_cmn600_alloc_localpmc(void *arg, int nodeid, int node_type, int *counter)
496 struct cmn600_node *node;
497 struct cmn600_softc *sc;
501 sc = (struct cmn600_softc *)arg;
506 node_type = NODE_TYPE_XP;
507 /* Parent XP node has always zero port and device bits. */
510 ret = cmn600_find_node(sc, nodeid, node_type, &node);
513 for (i = 0; i < 4; i++) {
514 new = old = node->nd_paired;
517 if ((old & (1 << i)) != 0)
520 if (atomic_cmpset_32(&node->nd_paired, old, new) != 0)
528 pmu_cmn600_free_localpmc(void *arg, int nodeid, int node_type, int counter)
530 struct cmn600_node *node;
531 struct cmn600_softc *sc;
535 sc = (struct cmn600_softc *)arg;
540 node_type = NODE_TYPE_XP;
542 ret = cmn600_find_node(sc, nodeid, node_type, &node);
547 new = old = node->nd_paired;
548 new &= ~(1 << counter);
549 } while (atomic_cmpset_32(&node->nd_paired, old, new) == 0);
554 pmu_cmn600_rd4(void *arg, int nodeid, int node_type, off_t reg)
556 struct cmn600_node *node;
557 struct cmn600_softc *sc;
560 sc = (struct cmn600_softc *)arg;
561 ret = cmn600_find_node(sc, nodeid, node_type, &node);
564 return (cmn600_node_read4(node, reg));
568 pmu_cmn600_wr4(void *arg, int nodeid, int node_type, off_t reg, uint32_t val)
570 struct cmn600_node *node;
571 struct cmn600_softc *sc;
574 sc = (struct cmn600_softc *)arg;
575 ret = cmn600_find_node(sc, nodeid, node_type, &node);
578 cmn600_node_write4(node, reg, val);
583 pmu_cmn600_rd8(void *arg, int nodeid, int node_type, off_t reg)
585 struct cmn600_node *node;
586 struct cmn600_softc *sc;
589 sc = (struct cmn600_softc *)arg;
590 ret = cmn600_find_node(sc, nodeid, node_type, &node);
593 return (cmn600_node_read8(node, reg));
597 pmu_cmn600_wr8(void *arg, int nodeid, int node_type, off_t reg, uint64_t val)
599 struct cmn600_node *node;
600 struct cmn600_softc *sc;
603 sc = (struct cmn600_softc *)arg;
604 ret = cmn600_find_node(sc, nodeid, node_type, &node);
607 cmn600_node_write8(node, reg, val);
612 pmu_cmn600_set8(void *arg, int nodeid, int node_type, off_t reg, uint64_t val)
614 struct cmn600_node *node;
615 struct cmn600_softc *sc;
618 sc = (struct cmn600_softc *)arg;
619 ret = cmn600_find_node(sc, nodeid, node_type, &node);
622 cmn600_node_write8(node, reg, cmn600_node_read8(node, reg) | val);
627 pmu_cmn600_clr8(void *arg, int nodeid, int node_type, off_t reg, uint64_t val)
629 struct cmn600_node *node;
630 struct cmn600_softc *sc;
633 sc = (struct cmn600_softc *)arg;
634 ret = cmn600_find_node(sc, nodeid, node_type, &node);
637 cmn600_node_write8(node, reg, cmn600_node_read8(node, reg) & ~val);
642 pmu_cmn600_md8(void *arg, int nodeid, int node_type, off_t reg, uint64_t mask,
645 struct cmn600_node *node;
646 struct cmn600_softc *sc;
649 sc = (struct cmn600_softc *)arg;
650 ret = cmn600_find_node(sc, nodeid, node_type, &node);
653 cmn600_node_write8(node, reg, (cmn600_node_read8(node, reg) & ~mask) |
659 cmn600_acpi_probe(device_t dev)
663 err = ACPI_ID_PROBE(device_get_parent(dev), dev, cmn600_ids, NULL);
665 device_set_desc(dev, "Arm CoreLink CMN-600 Coherent Mesh Network");
671 cmn600_acpi_attach(device_t dev)
673 struct sysctl_ctx_list *ctx;
674 struct sysctl_oid_list *child;
675 struct cmn600_softc *sc;
676 int cpu, domain, i, u;
678 rman_res_t count, periph_base, rootnode_base;
679 struct cmn600_node *node;
681 dname = device_get_name(dev);
682 sc = device_get_softc(dev);
684 u = device_get_unit(dev);
688 if ((resource_int_value(dname, u, "domain", &domain) == 0 ||
689 bus_get_domain(dev, &domain) == 0) && domain < MAXMEMDOM) {
690 sc->sc_domain = domain;
692 if (domain == -1) /* NUMA not supported. Use single domain. */
694 sc->sc_domain = domain;
695 device_printf(dev, "domain=%d\n", sc->sc_domain);
697 cpu = CPU_FFS(&cpuset_domain[domain]) - 1;
699 i = bus_alloc_resources(dev, cmn600_res_spec, sc->sc_res);
701 device_printf(dev, "cannot allocate resources for device (%d)\n",
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;
712 printf("ROOTNODE at %lx x %lx\n", rootnode_base, count);
714 sc->sc_rootnode = cmn600_create_node(sc, rootnode_base, NULL, 0);
715 ctx = device_get_sysctl_ctx(sc->sc_dev);
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");
722 node = sc->sc_dtcnode;
726 cmn600_pmc_register(sc->sc_unit, (void *)sc, domain);
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);
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);
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);
751 cmn600_acpi_detach(device_t dev)
753 struct cmn600_softc *sc;
754 struct cmn600_node *node;
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);
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);
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);
774 cmn600_pmu_intr_cb(void *arg, int (*handler)(struct trapframe *tf, int unit,
777 struct cmn600_softc *sc;
779 sc = (struct cmn600_softc *) arg;
780 sc->sc_pmu_ih = handler;
785 cmn600_intr(void *arg)
787 struct cmn600_node *node;
788 struct cmn600_softc *sc;
789 struct trapframe *tf;
790 uint64_t mask, ready, val;
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++) {
803 if ((val & mask) == 0)
805 if (sc->sc_pmu_ih != NULL)
806 sc->sc_pmu_ih(tf, sc->sc_unit, i);
810 node->nd_write8(node, POR_DT_PMOVSR_CLR, ready);
813 return (FILTER_HANDLED);
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),
826 static driver_t cmn600_acpi_driver = {
829 sizeof(struct cmn600_softc),
832 DRIVER_MODULE(cmn600, acpi, cmn600_acpi_driver, 0, 0);
833 MODULE_VERSION(cmn600, 1);