diff --git a/sys/arm64/arm64/cmn600.c b/sys/arm64/arm64/cmn600.c new file mode 100644 index 000000000000..9ed998bc0354 --- /dev/null +++ b/sys/arm64/arm64/cmn600.c @@ -0,0 +1,834 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2021 ARM Ltd + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/* Arm CoreLink CMN-600 Coherent Mesh Network Driver */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_acpi.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#define RD4(sc, r) bus_read_4((sc)->sc_res[0], (r)) +#define RD8(sc, r) bus_read_8((sc)->sc_res[0], (r)) +#define WR4(sc, r, v) bus_write_4((sc)->sc_res[0], (r), (v)) +#define WR8(sc, r, v) bus_write_8((sc)->sc_res[0], (r), (v)) +#define FLD(v, n) (((v) & n ## _MASK) >> n ## _SHIFT) + +static char *cmn600_ids[] = { + "ARMHC600", + NULL +}; + +static struct resource_spec cmn600_res_spec[] = { + { SYS_RES_MEMORY, 0, RF_ACTIVE }, + { SYS_RES_MEMORY, 1, RF_ACTIVE | RF_UNMAPPED | RF_OPTIONAL }, + { SYS_RES_IRQ, 0, RF_ACTIVE }, + { -1, 0 } +}; + +struct cmn600_node; + +typedef uint64_t (*nd_read_8_t)(struct cmn600_node *, uint32_t); +typedef uint32_t (*nd_read_4_t)(struct cmn600_node *, uint32_t); +typedef void (*nd_write_8_t)(struct cmn600_node *, uint32_t, uint64_t); +typedef void (*nd_write_4_t)(struct cmn600_node *, uint32_t, uint32_t); + +struct cmn600_node { + struct cmn600_softc *sc; + off_t nd_offset; + int nd_type; + uint16_t nd_id; + uint16_t nd_logical_id; + uint8_t nd_x, nd_y, nd_port, nd_sub; + uint16_t nd_child_count; + uint32_t nd_paired; + struct cmn600_node *nd_parent; + nd_read_8_t nd_read8; + nd_read_4_t nd_read4; + nd_write_8_t nd_write8; + nd_write_4_t nd_write4; + struct cmn600_node **nd_children; +}; + +struct cmn600_softc { + device_t sc_dev; + int sc_unit; + int sc_domain; + int sc_longid; + int sc_mesh_x; + int sc_mesh_y; + struct resource *sc_res[3]; + void *sc_ih; + int sc_r2; + int sc_rev; + struct cmn600_node *sc_rootnode; + struct cmn600_node *sc_dtcnode; + struct cmn600_node *sc_dvmnode; + struct cmn600_node *sc_xpnodes[64]; + int (*sc_pmu_ih)(struct trapframe *tf, int unit, int i); +}; + +static struct cmn600_pmc cmn600_pmcs[CMN600_UNIT_MAX]; +static int cmn600_npmcs = 0; + +static int cmn600_acpi_detach(device_t dev); +static int cmn600_intr(void *arg); + +static void +cmn600_pmc_register(int unit, void *arg, int domain) +{ + + if (unit >= CMN600_UNIT_MAX) { + /* TODO */ + return; + } + + cmn600_pmcs[unit].arg = arg; + cmn600_pmcs[unit].domain = domain; + cmn600_npmcs++; +} + +static void +cmn600_pmc_unregister(int unit) +{ + + cmn600_pmcs[unit].arg = NULL; + cmn600_npmcs--; +} + +int +cmn600_pmc_nunits(void) +{ + + return (cmn600_npmcs); +} + +int +cmn600_pmc_getunit(int unit, void **arg, int *domain) +{ + + if (unit >= cmn600_npmcs) + return (EINVAL); + if (cmn600_pmcs[unit].arg == NULL) + return (EINVAL); + *arg = cmn600_pmcs[unit].arg; + *domain = cmn600_pmcs[unit].domain; + return (0); +} + +int +pmu_cmn600_rev(void *arg) +{ + struct cmn600_softc *sc; + + sc = (struct cmn600_softc *)arg; + switch (sc->sc_rev) { + case 0x0: + return (0x100); + case 0x1: + return (0x101); + case 0x2: + return (0x102); + case 0x3: + return (0x103); + case 0x4: + return (0x200); + case 0x5: + return (0x300); + case 0x6: + return (0x301); + } + return (0x302); /* Unknown revision. */ +} + +static uint64_t +cmn600_node_read8(struct cmn600_node *nd, uint32_t reg) +{ + + return (RD8(nd->sc, nd->nd_offset + reg)); +} + +static void +cmn600_node_write8(struct cmn600_node *nd, uint32_t reg, uint64_t val) +{ + + WR8(nd->sc, nd->nd_offset + reg, val); +} + +static uint32_t +cmn600_node_read4(struct cmn600_node *nd, uint32_t reg) +{ + + return (RD4(nd->sc, nd->nd_offset + reg)); +} + +static void +cmn600_node_write4(struct cmn600_node *nd, uint32_t reg, uint32_t val) +{ + + WR4(nd->sc, nd->nd_offset + reg, val); +} + +static const char * +cmn600_node_type_str(int type) +{ + +#define NAME_OF(t, n) case NODE_TYPE_ ## t: return n + switch (type) { + NAME_OF(INVALID, ""); + NAME_OF(DVM, "DVM"); + NAME_OF(CFG, "CFG"); + NAME_OF(DTC, "DTC"); + NAME_OF(HN_I, "HN-I"); + NAME_OF(HN_F, "HN-F"); + NAME_OF(XP, "XP"); + NAME_OF(SBSX, "SBSX"); + NAME_OF(RN_I, "RN-I"); + NAME_OF(RN_D, "RN-D"); + NAME_OF(RN_SAM, "RN-SAM"); + NAME_OF(CXRA, "CXRA"); + NAME_OF(CXHA, "CXHA"); + NAME_OF(CXLA, "CXLA"); + default: + return ""; + } +#undef NAME_OF +} + +static const char * +cmn600_xpport_dev_type_str(uint8_t type) +{ + +#define NAME_OF(t, n) case POR_MXP_PX_INFO_DEV_TYPE_ ## t: return n + switch (type) { + NAME_OF(RN_I, "RN-I"); + NAME_OF(RN_D, "RN-D"); + NAME_OF(RN_F_CHIB, "RN-F CHIB"); + NAME_OF(RN_F_CHIB_ESAM, "RN-F CHIB ESAM"); + NAME_OF(RN_F_CHIA, "RN-F CHIA"); + NAME_OF(RN_F_CHIA_ESAM, "RN-F CHIA ESAM"); + NAME_OF(HN_T, "HN-T"); + NAME_OF(HN_I, "HN-I"); + NAME_OF(HN_D, "HN-D"); + NAME_OF(SN_F, "SN-F"); + NAME_OF(SBSX, "SBSX"); + NAME_OF(HN_F, "HN-F"); + NAME_OF(CXHA, "CXHA"); + NAME_OF(CXRA, "CXRA"); + NAME_OF(CXRH, "CXRH"); + default: + return ""; + } +#undef NAME_OF +} + +static void +cmn600_dump_node(struct cmn600_node *node, int lvl) +{ + int i; + + for (i = 0; i < lvl; i++) printf(" "); + printf("%s [%dx%d:%d:%d] id: 0x%x @0x%lx Logical Id: 0x%x", + cmn600_node_type_str(node->nd_type), node->nd_x, node->nd_y, + node->nd_port, node->nd_sub, node->nd_id, node->nd_offset, + node->nd_logical_id); + if (node->nd_child_count > 0) + printf(", Children: %d", node->nd_child_count); + printf("\n"); + if (node->nd_type == NODE_TYPE_XP) + printf("\tPort 0: %s\n\tPort 1: %s\n", + cmn600_xpport_dev_type_str(node->nd_read4(node, + POR_MXP_P0_INFO) & 0x1f), + cmn600_xpport_dev_type_str(node->nd_read4(node, + POR_MXP_P1_INFO) & 0x1f)); +} + +static void +cmn600_dump_node_recursive(struct cmn600_node *node, int lvl) +{ + int i; + + cmn600_dump_node(node, lvl); + for (i = 0; i < node->nd_child_count; i++) { + cmn600_dump_node_recursive(node->nd_children[i], lvl + 1); + } +} + +static void +cmn600_dump_nodes_tree(struct cmn600_softc *sc) +{ + + device_printf(sc->sc_dev, " nodes:\n"); + cmn600_dump_node_recursive(sc->sc_rootnode, 0); +} + +static int +cmn600_sysctl_dump_nodes(SYSCTL_HANDLER_ARGS) +{ + struct cmn600_softc *sc; + uint32_t val; + int err; + + sc = (struct cmn600_softc *)arg1; + val = 0; + err = sysctl_handle_int(oidp, &val, 0, req); + + if (err) + return (err); + + if (val != 0) + cmn600_dump_nodes_tree(sc); + + return (0); +} + +static struct cmn600_node * +cmn600_create_node(struct cmn600_softc *sc, off_t node_offset, + struct cmn600_node *parent, int lvl) +{ + struct cmn600_node *node; + off_t child_offset; + uint64_t val; + int i; + + node = malloc(sizeof(struct cmn600_node), M_DEVBUF, M_WAITOK); + if (node == NULL) + return (NULL); + + node->sc = sc; + node->nd_offset = node_offset; + node->nd_parent = parent; + node->nd_read4 = cmn600_node_read4; + node->nd_read8 = cmn600_node_read8; + node->nd_write4 = cmn600_node_write4; + node->nd_write8 = cmn600_node_write8; + + val = node->nd_read8(node, POR_CFGM_NODE_INFO); + node->nd_type = FLD(val, POR_CFGM_NODE_INFO_NODE_TYPE); + node->nd_id = FLD(val, POR_CFGM_NODE_INFO_NODE_ID); + node->nd_logical_id = FLD(val, POR_CFGM_NODE_INFO_LOGICAL_ID); + + val = node->nd_read8(node, POR_CFGM_CHILD_INFO); + node->nd_child_count = FLD(val, POR_CFGM_CHILD_INFO_CHILD_COUNT); + child_offset = FLD(val, POR_CFGM_CHILD_INFO_CHILD_PTR_OFFSET); + + if (parent == NULL) { + /* Find XP node with Id 8. It have to be last in a row. */ + for (i = 0; i < node->nd_child_count; i++) { + val = node->nd_read8(node, child_offset + (i * 8)); + val &= POR_CFGM_CHILD_POINTER_BASE_MASK; + val = RD8(sc, val + POR_CFGM_NODE_INFO); + + if (FLD(val, POR_CFGM_NODE_INFO_NODE_ID) != 8) + continue; + + sc->sc_mesh_x = FLD(val, POR_CFGM_NODE_INFO_LOGICAL_ID); + sc->sc_mesh_y = node->nd_child_count / sc->sc_mesh_x; + if (bootverbose) + printf("Mesh width X/Y %d/%d\n", sc->sc_mesh_x, + sc->sc_mesh_y); + + if ((sc->sc_mesh_x > 4) || (sc->sc_mesh_y > 4)) + sc->sc_longid = 1; + break; + } + + val = node->nd_read8(node, POR_INFO_GLOBAL); + sc->sc_r2 = (val & POR_INFO_GLOBAL_R2_ENABLE) ? 1 : 0; + val = node->nd_read4(node, POR_CFGM_PERIPH_ID_2_PERIPH_ID_3); + sc->sc_rev = FLD(val, POR_CFGM_PERIPH_ID_2_REV); + if (bootverbose) + printf(" Rev: %d, R2_ENABLE = %s\n", sc->sc_rev, + sc->sc_r2 ? "true" : "false"); + } + node->nd_sub = FLD(node->nd_id, NODE_ID_SUB); + node->nd_port = FLD(node->nd_id, NODE_ID_PORT); + node->nd_paired = 0; + if (sc->sc_longid == 1) { + node->nd_x = FLD(node->nd_id, NODE_ID_X3B); + node->nd_y = FLD(node->nd_id, NODE_ID_Y3B); + } else { + node->nd_x = FLD(node->nd_id, NODE_ID_X2B); + node->nd_y = FLD(node->nd_id, NODE_ID_Y2B); + } + + if (bootverbose) { + cmn600_dump_node(node, lvl); + } + + node->nd_children = (struct cmn600_node **)mallocarray( + node->nd_child_count, sizeof(struct cmn600_node *), M_DEVBUF, + M_WAITOK); + if (node->nd_children == NULL) + goto FAIL; + for (i = 0; i < node->nd_child_count; i++) { + val = node->nd_read8(node, child_offset + (i * 8)); + node->nd_children[i] = cmn600_create_node(sc, val & + POR_CFGM_CHILD_POINTER_BASE_MASK, node, lvl + 1); + } + switch (node->nd_type) { + case NODE_TYPE_DTC: + sc->sc_dtcnode = node; + break; + case NODE_TYPE_DVM: + sc->sc_dvmnode = node; + break; + case NODE_TYPE_XP: + sc->sc_xpnodes[node->nd_id >> NODE_ID_X2B_SHIFT] = node; + break; + default: + break; + } + return (node); +FAIL: + free(node, M_DEVBUF); + return (NULL); +} + +static void +cmn600_destroy_node(struct cmn600_node *node) +{ + int i; + + for (i = 0; i < node->nd_child_count; i++) { + if (node->nd_children[i] == NULL) + continue; + cmn600_destroy_node(node->nd_children[i]); + } + free(node->nd_children, M_DEVBUF); + free(node, M_DEVBUF); +} + +static int +cmn600_find_node(struct cmn600_softc *sc, int node_id, int type, + struct cmn600_node **node) +{ + struct cmn600_node *xp, *child; + uint8_t xp_xy; + int i; + + switch (type) { + case NODE_TYPE_INVALID: + return (ENXIO); + case NODE_TYPE_CFG: + *node = sc->sc_rootnode; + return (0); + case NODE_TYPE_DTC: + *node = sc->sc_dtcnode; + return (0); + case NODE_TYPE_DVM: + *node = sc->sc_dvmnode; + return (0); + default: + break; + } + + xp_xy = node_id >> NODE_ID_X2B_SHIFT; + if (xp_xy >= 64) + return (ENXIO); + if (sc->sc_xpnodes[xp_xy] == NULL) + return (ENOENT); + + switch (type) { + case NODE_TYPE_XP: + *node = sc->sc_xpnodes[xp_xy]; + return (0); + default: + xp = sc->sc_xpnodes[xp_xy]; + for (i = 0; i < xp->nd_child_count; i++) { + child = xp->nd_children[i]; + if (child->nd_id == node_id && child->nd_type == type) { + *node = child; + return (0); + } + } + } + return (ENOENT); +} + +int +pmu_cmn600_alloc_localpmc(void *arg, int nodeid, int node_type, int *counter) +{ + struct cmn600_node *node; + struct cmn600_softc *sc; + uint32_t new, old; + int i, ret; + + sc = (struct cmn600_softc *)arg; + switch (node_type) { + case NODE_TYPE_CXLA: + break; + default: + node_type = NODE_TYPE_XP; + /* Parent XP node has always zero port and device bits. */ + nodeid &= ~0x07; + } + ret = cmn600_find_node(sc, nodeid, node_type, &node); + if (ret != 0) + return (ret); + for (i = 0; i < 4; i++) { + new = old = node->nd_paired; + if (old == 0xf) + return (EBUSY); + if ((old & (1 << i)) != 0) + continue; + new |= 1 << i; + if (atomic_cmpset_32(&node->nd_paired, old, new) != 0) + break; + } + *counter = i; + return (0); +} + +int +pmu_cmn600_free_localpmc(void *arg, int nodeid, int node_type, int counter) +{ + struct cmn600_node *node; + struct cmn600_softc *sc; + uint32_t new, old; + int ret; + + sc = (struct cmn600_softc *)arg; + switch (node_type) { + case NODE_TYPE_CXLA: + break; + default: + node_type = NODE_TYPE_XP; + } + ret = cmn600_find_node(sc, nodeid, node_type, &node); + if (ret != 0) + return (ret); + + do { + new = old = node->nd_paired; + new &= ~(1 << counter); + } while (atomic_cmpset_32(&node->nd_paired, old, new) == 0); + return (0); +} + +uint32_t +pmu_cmn600_rd4(void *arg, int nodeid, int node_type, off_t reg) +{ + struct cmn600_node *node; + struct cmn600_softc *sc; + int ret; + + sc = (struct cmn600_softc *)arg; + ret = cmn600_find_node(sc, nodeid, node_type, &node); + if (ret != 0) + return (UINT32_MAX); + return (cmn600_node_read4(node, reg)); +} + +int +pmu_cmn600_wr4(void *arg, int nodeid, int node_type, off_t reg, uint32_t val) +{ + struct cmn600_node *node; + struct cmn600_softc *sc; + int ret; + + sc = (struct cmn600_softc *)arg; + ret = cmn600_find_node(sc, nodeid, node_type, &node); + if (ret != 0) + return (ret); + cmn600_node_write4(node, reg, val); + return (0); +} + +uint64_t +pmu_cmn600_rd8(void *arg, int nodeid, int node_type, off_t reg) +{ + struct cmn600_node *node; + struct cmn600_softc *sc; + int ret; + + sc = (struct cmn600_softc *)arg; + ret = cmn600_find_node(sc, nodeid, node_type, &node); + if (ret != 0) + return (UINT64_MAX); + return (cmn600_node_read8(node, reg)); +} + +int +pmu_cmn600_wr8(void *arg, int nodeid, int node_type, off_t reg, uint64_t val) +{ + struct cmn600_node *node; + struct cmn600_softc *sc; + int ret; + + sc = (struct cmn600_softc *)arg; + ret = cmn600_find_node(sc, nodeid, node_type, &node); + if (ret != 0) + return (ret); + cmn600_node_write8(node, reg, val); + return (0); +} + +int +pmu_cmn600_set8(void *arg, int nodeid, int node_type, off_t reg, uint64_t val) +{ + struct cmn600_node *node; + struct cmn600_softc *sc; + int ret; + + sc = (struct cmn600_softc *)arg; + ret = cmn600_find_node(sc, nodeid, node_type, &node); + if (ret != 0) + return (ret); + cmn600_node_write8(node, reg, cmn600_node_read8(node, reg) | val); + return (0); +} + +int +pmu_cmn600_clr8(void *arg, int nodeid, int node_type, off_t reg, uint64_t val) +{ + struct cmn600_node *node; + struct cmn600_softc *sc; + int ret; + + sc = (struct cmn600_softc *)arg; + ret = cmn600_find_node(sc, nodeid, node_type, &node); + if (ret != 0) + return (ret); + cmn600_node_write8(node, reg, cmn600_node_read8(node, reg) & ~val); + return (0); +} + +int +pmu_cmn600_md8(void *arg, int nodeid, int node_type, off_t reg, uint64_t mask, + uint64_t val) +{ + struct cmn600_node *node; + struct cmn600_softc *sc; + int ret; + + sc = (struct cmn600_softc *)arg; + ret = cmn600_find_node(sc, nodeid, node_type, &node); + if (ret != 0) + return (ret); + cmn600_node_write8(node, reg, (cmn600_node_read8(node, reg) & ~mask) | + val); + return (0); +} + +static int +cmn600_acpi_probe(device_t dev) +{ + int err; + + err = ACPI_ID_PROBE(device_get_parent(dev), dev, cmn600_ids, NULL); + if (err <= 0) + device_set_desc(dev, "Arm CoreLink CMN-600 Coherent Mesh Network"); + + return (err); +} + +static int +cmn600_acpi_attach(device_t dev) +{ + struct sysctl_ctx_list *ctx; + struct sysctl_oid_list *child; + struct cmn600_softc *sc; + int cpu, domain, i, u; + const char *dname; + rman_res_t count, periph_base, rootnode_base; + struct cmn600_node *node; + + dname = device_get_name(dev); + sc = device_get_softc(dev); + sc->sc_dev = dev; + u = device_get_unit(dev); + sc->sc_unit = u; + domain = 0; + + if ((resource_int_value(dname, u, "domain", &domain) == 0 || + bus_get_domain(dev, &domain) == 0) && domain < MAXMEMDOM) { + sc->sc_domain = domain; + } + if (domain == -1) /* NUMA not supported. Use single domain. */ + domain = 0; + sc->sc_domain = domain; + device_printf(dev, "domain=%d\n", sc->sc_domain); + + cpu = CPU_FFS(&cpuset_domain[domain]) - 1; + + i = bus_alloc_resources(dev, cmn600_res_spec, sc->sc_res); + if (i != 0) { + device_printf(dev, "cannot allocate resources for device (%d)\n", + i); + return (i); + } + + bus_get_resource(dev, cmn600_res_spec[0].type, cmn600_res_spec[0].rid, + &periph_base, &count); + bus_get_resource(dev, cmn600_res_spec[1].type, cmn600_res_spec[1].rid, + &rootnode_base, &count); + rootnode_base -= periph_base; + if (bootverbose) + printf("ROOTNODE at %lx x %lx\n", rootnode_base, count); + + sc->sc_rootnode = cmn600_create_node(sc, rootnode_base, NULL, 0); + ctx = device_get_sysctl_ctx(sc->sc_dev); + + child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->sc_dev)); + SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "dump_nodes", CTLTYPE_INT | + CTLFLAG_RW | CTLFLAG_NEEDGIANT, sc, 0, cmn600_sysctl_dump_nodes, + "U", "Dump CMN-600 nodes tree"); + + node = sc->sc_dtcnode; + if (node == NULL) + return (ENXIO); + + cmn600_pmc_register(sc->sc_unit, (void *)sc, domain); + + node->nd_write8(node, POR_DT_PMCR, 0); + node->nd_write8(node, POR_DT_PMOVSR_CLR, POR_DT_PMOVSR_ALL); + node->nd_write8(node, POR_DT_PMCR, POR_DT_PMCR_OVFL_INTR_EN); + node->nd_write8(node, POR_DT_DTC_CTL, POR_DT_DTC_CTL_DT_EN); + + if (bus_setup_intr(dev, sc->sc_res[2], INTR_TYPE_MISC | INTR_MPSAFE, + cmn600_intr, NULL, sc, &sc->sc_ih)) { + bus_release_resources(dev, cmn600_res_spec, sc->sc_res); + device_printf(dev, "cannot setup interrupt handler\n"); + cmn600_acpi_detach(dev); + return (ENXIO); + } + if (bus_bind_intr(dev, sc->sc_res[2], cpu)) { + bus_teardown_intr(dev, sc->sc_res[2], sc->sc_ih); + bus_release_resources(dev, cmn600_res_spec, sc->sc_res); + device_printf(dev, "cannot setup interrupt handler\n"); + cmn600_acpi_detach(dev); + return (ENXIO); + } + return (0); +} + +static int +cmn600_acpi_detach(device_t dev) +{ + struct cmn600_softc *sc; + struct cmn600_node *node; + + sc = device_get_softc(dev); + if (sc->sc_res[2] != NULL) { + bus_teardown_intr(dev, sc->sc_res[2], sc->sc_ih); + } + + node = sc->sc_dtcnode; + node->nd_write4(node, POR_DT_DTC_CTL, + node->nd_read4(node, POR_DT_DTC_CTL) & ~POR_DT_DTC_CTL_DT_EN); + node->nd_write8(node, POR_DT_PMOVSR_CLR, POR_DT_PMOVSR_ALL); + + cmn600_pmc_unregister(sc->sc_unit); + cmn600_destroy_node(sc->sc_rootnode); + bus_release_resources(dev, cmn600_res_spec, sc->sc_res); + + return (0); +} + +int +cmn600_pmu_intr_cb(void *arg, int (*handler)(struct trapframe *tf, int unit, + int i)) +{ + struct cmn600_softc *sc; + + sc = (struct cmn600_softc *) arg; + sc->sc_pmu_ih = handler; + return (0); +} + +static int +cmn600_intr(void *arg) +{ + struct cmn600_node *node; + struct cmn600_softc *sc; + struct trapframe *tf; + uint64_t mask, ready, val; + int i; + + tf = PCPU_GET(curthread)->td_intr_frame; + sc = (struct cmn600_softc *) arg; + node = sc->sc_dtcnode; + val = node->nd_read8(node, POR_DT_PMOVSR); + if (val & POR_DT_PMOVSR_CYCLE_COUNTER) + node->nd_write8(node, POR_DT_PMOVSR_CLR, + POR_DT_PMOVSR_CYCLE_COUNTER); + if (val & POR_DT_PMOVSR_EVENT_COUNTERS) { + for (ready = 0, i = 0; i < 8; i++) { + mask = 1 << i; + if ((val & mask) == 0) + continue; + if (sc->sc_pmu_ih != NULL) + sc->sc_pmu_ih(tf, sc->sc_unit, i); + ready |= mask; + + } + node->nd_write8(node, POR_DT_PMOVSR_CLR, ready); + } + + return (FILTER_HANDLED); +} + +static device_method_t cmn600_acpi_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, cmn600_acpi_probe), + DEVMETHOD(device_attach, cmn600_acpi_attach), + DEVMETHOD(device_detach, cmn600_acpi_detach), + + /* End */ + DEVMETHOD_END +}; + +static driver_t cmn600_acpi_driver = { + "cmn600", + cmn600_acpi_methods, + sizeof(struct cmn600_softc), +}; +static devclass_t cmn600_acpi_devclass; + +DRIVER_MODULE(cmn600, acpi, cmn600_acpi_driver, cmn600_acpi_devclass, 0, 0); +MODULE_VERSION(cmn600, 1); diff --git a/sys/arm64/include/cmn600_reg.h b/sys/arm64/include/cmn600_reg.h index ffc4634f2781..d7fc9ecaac98 100644 --- a/sys/arm64/include/cmn600_reg.h +++ b/sys/arm64/include/cmn600_reg.h @@ -1,793 +1,809 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2021 ARM Ltd * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _MACHINE_CMN600_REG_H_ #define _MACHINE_CMN600_REG_H_ #define CMN600_COUNTERS_N 8 #define CMN600_UNIT_MAX 4 #define CMN600_PMU_DEFAULT_UNITS_N 2 #define CMN600_COMMON_PMU_EVENT_SEL 0x2000 /* rw */ #define CMN600_COMMON_PMU_EVENT_SEL_OCC_SHIFT 32 #define CMN600_COMMON_PMU_EVENT_SEL_OCC_MASK (0x7UL << 32) struct cmn600_pmc { void *arg; int domain; }; int cmn600_pmc_nunits(void); int cmn600_pmc_getunit(int unit, void **arg, int *domain); int cmn600_pmu_intr_cb(void *arg, int (*handler)(struct trapframe *tf, int unit, int i)); int pmu_cmn600_alloc_localpmc(void *arg, int nodeid, int node_type, int *local_counter); int pmu_cmn600_free_localpmc(void *arg, int nodeid, int node_type, int local_counter); int pmu_cmn600_rev(void *arg); uint32_t pmu_cmn600_rd4(void *arg, int nodeid, int node_type, off_t reg); int pmu_cmn600_wr4(void *arg, int nodeid, int node_type, off_t reg, uint32_t val); uint64_t pmu_cmn600_rd8(void *arg, int nodeid, int node_type, off_t reg); int pmu_cmn600_wr8(void *arg, int nodeid, int node_type, off_t reg, uint64_t val); int pmu_cmn600_set8(void *arg, int nodeid, int node_type, off_t reg, uint64_t val); int pmu_cmn600_clr8(void *arg, int nodeid, int node_type, off_t reg, uint64_t val); int pmu_cmn600_md8(void *arg, int nodeid, int node_type, off_t reg, uint64_t mask, uint64_t val); /* Configuration master registers */ #define POR_CFGM_NODE_INFO 0x0000 /* ro */ #define POR_CFGM_NODE_INFO_LOGICAL_ID_MASK 0xffff00000000UL #define POR_CFGM_NODE_INFO_LOGICAL_ID_SHIFT 32 #define POR_CFGM_NODE_INFO_NODE_ID_MASK 0xffff0000 #define POR_CFGM_NODE_INFO_NODE_ID_SHIFT 16 #define POR_CFGM_NODE_INFO_NODE_TYPE_MASK 0xffff #define POR_CFGM_NODE_INFO_NODE_TYPE_SHIFT 0 +#define NODE_ID_SUB_MASK 0x3 +#define NODE_ID_SUB_SHIFT 0 +#define NODE_ID_PORT_MASK 0x4 +#define NODE_ID_PORT_SHIFT 2 +#define NODE_ID_X2B_MASK (0x3 << 3) +#define NODE_ID_X2B_SHIFT 3 +#define NODE_ID_Y2B_MASK (0x3 << 5) +#define NODE_ID_Y2B_SHIFT 5 +#define NODE_ID_X3B_MASK (0x7 << 3) +#define NODE_ID_X3B_SHIFT 3 +#define NODE_ID_Y3B_MASK (0x7 << 6) +#define NODE_ID_Y3B_SHIFT 6 + #define NODE_TYPE_INVALID 0x000 #define NODE_TYPE_DVM 0x001 #define NODE_TYPE_CFG 0x002 #define NODE_TYPE_DTC 0x003 #define NODE_TYPE_HN_I 0x004 #define NODE_TYPE_HN_F 0x005 #define NODE_TYPE_XP 0x006 #define NODE_TYPE_SBSX 0x007 #define NODE_TYPE_RN_I 0x00A #define NODE_TYPE_RN_D 0x00D #define NODE_TYPE_RN_SAM 0x00F #define NODE_TYPE_CXRA 0x100 #define NODE_TYPE_CXHA 0x101 #define NODE_TYPE_CXLA 0x102 #define POR_CFGM_PERIPH_ID_0_PERIPH_ID_1 0x0008 /* ro */ #define POR_CFGM_PERIPH_ID_2_PERIPH_ID_3 0x0010 /* ro */ #define POR_CFGM_PERIPH_ID_2_REV_SHIFT 4 #define POR_CFGM_PERIPH_ID_2_REV_MASK 0xf0 #define POR_CFGM_PERIPH_ID_2_REV_R1P0 0 #define POR_CFGM_PERIPH_ID_2_REV_R1P1 1 #define POR_CFGM_PERIPH_ID_2_REV_R1P2 2 #define POR_CFGM_PERIPH_ID_2_REV_R1P3 3 #define POR_CFGM_PERIPH_ID_2_REV_R2P0 4 #define POR_CFGM_PERIPH_ID_4_PERIPH_ID_5 0x0018 /* ro */ #define POR_CFGM_PERIPH_ID_6_PERIPH_ID_7 0x0020 /* ro */ #define POR_CFGM_PERIPH_ID_32(x) (0x0008 + ((x) * 4)) /* ro 32 */ #define POR_CFGM_COMPONENT_ID_0_COMPONENT_ID_1 0x0028 /* ro */ #define POR_CFGM_COMPONENT_ID_2_COMPONENT_ID_3 0x0030 /* ro */ #define POR_CFGM_CHILD_INFO 0x0080 /* ro */ #define POR_CFGM_CHILD_INFO_CHILD_PTR_OFFSET_MASK 0xffff0000 #define POR_CFGM_CHILD_INFO_CHILD_PTR_OFFSET_SHIFT 16 #define POR_CFGM_CHILD_INFO_CHILD_COUNT_MASK 0x0000ffff #define POR_CFGM_CHILD_INFO_CHILD_COUNT_SHIFT 0 #define POR_CFGM_SECURE_ACCESS 0x0980 /* rw */ #define POR_CFGM_ERRGSR0 0x3000 /* ro */ #define POR_CFGM_ERRGSR1 0x3008 /* ro */ #define POR_CFGM_ERRGSR2 0x3010 /* ro */ #define POR_CFGM_ERRGSR3 0x3018 /* ro */ #define POR_CFGM_ERRGSR4 0x3020 /* ro */ #define POR_CFGM_ERRGSR5 0x3080 /* ro */ #define POR_CFGM_ERRGSR6 0x3088 /* ro */ #define POR_CFGM_ERRGSR7 0x3090 /* ro */ #define POR_CFGM_ERRGSR8 0x3098 /* ro */ #define POR_CFGM_ERRGSR9 0x30a0 /* ro */ #define POR_CFGM_ERRGSR(x) (0x3000 + ((x) * 8)) /* ro */ #define POR_CFGM_ERRGSR0_ns 0x3100 /* ro */ #define POR_CFGM_ERRGSR1_ns 0x3108 /* ro */ #define POR_CFGM_ERRGSR2_ns 0x3110 /* ro */ #define POR_CFGM_ERRGSR3_ns 0x3118 /* ro */ #define POR_CFGM_ERRGSR4_ns 0x3120 /* ro */ #define POR_CFGM_ERRGSR5_ns 0x3180 /* ro */ #define POR_CFGM_ERRGSR6_ns 0x3188 /* ro */ #define POR_CFGM_ERRGSR7_ns 0x3190 /* ro */ #define POR_CFGM_ERRGSR8_ns 0x3198 /* ro */ #define POR_CFGM_ERRGSR9_ns 0x31a0 /* ro */ #define POR_CFGM_ERRGSR_ns(x) (0x3100 + ((x) * 8)) /* ro */ #define POR_CFGM_ERRDEVAFF 0x3fa8 /* ro */ #define POR_CFGM_ERRDEVARCH 0x3fb8 /* ro */ #define POR_CFGM_ERRIDR 0x3fc8 /* ro */ #define POR_CFGM_ERRPIDR45 0x3fd0 /* ro */ #define POR_CFGM_ERRPIDR67 0x3fd8 /* ro */ #define POR_CFGM_ERRPIDR01 0x3fe0 /* ro */ #define POR_CFGM_ERRPIDR23 0x3fe8 /* ro */ #define POR_CFGM_ERRCIDR01 0x3ff0 /* ro */ #define POR_CFGM_ERRCIDR23 0x3ff8 /* ro */ #define POR_INFO_GLOBAL 0x0900 /* ro */ #define POR_INFO_GLOBAL_CHIC_MODE_EN (1UL << 49) /* CHI-C mode enable */ #define POR_INFO_GLOBAL_R2_ENABLE (1UL << 48) /* CMN R2 feature enable */ #define POR_INFO_GLOBAL_RNSAM_NUM_ADD_HASHED_TGT_SHIFT 36 /* Number of additional hashed target ID's supported by the RN SAM, beyond the local HNF count */ #define POR_INFO_GLOBAL_RNSAM_NUM_ADD_HASHED_TGT_MASK (0x3fUL << 36) #define POR_INFO_GLOBAL_NUM_REMOTE_RNF_SHIFT 28 /* Number of remote RN-F devices in the system when the CML feature is enabled */ #define POR_INFO_GLOBAL_NUM_REMOTE_RNF_MASK (0xffUL << 28) #define POR_INFO_GLOBAL_FLIT_PARITY_EN (1 << 25) /* Indicates whether parity checking is enabled in the transport layer on all flits sent on the interconnect */ #define POR_INFO_GLOBAL_DATACHECK_EN (1 << 24) /* Indicates whether datacheck feature is enabled for CHI DAT flit */ #define POR_INFO_GLOBAL_PHYSICAL_ADDRESS_WIDTH_SHIFT 16 /* Physical address width */ #define POR_INFO_GLOBAL_PHYSICAL_ADDRESS_WIDTH_MASK (0xff << 16) #define POR_INFO_GLOBAL_CHI_REQ_ADDR_WIDTH_SHIFT 8 /* REQ address width */ #define POR_INFO_GLOBAL_CHI_REQ_ADDR_WIDTH_MASK (0xff << 8) #define POR_INFO_GLOBAL_CHI_REQ_RSVDC_WIDTH_SHIFT 0 /* RSVDC field width in CHI REQ flit */ #define POR_INFO_GLOBAL_CHI_REQ_RSVDC_WIDTH_MASK 0xff #define POR_PPU_INT_ENABLE 0x1000 /* rw */ #define POR_PPU_INT_STATUS 0x1008 /* w1c */ #define POR_PPU_QACTIVE_HYST 0x1010 /* rw */ #define POR_CFGM_CHILD_POINTER_0 0x0100 /* ro */ #define POR_CFGM_CHILD_POINTER(x) (POR_CFGM_CHILD_POINTER_0 + ((x) * 8)) #define POR_CFGM_CHILD_POINTER_EXT (1 << 31) #define POR_CFGM_CHILD_POINTER_BASE_MASK 0x0fffffffUL /* DN registers */ #define POR_DN_NODE_INFO 0x0000 /* ro */ #define POR_DN_CHILD_INFO 0x0080 /* ro */ #define POR_DN_BUILD_INFO 0x0900 /* ro */ #define POR_DN_SECURE_REGISTER_GROUPS_OVERRIDE 0x0980 /* rw */ #define POR_DN_AUX_CTL 0x0a00 /* rw */ #define POR_DN_VMF0_CTRL 0x0c00 /* rw */ #define POR_DN_VMF0_RNF0 0x0c08 /* rw */ #define POR_DN_VMF0_RND 0x0c10 /* rw */ #define POR_DN_VMF0_CXRA 0x0c18 /* rw */ #define POR_DN_VMF1_CTRL 0x0c20 /* rw */ #define POR_DN_VMF1_RNF0 0x0c28 /* rw */ #define POR_DN_VMF1_RND 0x0c30 /* rw */ #define POR_DN_VMF1_CXRA 0x0c38 /* rw */ #define POR_DN_VMF2_CTRL 0x0c40 /* rw */ #define POR_DN_VMF2_RNF0 0x0c48 /* rw */ #define POR_DN_VMF2_RND 0x0c50 /* rw */ #define POR_DN_VMF2_CXRA 0x0c58 /* rw */ #define POR_DN_VMF3_CTRL 0x0c60 /* rw */ #define POR_DN_VMF3_RNF0 0x0c68 /* rw */ #define POR_DN_VMF3_RND 0x0c70 /* rw */ #define POR_DN_VMF3_CXRA 0x0c78 /* rw */ #define POR_DN_VMF4_CTRL 0x0c80 /* rw */ #define POR_DN_VMF4_RNF0 0x0c88 /* rw */ #define POR_DN_VMF4_RND 0x0c90 /* rw */ #define POR_DN_VMF4_CXRA 0x0c98 /* rw */ #define POR_DN_VMF5_CTRL 0x0ca0 /* rw */ #define POR_DN_VMF5_RNF0 0x0ca8 /* rw */ #define POR_DN_VMF5_RND 0x0cb0 /* rw */ #define POR_DN_VMF5_CXRA 0x0cb8 /* rw */ #define POR_DN_VMF6_CTRL 0x0cc0 /* rw */ #define POR_DN_VMF6_RNF0 0x0cc8 /* rw */ #define POR_DN_VMF6_RND 0x0cd0 /* rw */ #define POR_DN_VMF6_CXRA 0x0cd8 /* rw */ #define POR_DN_VMF7_CTRL 0x0ce0 /* rw */ #define POR_DN_VMF7_RNF0 0x0ce8 /* rw */ #define POR_DN_VMF7_RND 0x0cf0 /* rw */ #define POR_DN_VMF7_CXRA 0x0cf8 /* rw */ #define POR_DN_VMF8_CTRL 0x0d00 /* rw */ #define POR_DN_VMF8_RNF0 0x0d08 /* rw */ #define POR_DN_VMF8_RND 0x0d10 /* rw */ #define POR_DN_VMF8_CXRA 0x0d18 /* rw */ #define POR_DN_VMF9_CTRL 0x0d20 /* rw */ #define POR_DN_VMF9_RNF0 0x0d28 /* rw */ #define POR_DN_VMF9_RND 0x0d30 /* rw */ #define POR_DN_VMF9_CXRA 0x0d38 /* rw */ #define POR_DN_VMF10_CTRL 0x0d40 /* rw */ #define POR_DN_VMF10_RNF0 0x0d48 /* rw */ #define POR_DN_VMF10_RND 0x0d50 /* rw */ #define POR_DN_VMF10_CXRA 0x0d58 /* rw */ #define POR_DN_VMF11_CTRL 0x0d60 /* rw */ #define POR_DN_VMF11_RNF0 0x0d68 /* rw */ #define POR_DN_VMF11_RND 0x0d70 /* rw */ #define POR_DN_VMF11_CXRA 0x0d78 /* rw */ #define POR_DN_VMF12_CTRL 0x0d80 /* rw */ #define POR_DN_VMF12_RNF0 0x0d88 /* rw */ #define POR_DN_VMF12_RND 0x0d90 /* rw */ #define POR_DN_VMF12_CXRA 0x0d98 /* rw */ #define POR_DN_VMF13_CTRL 0x0da0 /* rw */ #define POR_DN_VMF13_RNF0 0x0da8 /* rw */ #define POR_DN_VMF13_RND 0x0db0 /* rw */ #define POR_DN_VMF13_CXRA 0x0db8 /* rw */ #define POR_DN_VMF14_CTRL 0x0dc0 /* rw */ #define POR_DN_VMF14_RNF0 0x0dc8 /* rw */ #define POR_DN_VMF14_RND 0x0dd0 /* rw */ #define POR_DN_VMF14_CXRA 0x0dd8 /* rw */ #define POR_DN_VMF15_CTRL 0x0de0 /* rw */ #define POR_DN_VMF15_RNF0 0x0de8 /* rw */ #define POR_DN_VMF15_RND 0x0df0 /* rw */ #define POR_DN_VMF15_CXRA 0x0df8 /* rw */ #define POR_DN_PMU_EVENT_SEL 0x2000 /* rw */ #define POR_DN_PMU_EVENT_SEL_OCCUP1_ID_SHIFT 32 #define POR_DN_PMU_EVENT_SEL_OCCUP1_ID_MASK (0xf << 32) #define POR_DN_PMU_EVENT_SEL_OCCUP1_ID_ALL 0 #define POR_DN_PMU_EVENT_SEL_OCCUP1_ID_DVM_OPS 1 #define POR_DN_PMU_EVENT_SEL_OCCUP1_ID_DVM_SYNCS 2 #define POR_DN_PMU_EVENT_SEL_EVENT_ID3_SHIFT 24 #define POR_DN_PMU_EVENT_SEL_EVENT_ID3_MASK (0x3f << 24) #define POR_DN_PMU_EVENT_SEL_EVENT_ID2_SHIFT 16 #define POR_DN_PMU_EVENT_SEL_EVENT_ID2_MASK (0x3f << 16) #define POR_DN_PMU_EVENT_SEL_EVENT_ID1_SHIFT 8 #define POR_DN_PMU_EVENT_SEL_EVENT_ID1_MASK (0x3f << 8) #define POR_DN_PMU_EVENT_SEL_EVENT_ID0_SHIFT 0 #define POR_DN_PMU_EVENT_SEL_EVENT_ID0_MASK 0x3f /* Debug and trace register */ #define POR_DT_NODE_INFO 0x0000 /* ro */ #define POR_DT_CHILD_INFO 0x0080 /* ro */ #define POR_DT_SECURE_ACCESS 0x0980 /* rw */ #define POR_DT_DTC_CTL 0x0a00 /* rw */ #define POR_DT_DTC_CTL_DT_EN (1 << 0) #define POR_DT_TRIGGER_STATUS 0x0a10 /* ro */ #define POR_DT_TRIGGER_STATUS_CLR 0x0a20 /* wo */ #define POR_DT_TRACE_CONTROL 0x0a30 /* rw */ #define POR_DT_TRACEID 0x0a48 /* rw */ #define POR_DT_PMEVCNTAB 0x2000 /* rw */ #define POR_DT_PMEVCNTCD 0x2010 /* rw */ #define POR_DT_PMEVCNTEF 0x2020 /* rw */ #define POR_DT_PMEVCNTGH 0x2030 /* rw */ #define POR_DT_PMEVCNT(x) (0x2000 + ((x) * 0x10)) +#define POR_DT_PMEVCNT_EVENCNT_SHIFT 0 +#define POR_DT_PMEVCNT_ODDCNT_SHIFT 32 #define POR_DT_PMCCNTR 0x2040 /* rw */ #define POR_DT_PMEVCNTSRAB 0x2050 /* rw */ #define POR_DT_PMEVCNTSRCD 0x2060 /* rw */ #define POR_DT_PMEVCNTSREF 0x2070 /* rw */ #define POR_DT_PMEVCNTSRGH 0x2080 /* rw */ #define POR_DT_PMCCNTRSR 0x2090 /* rw */ #define POR_DT_PMCR 0x2100 /* rw */ #define POR_DT_PMCR_OVFL_INTR_EN (1 << 6) #define POR_DT_PMCR_CNTR_RST (1 << 5) #define POR_DT_PMCR_CNTCFG_SHIFT 1 #define POR_DT_PMCR_CNTCFG_MASK (0xf << POR_DT_PMCR_CNTCFG_SHIFT) #define POR_DT_PMCR_PMU_EN (1 << 0) #define POR_DT_PMOVSR 0x2118 /* ro */ #define POR_DT_PMOVSR_CLR 0x2120 /* wo */ #define POR_DT_PMOVSR_EVENT_COUNTERS 0xffUL #define POR_DT_PMOVSR_CYCLE_COUNTER 0x100UL #define POR_DT_PMOVSR_ALL \ (POR_DT_PMOVSR_EVENT_COUNTERS | POR_DT_PMOVSR_CYCLE_COUNTER) #define POR_DT_PMSSR 0x2128 /* ro */ #define POR_DT_PMSRR 0x2130 /* wo */ #define POR_DT_CLAIM 0x2da0 /* rw */ #define POR_DT_DEVAFF 0x2da8 /* ro */ #define POR_DT_LSR 0x2db0 /* ro */ #define POR_DT_AUTHSTATUS_DEVARCH 0x2db8 /* ro */ #define POR_DT_DEVID 0x2dc0 /* ro */ #define POR_DT_DEVTYPE 0x2dc8 /* ro */ #define POR_DT_PIDR45 0x2dd0 /* ro */ #define POR_DT_PIDR67 0x2dd8 /* ro */ #define POR_DT_PIDR01 0x2de0 /* ro */ #define POR_DT_PIDR23 0x2de8 /* ro */ #define POR_DT_CIDR01 0x2df0 /* ro */ #define POR_DT_CIDR23 0x2df8 /* ro */ /* HN-F registers */ #define POR_HNF_NODE_INFO 0x0000 /* ro */ #define POR_HNF_CHILD_INFO 0x0080 /* ro */ #define POR_HNF_SECURE_REGISTER_GROUPS_OVERRIDE 0x0980 /* rw */ #define POR_HNF_UNIT_INFO 0x0900 /* ro */ #define POR_HNF_CFG_CTL 0x0a00 /* rw */ #define POR_HNF_AUX_CTL 0x0a08 /* rw */ #define POR_HNF_R2_AUX_CTL 0x0a10 /* rw */ #define POR_HNF_PPU_PWPR 0x1000 /* rw */ #define POR_HNF_PPU_PWSR 0x1008 /* ro */ #define POR_HNF_PPU_MISR 0x1014 /* ro */ #define POR_HNF_PPU_IDR0 0x1fb0 /* ro */ #define POR_HNF_PPU_IDR1 0x1fb4 /* ro */ #define POR_HNF_PPU_IIDR 0x1fc8 /* ro */ #define POR_HNF_PPU_AIDR 0x1fcc /* ro */ #define POR_HNF_PPU_DYN_RET_THRESHOLD 0x1100 /* rw */ #define POR_HNF_QOS_BAND 0x0a80 /* ro */ #define POR_HNF_QOS_RESERVATION 0x0a88 /* rw */ #define POR_HNF_RN_STARVATION 0x0a90 /* rw */ #define POR_HNF_ERRFR 0x3000 /* ro */ #define POR_HNF_ERRCTLR 0x3008 /* rw */ #define POR_HNF_ERRSTATUS 0x3010 /* w1c */ #define POR_HNF_ERRADDR 0x3018 /* rw */ #define POR_HNF_ERRMISC 0x3020 /* rw */ #define POR_HNF_ERR_INJ 0x3030 /* rw */ #define POR_HNF_BYTE_PAR_ERR_INJ 0x3038 /* wo */ #define POR_HNF_ERRFR_NS 0x3100 /* ro */ #define POR_HNF_ERRCTLR_NS 0x3108 /* rw */ #define POR_HNF_ERRSTATUS_NS 0x3110 /* w1c */ #define POR_HNF_ERRADDR_NS 0x3118 /* rw */ #define POR_HNF_ERRMISC_NS 0x3120 /* rw */ #define POR_HNF_SLC_LOCK_WAYS 0x0c00 /* rw */ #define POR_HNF_SLC_LOCK_BASE0 0x0c08 /* rw */ #define POR_HNF_SLC_LOCK_BASE1 0x0c10 /* rw */ #define POR_HNF_SLC_LOCK_BASE2 0x0c18 /* rw */ #define POR_HNF_SLC_LOCK_BASE3 0x0c20 /* rw */ #define POR_HNF_RNF_REGION_VEC1 0x0c28 /* rw */ #define POR_HNF_RNI_REGION_VEC 0x0c30 /* rw */ #define POR_HNF_RNF_REGION_VEC 0x0c38 /* rw */ #define POR_HNF_RND_REGION_VEC 0x0c40 /* rw */ #define POR_HNF_SLCWAY_PARTITION0_RNF_VEC 0x0c48 /* rw */ #define POR_HNF_SLCWAY_PARTITION1_RNF_VEC 0x0c50 /* rw */ #define POR_HNF_SLCWAY_PARTITION2_RNF_VEC 0x0c58 /* rw */ #define POR_HNF_SLCWAY_PARTITION3_RNF_VEC 0x0c60 /* rw */ #define POR_HNF_SLCWAY_PARTITION0_RNF_VEC1 0x0cb0 /* rw */ #define POR_HNF_SLCWAY_PARTITION1_RNF_VEC1 0x0cb8 /* rw */ #define POR_HNF_SLCWAY_PARTITION2_RNF_VEC1 0x0cc0 /* rw */ #define POR_HNF_SLCWAY_PARTITION3_RNF_VEC1 0x0cc8 /* rw */ #define POR_HNF_SLCWAY_PARTITION0_RNI_VEC 0x0c68 /* rw */ #define POR_HNF_SLCWAY_PARTITION1_RNI_VEC 0x0c70 /* rw */ #define POR_HNF_SLCWAY_PARTITION2_RNI_VEC 0x0c78 /* rw */ #define POR_HNF_SLCWAY_PARTITION3_RNI_VEC 0x0c80 /* rw */ #define POR_HNF_SLCWAY_PARTITION0_RND_VEC 0x0c88 /* rw */ #define POR_HNF_SLCWAY_PARTITION1_RND_VEC 0x0c90 /* rw */ #define POR_HNF_SLCWAY_PARTITION2_RND_VEC 0x0c98 /* rw */ #define POR_HNF_SLCWAY_PARTITION3_RND_VEC 0x0ca0 /* rw */ #define POR_HNF_RN_REGION_LOCK 0x0ca8 /* rw */ #define POR_HNF_SAM_CONTROL 0x0d00 /* rw */ #define POR_HNF_SAM_MEMREGION0 0x0d08 /* rw */ #define POR_HNF_SAM_MEMREGION1 0x0d10 /* rw */ #define POR_HNF_SAM_SN_PROPERTIES 0x0d18 /* rw */ #define POR_HNF_SAM_6SN_NODEID 0x0d20 /* rw */ #define POR_HNF_RN_PHYS_ID(x) (0x0d28 + 8 * (x)) /* rw */ #define POR_HNF_RN_PHYS_ID63 0x0f90 /* rw */ #define POR_HNF_SF_CXG_BLOCKED_WAYS 0x0f00 /* rw */ #define POR_HNF_CML_PORT_AGGR_GRP0_ADD_MASK 0x0f10 /* rw */ #define POR_HNF_CML_PORT_AGGR_GRP1_ADD_MASK 0x0f18 /* rw */ #define POR_HNF_CML_PORT_AGGR_GRP0_REG 0x0f28 /* rw */ #define POR_HNF_CML_PORT_AGGR_GRP1_REG 0x0f30 /* rw */ #define HN_SAM_HASH_ADDR_MASK_REG 0x0f40 /* rw */ #define HN_SAM_REGION_CMP_ADDR_MASK_REG 0x0f48 /* rw */ #define POR_HNF_ABF_LO_ADDR 0x0f50 /* rw */ #define POR_HNF_ABF_HI_ADDR 0x0f58 /* rw */ #define POR_HNF_ABF_PR 0x0f60 /* rw */ #define POR_HNF_ABF_SR 0x0f68 /* ro */ #define POR_HNF_LDID_MAP_TABLE_REG0 0x0f98 /* rw */ #define POR_HNF_LDID_MAP_TABLE_REG1 0x0fa0 /* rw */ #define POR_HNF_LDID_MAP_TABLE_REG2 0x0fa8 /* rw */ #define POR_HNF_LDID_MAP_TABLE_REG3 0x0fb0 /* rw */ #define POR_HNF_CFG_SLCSF_DBGRD 0x0b80 /* wo */ #define POR_HNF_SLC_CACHE_ACCESS_SLC_TAG 0x0b88 /* ro */ #define POR_HNF_SLC_CACHE_ACCESS_SLC_DATA 0x0b90 /* ro */ #define POR_HNF_SLC_CACHE_ACCESS_SF_TAG 0x0b98 /* ro */ #define POR_HNF_SLC_CACHE_ACCESS_SF_TAG1 0x0ba0 /* ro */ #define POR_HNF_SLC_CACHE_ACCESS_SF_TAG2 0x0ba8 /* ro */ #define POR_HNF_PMU_EVENT_SEL 0x2000 /* rw */ /* HN-I registers */ #define POR_HNI_NODE_INFO 0x0000 /* ro */ #define POR_HNI_CHILD_INFO 0x0080 /* ro */ #define POR_HNI_SECURE_REGISTER_GROUPS_OVERRIDE 0x0980 /* rw */ #define POR_HNI_UNIT_INFO 0x0900 /* ro */ #define POR_HNI_SAM_ADDRREGION0_CFG 0x0c00 /* rw */ #define POR_HNI_SAM_ADDRREGION1_CFG 0x0c08 /* rw */ #define POR_HNI_SAM_ADDRREGION2_CFG 0x0c10 /* rw */ #define POR_HNI_SAM_ADDRREGION3_CFG 0x0c18 /* rw */ #define POR_HNI_CFG_CTL 0x0a00 /* rw */ #define POR_HNI_AUX_CTL 0x0a08 /* rw */ #define POR_HNI_ERRFR 0x3000 /* ro */ #define POR_HNI_ERRCTLR 0x3008 /* rw */ #define POR_HNI_ERRSTATUS 0x3010 /* w1c */ #define POR_HNI_ERRADDR 0x3018 /* rw */ #define POR_HNI_ERRMISC 0x3020 /* rw */ #define POR_HNI_ERRFR_NS 0x3100 /* ro */ #define POR_HNI_ERRCTLR_NS 0x3108 /* rw */ #define POR_HNI_ERRSTATUS_NS 0x3110 /* w1c */ #define POR_HNI_ERRADDR_NS 0x3118 /* rw */ #define POR_HNI_ERRMISC_NS 0x3120 /* rw */ #define POR_HNI_PMU_EVENT_SEL 0x2000 /* rw */ /* XP registers */ #define POR_MXP_NODE_INFO 0x0000 /* ro */ #define POR_MXP_DEVICE_PORT_CONNECT_INFO_P0 0x0008 /* ro */ #define POR_MXP_DEVICE_PORT_CONNECT_INFO_P1 0x0010 /* ro */ #define POR_MXP_MESH_PORT_CONNECT_INFO_EAST 0x0018 /* ro */ #define POR_MXP_MESH_PORT_CONNECT_INFO_NORTH 0x0020 /* ro */ #define POR_MXP_CHILD_INFO 0x0080 /* ro */ #define POR_MXP_CHILD_POINTER_0 0x0100 /* ro */ #define POR_MXP_CHILD_POINTER_1 0x0108 /* ro */ #define POR_MXP_CHILD_POINTER_2 0x0110 /* ro */ #define POR_MXP_CHILD_POINTER_3 0x0118 /* ro */ #define POR_MXP_CHILD_POINTER_4 0x0120 /* ro */ #define POR_MXP_CHILD_POINTER_5 0x0128 /* ro */ #define POR_MXP_CHILD_POINTER_6 0x0130 /* ro */ #define POR_MXP_CHILD_POINTER_7 0x0138 /* ro */ #define POR_MXP_CHILD_POINTER_8 0x0140 /* ro */ #define POR_MXP_CHILD_POINTER_9 0x0148 /* ro */ #define POR_MXP_CHILD_POINTER_10 0x0150 /* ro */ #define POR_MXP_CHILD_POINTER_11 0x0158 /* ro */ #define POR_MXP_CHILD_POINTER_12 0x0160 /* ro */ #define POR_MXP_CHILD_POINTER_13 0x0168 /* ro */ #define POR_MXP_CHILD_POINTER_14 0x0170 /* ro */ #define POR_MXP_CHILD_POINTER_15 0x0178 /* ro */ #define POR_MXP_P0_INFO 0x0900 /* ro */ #define POR_MXP_P1_INFO 0x0908 /* ro */ #define POR_MXP_PX_INFO_DEV_TYPE_RN_I 0x01 #define POR_MXP_PX_INFO_DEV_TYPE_RN_D 0x02 #define POR_MXP_PX_INFO_DEV_TYPE_RN_F_CHIB 0x04 #define POR_MXP_PX_INFO_DEV_TYPE_RN_F_CHIB_ESAM 0x05 #define POR_MXP_PX_INFO_DEV_TYPE_RN_F_CHIA 0x06 #define POR_MXP_PX_INFO_DEV_TYPE_RN_F_CHIA_ESAM 0x07 #define POR_MXP_PX_INFO_DEV_TYPE_HN_T 0x08 #define POR_MXP_PX_INFO_DEV_TYPE_HN_I 0x09 #define POR_MXP_PX_INFO_DEV_TYPE_HN_D 0x0a #define POR_MXP_PX_INFO_DEV_TYPE_SN_F 0x0c #define POR_MXP_PX_INFO_DEV_TYPE_SBSX 0x0d #define POR_MXP_PX_INFO_DEV_TYPE_HN_F 0x0e #define POR_MXP_PX_INFO_DEV_TYPE_CXHA 0x11 #define POR_MXP_PX_INFO_DEV_TYPE_CXRA 0x12 #define POR_MXP_PX_INFO_DEV_TYPE_CXRH 0x13 #define POR_MXP_SECURE_REGISTER_GROUPS_OVERRIDE 0x0980 /* rw */ #define POR_MXP_AUX_CTL 0x0a00 /* rw */ #define POR_MXP_P0_QOS_CONTROL 0x0a80 /* rw */ #define POR_MXP_P0_QOS_LAT_TGT 0x0a88 /* rw */ #define POR_MXP_P0_QOS_LAT_SCALE 0x0a90 /* rw */ #define POR_MXP_P0_QOS_LAT_RANGE 0x0a98 /* rw */ #define POR_MXP_P1_QOS_CONTROL 0x0aa0 /* rw */ #define POR_MXP_P1_QOS_LAT_TGT 0x0aa8 /* rw */ #define POR_MXP_P1_QOS_LAT_SCALE 0x0ab0 /* rw */ #define POR_MXP_P1_QOS_LAT_RANGE 0x0ab8 /* rw */ #define POR_MXP_PMU_EVENT_SEL 0x2000 /* rw */ #define POR_MXP_ERRFR 0x3000 /* ro */ #define POR_MXP_ERRCTLR 0x3008 /* rw */ #define POR_MXP_ERRSTATUS 0x3010 /* w1c */ #define POR_MXP_ERRMISC 0x3028 /* rw */ #define POR_MXP_P0_BYTE_PAR_ERR_INJ 0x3030 /* wo */ #define POR_MXP_P1_BYTE_PAR_ERR_INJ 0x3038 /* wo */ #define POR_MXP_ERRFR_NS 0x3100 /* ro */ #define POR_MXP_ERRCTLR_NS 0x3108 /* rw */ #define POR_MXP_ERRSTATUS_NS 0x3110 /* w1c */ #define POR_MXP_ERRMISC_NS 0x3128 /* rw */ #define POR_MXP_P0_SYSCOREQ_CTL 0x1000 /* rw */ #define POR_MXP_P1_SYSCOREQ_CTL 0x1008 /* rw */ #define POR_MXP_P0_SYSCOACK_STATUS 0x1010 /* ro */ #define POR_MXP_P1_SYSCOACK_STATUS 0x1018 /* ro */ #define POR_DTM_CONTROL 0x2100 /* rw */ #define POR_DTM_CONTROL_TRACE_NO_ATB (1 << 3) #define POR_DTM_CONTROL_SAMPLE_PROFILE_ENABLE (1 << 2) #define POR_DTM_CONTROL_TRACE_TAG_ENABLE (1 << 1) #define POR_DTM_CONTROL_DTM_ENABLE (1 << 0) #define POR_DTM_FIFO_ENTRY_READY 0x2118 /* w1c */ #define POR_DTM_FIFO_ENTRY0_0 0x2120 /* ro */ #define POR_DTM_FIFO_ENTRY0_1 0x2128 /* ro */ #define POR_DTM_FIFO_ENTRY0_2 0x2130 /* ro */ #define POR_DTM_FIFO_ENTRY1_0 0x2138 /* ro */ #define POR_DTM_FIFO_ENTRY1_1 0x2140 /* ro */ #define POR_DTM_FIFO_ENTRY1_2 0x2148 /* ro */ #define POR_DTM_FIFO_ENTRY2_0 0x2150 /* ro */ #define POR_DTM_FIFO_ENTRY2_1 0x2158 /* ro */ #define POR_DTM_FIFO_ENTRY2_2 0x2160 /* ro */ #define POR_DTM_FIFO_ENTRY3_0 0x2168 /* ro */ #define POR_DTM_FIFO_ENTRY3_1 0x2170 /* ro */ #define POR_DTM_FIFO_ENTRY3_2 0x2178 /* ro */ #define POR_DTM_WP0_CONFIG 0x21a0 /* rw */ #define POR_DTM_WP0_VAL 0x21a8 /* rw */ #define POR_DTM_WP0_MASK 0x21b0 /* rw */ #define POR_DTM_WP1_CONFIG 0x21b8 /* rw */ #define POR_DTM_WP1_VAL 0x21c0 /* rw */ #define POR_DTM_WP1_MASK 0x21c8 /* rw */ #define POR_DTM_WP2_CONFIG 0x21d0 /* rw */ #define POR_DTM_WP2_VAL 0x21d8 /* rw */ #define POR_DTM_WP2_MASK 0x21e0 /* rw */ #define POR_DTM_WP3_CONFIG 0x21e8 /* rw */ #define POR_DTM_WP3_VAL 0x21f0 /* rw */ #define POR_DTM_WP3_MASK 0x21f8 /* rw */ #define POR_DTM_PMSICR 0x2200 /* rw */ #define POR_DTM_PMSIRR 0x2208 /* rw */ #define POR_DTM_PMU_CONFIG 0x2210 /* rw */ #define POR_DTM_PMU_CONFIG_PMU_EN (1 << 0) #define POR_DTM_PMU_CONFIG_VCNT_INPUT_SEL_SHIFT 32 #define POR_DTM_PMU_CONFIG_VCNT_INPUT_SEL_WIDTH 8 #define POR_DTM_PMEVCNT 0x2220 /* rw */ +#define POR_DTM_PMEVCNT_CNTR_WIDTH 16 #define POR_DTM_PMEVCNTSR 0x2240 /* rw */ /* RN-D registers */ #define POR_RND_NODE_INFO 0x0000 /* ro */ #define POR_RND_CHILD_INFO 0x0080 /* ro */ #define POR_RND_SECURE_REGISTER_GROUPS_OVERRIDE 0x0980 /* rw */ #define POR_RND_UNIT_INFO 0x0900 /* ro */ #define POR_RND_CFG_CTL 0x0a00 /* rw */ #define POR_RND_AUX_CTL 0x0a08 /* rw */ #define POR_RND_S0_PORT_CONTROL 0x0a10 /* rw */ #define POR_RND_S1_PORT_CONTROL 0x0a18 /* rw */ #define POR_RND_S2_PORT_CONTROL 0x0a20 /* rw */ #define POR_RND_S0_QOS_CONTROL 0x0a80 /* rw */ #define POR_RND_S0_QOS_LAT_TGT 0x0a88 /* rw */ #define POR_RND_S0_QOS_LAT_SCALE 0x0a90 /* rw */ #define POR_RND_S0_QOS_LAT_RANGE 0x0a98 /* rw */ #define POR_RND_S1_QOS_CONTROL 0x0aa0 /* rw */ #define POR_RND_S1_QOS_LAT_TGT 0x0aa8 /* rw */ #define POR_RND_S1_QOS_LAT_SCALE 0x0ab0 /* rw */ #define POR_RND_S1_QOS_LAT_RANGE 0x0ab8 /* rw */ #define POR_RND_S2_QOS_CONTROL 0x0ac0 /* rw */ #define POR_RND_S2_QOS_LAT_TGT 0x0ac8 /* rw */ #define POR_RND_S2_QOS_LAT_SCALE 0x0ad0 /* rw */ #define POR_RND_S2_QOS_LAT_RANGE 0x0ad8 /* rw */ #define POR_RND_PMU_EVENT_SEL 0x2000 /* rw */ #define POR_RND_SYSCOREQ_CTL 0x1000 /* rw */ #define POR_RND_SYSCOACK_STATUS 0x1008 /* ro */ /* RN-I registers */ #define POR_RNI_NODE_INFO 0x0000 /* ro */ #define POR_RNI_CHILD_INFO 0x0080 /* ro */ #define POR_RNI_SECURE_REGISTER_GROUPS_OVERRIDE 0x0980 /* rw */ #define POR_RNI_UNIT_INFO 0x0900 /* ro */ #define POR_RNI_CFG_CTL 0x0a00 /* rw */ #define POR_RNI_AUX_CTL 0x0a08 /* rw */ #define POR_RNI_S0_PORT_CONTROL 0x0a10 /* rw */ #define POR_RNI_S1_PORT_CONTROL 0x0a18 /* rw */ #define POR_RNI_S2_PORT_CONTROL 0x0a20 /* rw */ #define POR_RNI_S0_QOS_CONTROL 0x0a80 /* rw */ #define POR_RNI_S0_QOS_LAT_TGT 0x0a88 /* rw */ #define POR_RNI_S0_QOS_LAT_SCALE 0x0a90 /* rw */ #define POR_RNI_S0_QOS_LAT_RANGE 0x0a98 /* rw */ #define POR_RNI_S1_QOS_CONTROL 0x0aa0 /* rw */ #define POR_RNI_S1_QOS_LAT_TGT 0x0aa8 /* rw */ #define POR_RNI_S1_QOS_LAT_SCALE 0x0ab0 /* rw */ #define POR_RNI_S1_QOS_LAT_RANGE 0x0ab8 /* rw */ #define POR_RNI_S2_QOS_CONTROL 0x0ac0 /* rw */ #define POR_RNI_S2_QOS_LAT_TGT 0x0ac8 /* rw */ #define POR_RNI_S2_QOS_LAT_SCALE 0x0ad0 /* rw */ #define POR_RNI_S2_QOS_LAT_RANGE 0x0ad8 /* rw */ #define POR_RNI_PMU_EVENT_SEL 0x2000 /* rw */ /* RN SAM registers */ #define POR_RNSAM_NODE_INFO 0x0000 /* ro */ #define POR_RNSAM_CHILD_INFO 0x0080 /* ro */ #define POR_RNSAM_SECURE_REGISTER_GROUPS_OVERRIDE 0x0980 /* rw */ #define POR_RNSAM_UNIT_INFO 0x0900 /* ro */ #define RNSAM_STATUS 0x0c00 /* rw */ #define NON_HASH_MEM_REGION_REG0 0x0c08 /* rw */ #define NON_HASH_MEM_REGION_REG1 0x0c10 /* rw */ #define NON_HASH_MEM_REGION_REG2 0x0c18 /* rw */ #define NON_HASH_MEM_REGION_REG3 0x0c20 /* rw */ #define NON_HASH_TGT_NODEID0 0x0c30 /* rw */ #define NON_HASH_TGT_NODEID1 0x0c38 /* rw */ #define NON_HASH_TGT_NODEID2 0x0c40 /* rw */ #define SYS_CACHE_GRP_REGION0 0x0c48 /* rw */ #define SYS_CACHE_GRP_REGION1 0x0c50 /* rw */ #define SYS_CACHE_GRP_HN_NODEID_REG0 0x0c58 /* rw */ #define SYS_CACHE_GRP_HN_NODEID_REG1 0x0c60 /* rw */ #define SYS_CACHE_GRP_HN_NODEID_REG2 0x0c68 /* rw */ #define SYS_CACHE_GRP_HN_NODEID_REG3 0x0c70 /* rw */ #define SYS_CACHE_GRP_HN_NODEID_REG4 0x0c78 /* rw */ #define SYS_CACHE_GRP_HN_NODEID_REG5 0x0c80 /* rw */ #define SYS_CACHE_GRP_HN_NODEID_REG6 0x0c88 /* rw */ #define SYS_CACHE_GRP_HN_NODEID_REG7 0x0c90 /* rw */ #define SYS_CACHE_GRP_NONHASH_NODEID 0x0c98 /* rw */ #define SYS_CACHE_GROUP_HN_COUNT 0x0d00 /* rw */ #define SYS_CACHE_GRP_SN_NODEID_REG0 0x0d08 /* rw */ #define SYS_CACHE_GRP_SN_NODEID_REG1 0x0d10 /* rw */ #define SYS_CACHE_GRP_SN_NODEID_REG2 0x0d18 /* rw */ #define SYS_CACHE_GRP_SN_NODEID_REG3 0x0d20 /* rw */ #define SYS_CACHE_GRP_SN_NODEID_REG4 0x0d28 /* rw */ #define SYS_CACHE_GRP_SN_NODEID_REG5 0x0d30 /* rw */ #define SYS_CACHE_GRP_SN_NODEID_REG6 0x0d38 /* rw */ #define SYS_CACHE_GRP_SN_NODEID_REG7 0x0d40 /* rw */ #define SYS_CACHE_GRP_SN_SAM_CFG0 0x0d48 /* rw */ #define SYS_CACHE_GRP_SN_SAM_CFG1 0x0d50 /* rw */ #define GIC_MEM_REGION_REG 0x0d58 /* rw */ #define SYS_CACHE_GRP_SN_ATTR 0x0d60 /* rw */ #define SYS_CACHE_GRP_HN_CPA_EN_REG 0x0d68 /* rw */ #define SYS_CACHE_GRP_HN_CPA_GRP_REG 0x0d70 /* rw */ #define CML_PORT_AGGR_MODE_CTRL_REG 0x0e00 /* rw */ #define CML_PORT_AGGR_GRP0_ADD_MASK 0x0e08 /* rw */ #define CML_PORT_AGGR_GRP1_ADD_MASK 0x0e10 /* rw */ #define CML_PORT_AGGR_GRP0_REG 0x0e40 /* rw */ #define CML_PORT_AGGR_GRP1_REG 0x0e48 /* rw */ #define SYS_CACHE_GRP_SECONDARY_REG0 0x0f00 /* rw */ #define SYS_CACHE_GRP_SECONDARY_REG1 0x0f08 /* rw */ #define SYS_CACHE_GRP_CAL_MODE_REG 0x0f10 /* rw */ #define RNSAM_HASH_ADDR_MASK_REG 0x0f18 /* rw */ #define RNSAM_REGION_CMP_ADDR_MASK_REG 0x0f20 /* rw */ #define SYS_CACHE_GRP_HN_NODEID_REG8 0x0f58 /* rw */ #define SYS_CACHE_GRP_HN_NODEID_REG9 0x0f60 /* rw */ #define SYS_CACHE_GRP_HN_NODEID_REG10 0x0f68 /* rw */ #define SYS_CACHE_GRP_HN_NODEID_REG11 0x0f70 /* rw */ #define SYS_CACHE_GRP_HN_NODEID_REG12 0x0f78 /* rw */ #define SYS_CACHE_GRP_HN_NODEID_REG13 0x0f80 /* rw */ #define SYS_CACHE_GRP_HN_NODEID_REG14 0x0f88 /* rw */ #define SYS_CACHE_GRP_HN_NODEID_REG15 0x0f90 /* rw */ #define SYS_CACHE_GRP_SN_NODEID_REG8 0x1008 /* rw */ #define SYS_CACHE_GRP_SN_NODEID_REG9 0x1010 /* rw */ #define SYS_CACHE_GRP_SN_NODEID_REG10 0x1018 /* rw */ #define SYS_CACHE_GRP_SN_NODEID_REG11 0x1020 /* rw */ #define SYS_CACHE_GRP_SN_NODEID_REG12 0x1028 /* rw */ #define SYS_CACHE_GRP_SN_NODEID_REG13 0x1030 /* rw */ #define SYS_CACHE_GRP_SN_NODEID_REG14 0x1038 /* rw */ #define SYS_CACHE_GRP_SN_NODEID_REG15 0x1040 /* rw */ /* SBSX registers */ #define POR_SBSX_NODE_INFO 0x0000 /* ro */ #define POR_SBSX_CHILD_INFO 0x0080 /* ro */ #define POR_SBSX_UNIT_INFO 0x0900 /* ro */ #define POR_SBSX_AUX_CTL 0x0a08 /* rw */ #define POR_SBSX_ERRFR 0x3000 /* ro */ #define POR_SBSX_ERRCTLR 0x3008 /* rw */ #define POR_SBSX_ERRSTATUS 0x3010 /* w1c */ #define POR_SBSX_ERRADDR 0x3018 /* rw */ #define POR_SBSX_ERRMISC 0x3020 /* rw */ #define POR_SBSX_ERRFR_NS 0x3100 /* ro */ #define POR_SBSX_ERRCTLR_NS 0x3108 /* rw */ #define POR_SBSX_ERRSTATUS_NS 0x3110 /* w1c */ #define POR_SBSX_ERRADDR_NS 0x3118 /* rw */ #define POR_SBSX_ERRMISC_NS 0x3120 /* rw */ #define POR_SBSX_PMU_EVENT_SEL 0x2000 /* rw */ /* CXHA registers */ #define POR_CXG_HA_NODE_INFO 0x0000 /* ro */ #define POR_CXG_HA_ID 0x0008 /* rw */ #define POR_CXG_HA_CHILD_INFO 0x0080 /* ro */ #define POR_CXG_HA_AUX_CTL 0x0a08 /* rw */ #define POR_CXG_HA_SECURE_REGISTER_GROUPS_OVERRIDE 0x0980 /* rw */ #define POR_CXG_HA_UNIT_INFO 0x0900 /* ro */ #define POR_CXG_HA_RNF_RAID_TO_LDID_REG0 0x0c00 /* rw */ #define POR_CXG_HA_RNF_RAID_TO_LDID_REG1 0x0c08 /* rw */ #define POR_CXG_HA_RNF_RAID_TO_LDID_REG2 0x0c10 /* rw */ #define POR_CXG_HA_RNF_RAID_TO_LDID_REG3 0x0c18 /* rw */ #define POR_CXG_HA_RNF_RAID_TO_LDID_REG4 0x0c20 /* rw */ #define POR_CXG_HA_RNF_RAID_TO_LDID_REG5 0x0c28 /* rw */ #define POR_CXG_HA_RNF_RAID_TO_LDID_REG6 0x0c30 /* rw */ #define POR_CXG_HA_RNF_RAID_TO_LDID_REG7 0x0c38 /* rw */ #define POR_CXG_HA_AGENTID_TO_LINKID_REG0 0x0c40 /* rw */ #define POR_CXG_HA_AGENTID_TO_LINKID_REG1 0x0c48 /* rw */ #define POR_CXG_HA_AGENTID_TO_LINKID_REG2 0x0c50 /* rw */ #define POR_CXG_HA_AGENTID_TO_LINKID_REG3 0x0c58 /* rw */ #define POR_CXG_HA_AGENTID_TO_LINKID_REG4 0x0c60 /* rw */ #define POR_CXG_HA_AGENTID_TO_LINKID_REG5 0x0c68 /* rw */ #define POR_CXG_HA_AGENTID_TO_LINKID_REG6 0x0c70 /* rw */ #define POR_CXG_HA_AGENTID_TO_LINKID_REG7 0x0c78 /* rw */ #define POR_CXG_HA_AGENTID_TO_LINKID_VAL 0x0d00 /* rw */ #define POR_CXG_HA_RNF_RAID_TO_LDID_VAL 0x0d08 /* rw */ #define POR_CXG_HA_PMU_EVENT_SEL 0x2000 /* rw */ #define POR_CXG_HA_PMU_EVENT_SEL_EVENT_ID3_SHIFT 24 #define POR_CXG_HA_PMU_EVENT_SEL_EVENT_ID3_MASK (0x3f << 24) #define POR_CXG_HA_PMU_EVENT_SEL_EVENT_ID2_SHIFT 16 #define POR_CXG_HA_PMU_EVENT_SEL_EVENT_ID2_MASK (0x3f << 16) #define POR_CXG_HA_PMU_EVENT_SEL_EVENT_ID1_SHIFT 8 #define POR_CXG_HA_PMU_EVENT_SEL_EVENT_ID1_MASK (0x3f << 8) #define POR_CXG_HA_PMU_EVENT_SEL_EVENT_ID0_SHIFT 0 #define POR_CXG_HA_PMU_EVENT_SEL_EVENT_ID0_MASK 0x3f #define POR_CXG_HA_CXPRTCL_LINK0_CTL 0x1000 /* rw */ #define POR_CXG_HA_CXPRTCL_LINK0_STATUS 0x1008 /* ro */ #define POR_CXG_HA_CXPRTCL_LINK1_CTL 0x1010 /* rw */ #define POR_CXG_HA_CXPRTCL_LINK1_STATUS 0x1018 /* ro */ #define POR_CXG_HA_CXPRTCL_LINK2_CTL 0x1020 /* rw */ #define POR_CXG_HA_CXPRTCL_LINK2_STATUS 0x1028 /* ro */ #define POR_CXG_HA_ERRFR 0x3000 /* ro */ #define POR_CXG_HA_ERRCTLR 0x3008 /* rw */ #define POR_CXG_HA_ERRSTATUS 0x3010 /* w1c */ #define POR_CXG_HA_ERRADDR 0x3018 /* rw */ #define POR_CXG_HA_ERRMISC 0x3020 /* rw */ #define POR_CXG_HA_ERRFR_NS 0x3100 /* ro */ #define POR_CXG_HA_ERRCTLR_NS 0x3108 /* rw */ #define POR_CXG_HA_ERRSTATUS_NS 0x3110 /* w1c */ #define POR_CXG_HA_ERRADDR_NS 0x3118 /* rw */ #define POR_CXG_HA_ERRMISC_NS 0x3120 /* rw */ /* CXRA registers */ #define POR_CXG_RA_NODE_INFO 0x0000 /* ro */ #define POR_CXG_RA_CHILD_INFO 0x0080 /* ro */ #define POR_CXG_RA_SECURE_REGISTER_GROUPS_OVERRIDE 0x0980 /* rw */ #define POR_CXG_RA_UNIT_INFO 0x0900 /* ro */ #define POR_CXG_RA_CFG_CTL 0x0a00 /* rw */ #define EN_CXLA_PMUCMD_PROP (1 << 8) #define POR_CXG_RA_AUX_CTL 0x0a08 /* rw */ #define POR_CXG_RA_SAM_ADDR_REGION_REG0 0x0da8 /* rw */ #define POR_CXG_RA_SAM_ADDR_REGION_REG1 0x0db0 /* rw */ #define POR_CXG_RA_SAM_ADDR_REGION_REG2 0x0db8 /* rw */ #define POR_CXG_RA_SAM_ADDR_REGION_REG3 0x0dc0 /* rw */ #define POR_CXG_RA_SAM_ADDR_REGION_REG4 0x0dc8 /* rw */ #define POR_CXG_RA_SAM_ADDR_REGION_REG5 0x0dd0 /* rw */ #define POR_CXG_RA_SAM_ADDR_REGION_REG6 0x0dd8 /* rw */ #define POR_CXG_RA_SAM_ADDR_REGION_REG7 0x0de0 /* rw */ #define POR_CXG_RA_SAM_MEM_REGION0_LIMIT_REG 0x0e00 /* rw */ #define POR_CXG_RA_SAM_MEM_REGION1_LIMIT_REG 0x0e08 /* rw */ #define POR_CXG_RA_SAM_MEM_REGION2_LIMIT_REG 0x0e10 /* rw */ #define POR_CXG_RA_SAM_MEM_REGION3_LIMIT_REG 0x0e18 /* rw */ #define POR_CXG_RA_SAM_MEM_REGION4_LIMIT_REG 0x0e20 /* rw */ #define POR_CXG_RA_SAM_MEM_REGION5_LIMIT_REG 0x0e28 /* rw */ #define POR_CXG_RA_SAM_MEM_REGION6_LIMIT_REG 0x0e30 /* rw */ #define POR_CXG_RA_SAM_MEM_REGION7_LIMIT_REG 0x0e38 /* rw */ #define POR_CXG_RA_AGENTID_TO_LINKID_REG0 0x0e60 /* rw */ #define POR_CXG_RA_AGENTID_TO_LINKID_REG1 0x0e68 /* rw */ #define POR_CXG_RA_AGENTID_TO_LINKID_REG2 0x0e70 /* rw */ #define POR_CXG_RA_AGENTID_TO_LINKID_REG3 0x0e78 /* rw */ #define POR_CXG_RA_AGENTID_TO_LINKID_REG4 0x0e80 /* rw */ #define POR_CXG_RA_AGENTID_TO_LINKID_REG5 0x0e88 /* rw */ #define POR_CXG_RA_AGENTID_TO_LINKID_REG6 0x0e90 /* rw */ #define POR_CXG_RA_AGENTID_TO_LINKID_REG7 0x0e98 /* rw */ #define POR_CXG_RA_RNF_LDID_TO_RAID_REG0 0x0ea0 /* rw */ #define POR_CXG_RA_RNF_LDID_TO_RAID_REG1 0x0ea8 /* rw */ #define POR_CXG_RA_RNF_LDID_TO_RAID_REG2 0x0eb0 /* rw */ #define POR_CXG_RA_RNF_LDID_TO_RAID_REG3 0x0eb8 /* rw */ #define POR_CXG_RA_RNF_LDID_TO_RAID_REG4 0x0ec0 /* rw */ #define POR_CXG_RA_RNF_LDID_TO_RAID_REG5 0x0ec8 /* rw */ #define POR_CXG_RA_RNF_LDID_TO_RAID_REG6 0x0ed0 /* rw */ #define POR_CXG_RA_RNF_LDID_TO_RAID_REG7 0x0ed8 /* rw */ #define POR_CXG_RA_RNI_LDID_TO_RAID_REG0 0x0ee0 /* rw */ #define POR_CXG_RA_RNI_LDID_TO_RAID_REG1 0x0ee8 /* rw */ #define POR_CXG_RA_RNI_LDID_TO_RAID_REG2 0x0ef0 /* rw */ #define POR_CXG_RA_RNI_LDID_TO_RAID_REG3 0x0ef8 /* rw */ #define POR_CXG_RA_RND_LDID_TO_RAID_REG0 0x0f00 /* rw */ #define POR_CXG_RA_RND_LDID_TO_RAID_REG1 0x0f08 /* rw */ #define POR_CXG_RA_RND_LDID_TO_RAID_REG2 0x0f10 /* rw */ #define POR_CXG_RA_RND_LDID_TO_RAID_REG3 0x0f18 /* rw */ #define POR_CXG_RA_AGENTID_TO_LINKID_VAL 0x0f20 /* rw */ #define POR_CXG_RA_RNF_LDID_TO_RAID_VAL 0x0f28 /* rw */ #define POR_CXG_RA_RNI_LDID_TO_RAID_VAL 0x0f30 /* rw */ #define POR_CXG_RA_RND_LDID_TO_RAID_VAL 0x0f38 /* rw */ #define POR_CXG_RA_PMU_EVENT_SEL 0x2000 /* rw */ #define POR_CXG_RA_CXPRTCL_LINK0_CTL 0x1000 /* rw */ #define POR_CXG_RA_CXPRTCL_LINK0_STATUS 0x1008 /* ro */ #define POR_CXG_RA_CXPRTCL_LINK1_CTL 0x1010 /* rw */ #define POR_CXG_RA_CXPRTCL_LINK1_STATUS 0x1018 /* ro */ #define POR_CXG_RA_CXPRTCL_LINK2_CTL 0x1020 /* rw */ #define POR_CXG_RA_CXPRTCL_LINK2_STATUS 0x1028 /* ro */ /* CXLA registers */ #define POR_CXLA_NODE_INFO 0x0000 /* ro */ #define POR_CXLA_CHILD_INFO 0x0080 /* ro */ #define POR_CXLA_SECURE_REGISTER_GROUPS_OVERRIDE 0x0980 /* rw */ #define POR_CXLA_UNIT_INFO 0x0900 /* ro */ #define POR_CXLA_AUX_CTL 0x0a08 /* rw */ #define POR_CXLA_CCIX_PROP_CAPABILITIES 0x0c00 /* ro */ #define POR_CXLA_CCIX_PROP_CONFIGURED 0x0c08 /* rw */ #define POR_CXLA_TX_CXS_ATTR_CAPABILITIES 0x0c10 /* ro */ #define POR_CXLA_RX_CXS_ATTR_CAPABILITIES 0x0c18 /* ro */ #define POR_CXLA_AGENTID_TO_LINKID_REG0 0x0c30 /* rw */ #define POR_CXLA_AGENTID_TO_LINKID_REG1 0x0c38 /* rw */ #define POR_CXLA_AGENTID_TO_LINKID_REG2 0x0c40 /* rw */ #define POR_CXLA_AGENTID_TO_LINKID_REG3 0x0c48 /* rw */ #define POR_CXLA_AGENTID_TO_LINKID_REG4 0x0c50 /* rw */ #define POR_CXLA_AGENTID_TO_LINKID_REG5 0x0c58 /* rw */ #define POR_CXLA_AGENTID_TO_LINKID_REG6 0x0c60 /* rw */ #define POR_CXLA_AGENTID_TO_LINKID_REG7 0x0c68 /* rw */ #define POR_CXLA_AGENTID_TO_LINKID_VAL 0x0c70 /* rw */ #define POR_CXLA_LINKID_TO_PCIE_BUS_NUM 0x0c78 /* rw */ #define POR_CXLA_PERMSG_PYLD_0_63 0x0d00 /* rw */ #define POR_CXLA_PERMSG_PYLD_64_127 0x0d08 /* rw */ #define POR_CXLA_PERMSG_PYLD_128_191 0x0d10 /* rw */ #define POR_CXLA_PERMSG_PYLD_192_255 0x0d18 /* rw */ #define POR_CXLA_PERMSG_CTL 0x0d20 /* rw */ #define POR_CXLA_ERR_AGENT_ID 0x0d28 /* rw */ #define POR_CXLA_PMU_EVENT_SEL 0x2000 /* rw */ #define POR_CXLA_PMU_CONFIG 0x2210 /* rw */ #define POR_CXLA_PMEVCNT 0x2220 /* rw */ #define POR_CXLA_PMEVCNTSR 0x2240 /* rw */ #endif /* _MACHINE_CMN600_REG_H_ */ diff --git a/sys/dev/hwpmc/hwpmc_cmn600.c b/sys/dev/hwpmc/hwpmc_cmn600.c new file mode 100644 index 000000000000..b33dd2693b25 --- /dev/null +++ b/sys/dev/hwpmc/hwpmc_cmn600.c @@ -0,0 +1,830 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2003-2008 Joseph Koshy + * Copyright (c) 2007 The FreeBSD Foundation + * Copyright (c) 2021 ARM Ltd + * + * Portions of this software were developed by A. Joseph Koshy under + * sponsorship from the FreeBSD Foundation and Google, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* Arm CoreLink CMN-600 Coherent Mesh Network PMU Driver */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +struct cmn600_descr { + struct pmc_descr pd_descr; /* "base class" */ + void *pd_rw_arg; /* Argument to use with read/write */ + struct pmc *pd_pmc; + struct pmc_hw *pd_phw; + uint32_t pd_nodeid; + int32_t pd_node_type; + int pd_local_counter; + +}; + +static struct cmn600_descr **cmn600_pmcdesc; + +static struct cmn600_pmc cmn600_pmcs[CMN600_UNIT_MAX]; +static int cmn600_units = 0; + +static inline struct cmn600_descr * +cmn600desc(int ri) +{ + + return (cmn600_pmcdesc[ri]); +} + +static inline int +class_ri2unit(int ri) +{ + + return (ri / CMN600_COUNTERS_N); +} + +#define EVENCNTR(x) (((x) >> POR_DT_PMEVCNT_EVENCNT_SHIFT) << \ + POR_DTM_PMEVCNT_CNTR_WIDTH) +#define ODDCNTR(x) (((x) >> POR_DT_PMEVCNT_ODDCNT_SHIFT) << \ + POR_DTM_PMEVCNT_CNTR_WIDTH) + +static uint64_t +cmn600_pmu_readcntr(void *arg, u_int nodeid, u_int xpcntr, u_int dtccntr, + u_int width) +{ + uint64_t dtcval, xpval; + + KASSERT(xpcntr < 4, ("[cmn600,%d] XP counter number %d is too big." + " Max: 3", __LINE__, xpcntr)); + KASSERT(dtccntr < 8, ("[cmn600,%d] Global counter number %d is too" + " big. Max: 7", __LINE__, dtccntr)); + + dtcval = pmu_cmn600_rd8(arg, nodeid, NODE_TYPE_DTC, + POR_DT_PMEVCNT(dtccntr >> 1)); + if (width == 4) { + dtcval = (dtccntr & 1) ? ODDCNTR(dtcval) : EVENCNTR(dtcval); + dtcval &= 0xffffffff0000UL; + } else + dtcval <<= POR_DTM_PMEVCNT_CNTR_WIDTH; + + xpval = pmu_cmn600_rd8(arg, nodeid, NODE_TYPE_XP, POR_DTM_PMEVCNT); + xpval >>= xpcntr * POR_DTM_PMEVCNT_CNTR_WIDTH; + xpval &= 0xffffUL; + return (dtcval | xpval); +} + +static void +cmn600_pmu_writecntr(void *arg, u_int nodeid, u_int xpcntr, u_int dtccntr, + u_int width, uint64_t val) +{ + int shift; + + KASSERT(xpcntr < 4, ("[cmn600,%d] XP counter number %d is too big." + " Max: 3", __LINE__, xpcntr)); + KASSERT(dtccntr < 8, ("[cmn600,%d] Global counter number %d is too" + " big. Max: 7", __LINE__, dtccntr)); + + if (width == 4) { + shift = (dtccntr & 1) ? POR_DT_PMEVCNT_ODDCNT_SHIFT : + POR_DT_PMEVCNT_EVENCNT_SHIFT; + pmu_cmn600_md8(arg, nodeid, NODE_TYPE_DTC, + POR_DT_PMEVCNT(dtccntr >> 1), 0xffffffffUL << shift, + ((val >> POR_DTM_PMEVCNT_CNTR_WIDTH) & 0xffffffff) << shift); + } else + pmu_cmn600_wr8(arg, nodeid, NODE_TYPE_DTC, + POR_DT_PMEVCNT(dtccntr & ~0x1), val >> + POR_DTM_PMEVCNT_CNTR_WIDTH); + + shift = xpcntr * POR_DTM_PMEVCNT_CNTR_WIDTH; + val &= 0xffffUL; + pmu_cmn600_md8(arg, nodeid, NODE_TYPE_XP, POR_DTM_PMEVCNT, + 0xffffUL << shift, val << shift); +} + +#undef EVENCNTR +#undef ODDCNTR + +/* + * read a pmc register + */ +static int +cmn600_read_pmc(int cpu, int ri, pmc_value_t *v) +{ + int counter, local_counter, nodeid; + struct cmn600_descr *desc; + struct pmc *pm; + void *arg; + + KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), + ("[cmn600,%d] illegal CPU value %d", __LINE__, cpu)); + KASSERT(ri >= 0, ("[cmn600,%d] row-index %d out of range", __LINE__, + ri)); + + counter = ri % CMN600_COUNTERS_N; + desc = cmn600desc(ri); + pm = desc->pd_phw->phw_pmc; + arg = desc->pd_rw_arg; + nodeid = pm->pm_md.pm_cmn600.pm_cmn600_nodeid; + local_counter = pm->pm_md.pm_cmn600.pm_cmn600_local_counter; + + KASSERT(pm != NULL, + ("[cmn600,%d] No owner for HWPMC [cpu%d,pmc%d]", __LINE__, + cpu, ri)); + + *v = cmn600_pmu_readcntr(arg, nodeid, local_counter, counter, 4); + PMCDBG3(MDP, REA, 2, "%s id=%d -> %jd", __func__, ri, *v); + + return (0); +} + +/* + * Write a pmc register. + */ +static int +cmn600_write_pmc(int cpu, int ri, pmc_value_t v) +{ + int counter, local_counter, nodeid; + struct cmn600_descr *desc; + struct pmc *pm; + void *arg; + + KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), + ("[cmn600,%d] illegal CPU value %d", __LINE__, cpu)); + KASSERT(ri >= 0, ("[cmn600,%d] row-index %d out of range", __LINE__, + ri)); + + counter = ri % CMN600_COUNTERS_N; + desc = cmn600desc(ri); + pm = desc->pd_phw->phw_pmc; + arg = desc->pd_rw_arg; + nodeid = pm->pm_md.pm_cmn600.pm_cmn600_nodeid; + local_counter = pm->pm_md.pm_cmn600.pm_cmn600_local_counter; + + KASSERT(pm != NULL, + ("[cmn600,%d] PMC not owned (cpu%d,pmc%d)", __LINE__, + cpu, ri)); + + PMCDBG4(MDP, WRI, 1, "%s cpu=%d ri=%d v=%jx", __func__, cpu, ri, v); + + cmn600_pmu_writecntr(arg, nodeid, local_counter, counter, 4, v); + return (0); +} + +/* + * configure hardware pmc according to the configuration recorded in + * pmc 'pm'. + */ +static int +cmn600_config_pmc(int cpu, int ri, struct pmc *pm) +{ + struct pmc_hw *phw; + + PMCDBG4(MDP, CFG, 1, "%s cpu=%d ri=%d pm=%p", __func__, cpu, ri, pm); + + KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), + ("[cmn600,%d] illegal CPU value %d", __LINE__, cpu)); + KASSERT(ri >= 0, ("[cmn600,%d] row-index %d out of range", __LINE__, + ri)); + + phw = cmn600desc(ri)->pd_phw; + + KASSERT(pm == NULL || phw->phw_pmc == NULL, + ("[cmn600,%d] pm=%p phw->pm=%p hwpmc not unconfigured", + __LINE__, pm, phw->phw_pmc)); + + phw->phw_pmc = pm; + return (0); +} + +/* + * Retrieve a configured PMC pointer from hardware state. + */ +static int +cmn600_get_config(int cpu, int ri, struct pmc **ppm) +{ + + *ppm = cmn600desc(ri)->pd_phw->phw_pmc; + + return (0); +} + +#define CASE_DN_VER_EVT(n, id) case PMC_EV_CMN600_PMU_ ## n: { *event = id; \ + return (0); } +static int +cmn600_map_ev2event(int ev, int rev, int *node_type, uint8_t *event) +{ + if (ev < PMC_EV_CMN600_PMU_dn_rxreq_dvmop || + ev > PMC_EV_CMN600_PMU_rni_rdb_ord) + return (EINVAL); + if (ev <= PMC_EV_CMN600_PMU_dn_rxreq_trk_full) { + *node_type = NODE_TYPE_DVM; + if (rev < 0x200) { + switch (ev) { + CASE_DN_VER_EVT(dn_rxreq_dvmop, 1); + CASE_DN_VER_EVT(dn_rxreq_dvmsync, 2); + CASE_DN_VER_EVT(dn_rxreq_dvmop_vmid_filtered, 3); + CASE_DN_VER_EVT(dn_rxreq_retried, 4); + CASE_DN_VER_EVT(dn_rxreq_trk_occupancy, 5); + } + } else { + switch (ev) { + CASE_DN_VER_EVT(dn_rxreq_tlbi_dvmop, 0x01); + CASE_DN_VER_EVT(dn_rxreq_bpi_dvmop, 0x02); + CASE_DN_VER_EVT(dn_rxreq_pici_dvmop, 0x03); + CASE_DN_VER_EVT(dn_rxreq_vivi_dvmop, 0x04); + CASE_DN_VER_EVT(dn_rxreq_dvmsync, 0x05); + CASE_DN_VER_EVT(dn_rxreq_dvmop_vmid_filtered, 0x06); + CASE_DN_VER_EVT(dn_rxreq_dvmop_other_filtered, 0x07); + CASE_DN_VER_EVT(dn_rxreq_retried, 0x08); + CASE_DN_VER_EVT(dn_rxreq_snp_sent, 0x09); + CASE_DN_VER_EVT(dn_rxreq_snp_stalled, 0x0a); + CASE_DN_VER_EVT(dn_rxreq_trk_full, 0x0b); + CASE_DN_VER_EVT(dn_rxreq_trk_occupancy, 0x0c); + } + } + return (EINVAL); + } else if (ev <= PMC_EV_CMN600_PMU_hnf_snp_fwded) { + *node_type = NODE_TYPE_HN_F; + *event = ev - PMC_EV_CMN600_PMU_hnf_cache_miss; + return (0); + } else if (ev <= PMC_EV_CMN600_PMU_hni_pcie_serialization) { + *node_type = NODE_TYPE_HN_I; + *event = ev - PMC_EV_CMN600_PMU_hni_rrt_rd_occ_cnt_ovfl; + return (0); + } else if (ev <= PMC_EV_CMN600_PMU_xp_partial_dat_flit) { + *node_type = NODE_TYPE_XP; + *event = ev - PMC_EV_CMN600_PMU_xp_txflit_valid; + return (0); + } else if (ev <= PMC_EV_CMN600_PMU_sbsx_txrsp_stall) { + *node_type = NODE_TYPE_SBSX; + *event = ev - PMC_EV_CMN600_PMU_sbsx_rd_req; + return (0); + } else if (ev <= PMC_EV_CMN600_PMU_rnd_rdb_ord) { + *node_type = NODE_TYPE_RN_D; + *event = ev - PMC_EV_CMN600_PMU_rnd_s0_rdata_beats; + return (0); + } else if (ev <= PMC_EV_CMN600_PMU_rni_rdb_ord) { + *node_type = NODE_TYPE_RN_I; + *event = ev - PMC_EV_CMN600_PMU_rni_s0_rdata_beats; + return (0); + } else if (ev <= PMC_EV_CMN600_PMU_cxha_snphaz_occ) { + *node_type = NODE_TYPE_CXHA; + *event = ev - PMC_EV_CMN600_PMU_cxha_rddatbyp; + return (0); + } else if (ev <= PMC_EV_CMN600_PMU_cxra_ext_dat_stall) { + *node_type = NODE_TYPE_CXRA; + *event = ev - PMC_EV_CMN600_PMU_cxra_req_trk_occ; + return (0); + } else if (ev <= PMC_EV_CMN600_PMU_cxla_avg_latency_form_tx_tlp) { + *node_type = NODE_TYPE_CXLA; + *event = ev - PMC_EV_CMN600_PMU_cxla_rx_tlp_link0; + return (0); + } + return (EINVAL); +} + +/* + * Check if a given allocation is feasible. + */ + +static int +cmn600_allocate_pmc(int cpu, int ri, struct pmc *pm, + const struct pmc_op_pmcallocate *a) +{ + struct cmn600_descr *desc; + const struct pmc_descr *pd; + uint64_t caps __unused; + int local_counter, node_type; + enum pmc_event pe; + void *arg; + uint8_t e; + int err; + + (void) cpu; + + KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), + ("[cmn600,%d] illegal CPU value %d", __LINE__, cpu)); + KASSERT(ri >= 0, ("[cmn600,%d] row-index %d out of range", __LINE__, + ri)); + + desc = cmn600desc(ri); + arg = desc->pd_rw_arg; + pd = &desc->pd_descr; + if (cmn600_pmcs[class_ri2unit(ri)].domain != pcpu_find(cpu)->pc_domain) + return (EINVAL); + + /* check class match */ + if (pd->pd_class != a->pm_class) + return (EINVAL); + + caps = pm->pm_caps; + + PMCDBG3(MDP, ALL, 1, "%s ri=%d caps=0x%x", __func__, ri, caps); + + pe = a->pm_ev; + err = cmn600_map_ev2event(pe, pmu_cmn600_rev(arg), &node_type, &e); + if (err != 0) + return (err); + err = pmu_cmn600_alloc_localpmc(arg, + a->pm_md.pm_cmn600.pma_cmn600_nodeid, node_type, &local_counter); + if (err != 0) + return (err); + + pm->pm_md.pm_cmn600.pm_cmn600_config = + a->pm_md.pm_cmn600.pma_cmn600_config; + pm->pm_md.pm_cmn600.pm_cmn600_occupancy = + a->pm_md.pm_cmn600.pma_cmn600_occupancy; + desc->pd_nodeid = pm->pm_md.pm_cmn600.pm_cmn600_nodeid = + a->pm_md.pm_cmn600.pma_cmn600_nodeid; + desc->pd_node_type = pm->pm_md.pm_cmn600.pm_cmn600_node_type = + node_type; + pm->pm_md.pm_cmn600.pm_cmn600_event = e; + desc->pd_local_counter = pm->pm_md.pm_cmn600.pm_cmn600_local_counter = + local_counter; + + PMCDBG3(MDP, ALL, 2, "%s ri=%d -> control=0x%x", __func__, ri, control); + + return (0); +} + +/* Release machine dependent state associated with a PMC. */ + +static int +cmn600_release_pmc(int cpu, int ri, struct pmc *pmc) +{ + struct cmn600_descr *desc; + struct pmc_hw *phw; + struct pmc *pm; + int err; + + (void) pmc; + + KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), + ("[cmn600,%d] illegal CPU value %d", __LINE__, cpu)); + KASSERT(ri >= 0, ("[cmn600,%d] row-index %d out of range", __LINE__, + ri)); + + desc = cmn600desc(ri); + phw = desc->pd_phw; + pm = phw->phw_pmc; + err = pmu_cmn600_free_localpmc(desc->pd_rw_arg, desc->pd_nodeid, + desc->pd_node_type, desc->pd_local_counter); + if (err != 0) + return (err); + + KASSERT(pm == NULL, ("[cmn600,%d] PHW pmc %p non-NULL", __LINE__, pm)); + + return (0); +} + +static inline uint64_t +cmn600_encode_source(int node_type, int counter, int port, int sub) +{ + + /* Calculate pmevcnt0_input_sel based on list in Table 3-794. */ + if (node_type == NODE_TYPE_XP) + return (0x4 | counter); + + return (((port + 1) << 4) | (sub << 2) | counter); +} + +/* + * start a PMC. + */ + +static int +cmn600_start_pmc(int cpu, int ri) +{ + int counter, local_counter, node_type, shift; + uint64_t config, occupancy, source, xp_pmucfg; + struct cmn600_descr *desc; + struct pmc_hw *phw; + struct pmc *pm; + uint8_t event, port, sub; + uint16_t nodeid; + void *arg; + + KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), + ("[cmn600,%d] illegal CPU value %d", __LINE__, cpu)); + KASSERT(ri >= 0, ("[cmn600,%d] row-index %d out of range", __LINE__, + ri)); + + counter = ri % CMN600_COUNTERS_N; + desc = cmn600desc(ri); + phw = desc->pd_phw; + pm = phw->phw_pmc; + arg = desc->pd_rw_arg; + + KASSERT(pm != NULL, + ("[cmn600,%d] starting cpu%d,pmc%d with null pmc record", __LINE__, + cpu, ri)); + + PMCDBG3(MDP, STA, 1, "%s cpu=%d ri=%d", __func__, cpu, ri); + + config = pm->pm_md.pm_cmn600.pm_cmn600_config; + occupancy = pm->pm_md.pm_cmn600.pm_cmn600_occupancy; + node_type = pm->pm_md.pm_cmn600.pm_cmn600_node_type; + event = pm->pm_md.pm_cmn600.pm_cmn600_event; + nodeid = pm->pm_md.pm_cmn600.pm_cmn600_nodeid; + local_counter = pm->pm_md.pm_cmn600.pm_cmn600_local_counter; + port = (nodeid >> 2) & 1; + sub = nodeid & 3; + + switch (node_type) { + case NODE_TYPE_DVM: + case NODE_TYPE_HN_F: + case NODE_TYPE_CXHA: + case NODE_TYPE_CXRA: + pmu_cmn600_md8(arg, nodeid, node_type, + CMN600_COMMON_PMU_EVENT_SEL, + CMN600_COMMON_PMU_EVENT_SEL_OCC_MASK, + occupancy << CMN600_COMMON_PMU_EVENT_SEL_OCC_SHIFT); + break; + case NODE_TYPE_XP: + /* Set PC and Interface.*/ + event |= config; + } + + /* + * 5.5.1 Set up PMU counters + * 1. Ensure that the NIDEN input is asserted. HW side. */ + /* 2. Select event of target node for one of four outputs. */ + pmu_cmn600_md8(arg, nodeid, node_type, CMN600_COMMON_PMU_EVENT_SEL, + 0xff << (local_counter * 8), + event << (local_counter * 8)); + + xp_pmucfg = pmu_cmn600_rd8(arg, nodeid, NODE_TYPE_XP, + POR_DTM_PMU_CONFIG); + /* + * 3. configure XP to connect one of four target node outputs to local + * counter. + */ + source = cmn600_encode_source(node_type, local_counter, port, sub); + shift = (local_counter * POR_DTM_PMU_CONFIG_VCNT_INPUT_SEL_WIDTH) + + POR_DTM_PMU_CONFIG_VCNT_INPUT_SEL_SHIFT; + xp_pmucfg &= ~(0xffUL << shift); + xp_pmucfg |= source << shift; + + /* 4. Pair with global counters A, B, C, ..., H. */ + shift = (local_counter * 4) + 16; + xp_pmucfg &= ~(0xfUL << shift); + xp_pmucfg |= counter << shift; + /* Enable pairing.*/ + xp_pmucfg |= 1 << (local_counter + 4); + + /* 5. Combine local counters 0 with 1, 2 with 3 or all four. */ + xp_pmucfg &= ~0xeUL; + + /* 6. Enable XP's PMU function. */ + xp_pmucfg |= POR_DTM_PMU_CONFIG_PMU_EN; + pmu_cmn600_wr8(arg, nodeid, NODE_TYPE_XP, POR_DTM_PMU_CONFIG, xp_pmucfg); + if (node_type == NODE_TYPE_CXLA) + pmu_cmn600_set8(arg, nodeid, NODE_TYPE_CXLA, + POR_CXG_RA_CFG_CTL, EN_CXLA_PMUCMD_PROP); + + /* 7. Enable DTM. */ + pmu_cmn600_set8(arg, nodeid, NODE_TYPE_XP, POR_DTM_CONTROL, + POR_DTM_CONTROL_DTM_ENABLE); + + /* 8. Reset grouping of global counters. Use 32 bits. */ + pmu_cmn600_clr8(arg, nodeid, NODE_TYPE_DTC, POR_DT_PMCR, + POR_DT_PMCR_CNTCFG_MASK); + + /* 9. Enable DTC. */ + pmu_cmn600_set8(arg, nodeid, NODE_TYPE_DTC, POR_DT_DTC_CTL, + POR_DT_DTC_CTL_DT_EN); + + /* 10. Enable Overflow Interrupt. */ + pmu_cmn600_set8(arg, nodeid, NODE_TYPE_DTC, POR_DT_PMCR, + POR_DT_PMCR_OVFL_INTR_EN); + + /* 11. Run PMC. */ + pmu_cmn600_set8(arg, nodeid, NODE_TYPE_DTC, POR_DT_PMCR, + POR_DT_PMCR_PMU_EN); + + PMCDBG2(MDP, STA, 2, "%s control=0x%x", __func__, control); + + return (0); +} + +/* + * Stop a PMC. + */ + +static int +cmn600_stop_pmc(int cpu, int ri) +{ + struct cmn600_descr *desc; + struct pmc_hw *phw; + struct pmc *pm; + int local_counter; + uint64_t val; + + KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), + ("[cmn600,%d] illegal CPU value %d", __LINE__, cpu)); + KASSERT(ri >= 0, ("[cmn600,%d] row-index %d out of range", __LINE__, + ri)); + + desc = cmn600desc(ri); + phw = desc->pd_phw; + pm = phw->phw_pmc; + + KASSERT(pm != NULL, + ("[cmn600,%d] cpu%d,pmc%d no PMC to stop", __LINE__, + cpu, ri)); + + PMCDBG2(MDP, STO, 1, "%s ri=%d", __func__, ri); + + /* Disable pairing. */ + local_counter = pm->pm_md.pm_cmn600.pm_cmn600_local_counter; + pmu_cmn600_clr8(desc->pd_rw_arg, pm->pm_md.pm_cmn600.pm_cmn600_nodeid, + NODE_TYPE_XP, POR_DTM_PMU_CONFIG, (1 << (local_counter + 4))); + + /* Shutdown XP's DTM function if no paired counters. */ + val = pmu_cmn600_rd8(desc->pd_rw_arg, + pm->pm_md.pm_cmn600.pm_cmn600_nodeid, NODE_TYPE_XP, + POR_DTM_PMU_CONFIG); + if ((val & 0xf0) == 0) + pmu_cmn600_clr8(desc->pd_rw_arg, + pm->pm_md.pm_cmn600.pm_cmn600_nodeid, NODE_TYPE_XP, + POR_DTM_PMU_CONFIG, POR_DTM_CONTROL_DTM_ENABLE); + + return (0); +} + +/* + * describe a PMC + */ +static int +cmn600_describe(int cpu, int ri, struct pmc_info *pi, struct pmc **ppmc) +{ + struct pmc_hw *phw; + size_t copied; + int error; + + KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), + ("[cmn600,%d] illegal CPU %d", __LINE__, cpu)); + KASSERT(ri >= 0, ("[cmn600,%d] row-index %d out of range", __LINE__, + ri)); + + phw = cmn600desc(ri)->pd_phw; + + if ((error = copystr(cmn600desc(ri)->pd_descr.pd_name, + pi->pm_name, PMC_NAME_MAX, &copied)) != 0) + return (error); + + pi->pm_class = cmn600desc(ri)->pd_descr.pd_class; + + if (phw->phw_state & PMC_PHW_FLAG_IS_ENABLED) { + pi->pm_enabled = TRUE; + *ppmc = phw->phw_pmc; + } else { + pi->pm_enabled = FALSE; + *ppmc = NULL; + } + + return (0); +} + +/* + * processor dependent initialization. + */ + +static int +cmn600_pcpu_init(struct pmc_mdep *md, int cpu) +{ + int first_ri, n, npmc; + struct pmc_hw *phw; + struct pmc_cpu *pc; + int mdep_class; + + mdep_class = PMC_MDEP_CLASS_INDEX_CMN600; + KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), + ("[cmn600,%d] insane cpu number %d", __LINE__, cpu)); + + PMCDBG1(MDP, INI, 1, "cmn600-init cpu=%d", cpu); + + /* + * Set the content of the hardware descriptors to a known + * state and initialize pointers in the MI per-cpu descriptor. + */ + + pc = pmc_pcpu[cpu]; + first_ri = md->pmd_classdep[mdep_class].pcd_ri; + npmc = md->pmd_classdep[mdep_class].pcd_num; + + for (n = 0; n < npmc; n++, phw++) { + phw = cmn600desc(n)->pd_phw; + phw->phw_state = PMC_PHW_CPU_TO_STATE(cpu) | + PMC_PHW_INDEX_TO_STATE(n); + /* Set enabled only if unit present. */ + if (cmn600_pmcs[class_ri2unit(n)].arg != NULL) + phw->phw_state |= PMC_PHW_FLAG_IS_ENABLED; + phw->phw_pmc = NULL; + pc->pc_hwpmcs[n + first_ri] = phw; + } + return (0); +} + +/* + * processor dependent cleanup prior to the KLD + * being unloaded + */ + +static int +cmn600_pcpu_fini(struct pmc_mdep *md, int cpu) +{ + + return (0); +} + +static int +cmn600_pmu_intr(struct trapframe *tf, int unit, int i) +{ + struct pmc_cpu *pc; + struct pmc_hw *phw; + struct pmc *pm; + int error, cpu, ri; + + ri = i + unit * CMN600_COUNTERS_N; + cpu = curcpu; + KASSERT(cpu >= 0 && cpu < pmc_cpu_max(), + ("[cmn600,%d] CPU %d out of range", __LINE__, cpu)); + pc = pmc_pcpu[cpu]; + KASSERT(pc != NULL, ("pc != NULL")); + + phw = cmn600desc(ri)->pd_phw; + KASSERT(phw != NULL, ("phw != NULL")); + pm = phw->phw_pmc; + if (pm == NULL) + return (0); + + if (!PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm))) { + /* Always CPU0. */ + pm->pm_pcpu_state[0].pps_overflowcnt += 1; + return (0); + } + + if (pm->pm_state != PMC_STATE_RUNNING) + return (0); + + error = pmc_process_interrupt(PMC_HR, pm, tf); + if (error) + cmn600_stop_pmc(cpu, ri); + + /* Reload sampling count */ + cmn600_write_pmc(cpu, ri, pm->pm_sc.pm_reloadcount); + + return (0); +} + +/* + * Initialize ourselves. + */ +static int +cmn600_init_pmc_units() +{ + int i; + + if (cmn600_units > 0) { /* Already initialized. */ + return (0); + } + + cmn600_units = cmn600_pmc_nunits(); + if (cmn600_units == 0) + return (ENOENT); + + for (i = 0; i < cmn600_units; i++) { + if (cmn600_pmc_getunit(i, &cmn600_pmcs[i].arg, + &cmn600_pmcs[i].domain) != 0) + cmn600_pmcs[i].arg = NULL; + } + return (0); +} + +int +pmc_cmn600_nclasses() +{ + + if (cmn600_pmc_nunits() > 0) + return (1); + return (0); +} + +int +pmc_cmn600_initialize(struct pmc_mdep *md) +{ + struct pmc_classdep *pcd; + int i, npmc, unit; + + cmn600_init_pmc_units(); + KASSERT(md != NULL, ("[cmn600,%d] md is NULL", __LINE__)); + KASSERT(cmn600_units < CMN600_UNIT_MAX, + ("[cmn600,%d] cmn600_units too big", __LINE__)); + + PMCDBG0(MDP,INI,1, "cmn600-initialize"); + + npmc = CMN600_COUNTERS_N * cmn600_units; + pcd = &md->pmd_classdep[PMC_MDEP_CLASS_INDEX_CMN600]; + + pcd->pcd_caps = PMC_CAP_SYSTEM | PMC_CAP_READ | + PMC_CAP_WRITE | PMC_CAP_QUALIFIER | PMC_CAP_INTERRUPT | + PMC_CAP_DOMWIDE; + pcd->pcd_class = PMC_CLASS_CMN600_PMU; + pcd->pcd_num = npmc; + pcd->pcd_ri = md->pmd_npmc; + pcd->pcd_width = 48; + + pcd->pcd_allocate_pmc = cmn600_allocate_pmc; + pcd->pcd_config_pmc = cmn600_config_pmc; + pcd->pcd_describe = cmn600_describe; + pcd->pcd_get_config = cmn600_get_config; + pcd->pcd_get_msr = NULL; + pcd->pcd_pcpu_fini = cmn600_pcpu_fini; + pcd->pcd_pcpu_init = cmn600_pcpu_init; + pcd->pcd_read_pmc = cmn600_read_pmc; + pcd->pcd_release_pmc = cmn600_release_pmc; + pcd->pcd_start_pmc = cmn600_start_pmc; + pcd->pcd_stop_pmc = cmn600_stop_pmc; + pcd->pcd_write_pmc = cmn600_write_pmc; + + md->pmd_npmc += npmc; + cmn600_pmcdesc = malloc(sizeof(struct cmn600_descr *) * npmc * + CMN600_PMU_DEFAULT_UNITS_N, M_PMC, M_WAITOK|M_ZERO); + for (i = 0; i < npmc; i++) { + cmn600_pmcdesc[i] = malloc(sizeof(struct cmn600_descr), M_PMC, + M_WAITOK|M_ZERO); + + unit = i / CMN600_COUNTERS_N; + KASSERT(unit >= 0, ("unit >= 0")); + KASSERT(cmn600_pmcs[unit].arg != NULL, ("arg != NULL")); + + cmn600_pmcdesc[i]->pd_rw_arg = cmn600_pmcs[unit].arg; + cmn600_pmcdesc[i]->pd_descr.pd_class = + PMC_CLASS_CMN600_PMU; + cmn600_pmcdesc[i]->pd_descr.pd_caps = pcd->pcd_caps; + cmn600_pmcdesc[i]->pd_phw = (struct pmc_hw *)malloc( + sizeof(struct pmc_hw), M_PMC, M_WAITOK|M_ZERO); + snprintf(cmn600_pmcdesc[i]->pd_descr.pd_name, 63, + "CMN600_%d", i); + cmn600_pmu_intr_cb(cmn600_pmcs[unit].arg, cmn600_pmu_intr); + } + + return (0); +} + +void +pmc_cmn600_finalize(struct pmc_mdep *md) +{ + struct pmc_classdep *pcd; + int i, npmc; + + KASSERT(md->pmd_classdep[PMC_MDEP_CLASS_INDEX_CMN600].pcd_class == + PMC_CLASS_CMN600_PMU, ("[cmn600,%d] pmc class mismatch", + __LINE__)); + + pcd = &md->pmd_classdep[PMC_MDEP_CLASS_INDEX_CMN600]; + + npmc = pcd->pcd_num; + for (i = 0; i < npmc; i++) { + free(cmn600_pmcdesc[i]->pd_phw, M_PMC); + free(cmn600_pmcdesc[i], M_PMC); + } + free(cmn600_pmcdesc, M_PMC); + cmn600_pmcdesc = NULL; +} + +MODULE_DEPEND(pmc, cmn600, 1, 1, 1); diff --git a/sys/modules/hwpmc/Makefile b/sys/modules/hwpmc/Makefile index 556866abc10c..0db4c55e64f3 100644 --- a/sys/modules/hwpmc/Makefile +++ b/sys/modules/hwpmc/Makefile @@ -1,41 +1,42 @@ # # $FreeBSD$ # .PATH: ${SRCTOP}/sys/dev/hwpmc .PATH: ${SRCTOP}/sys/arm64/arm64 KMOD= hwpmc SRCS= bus_if.h device_if.h hwpmc_mod.c hwpmc_logging.c hwpmc_soft.c SRCS+= vnode_if.h .if ${MACHINE_CPUARCH} == "aarch64" SRCS+= hwpmc_arm64.c hwpmc_arm64_md.c +SRCS+= cmn600.c hwpmc_cmn600.c SRCS+= hwpmc_dmc620.c pmu_dmc620.c .endif .if ${MACHINE_CPUARCH} == "amd64" SRCS+= hwpmc_amd.c hwpmc_core.c hwpmc_intel.c hwpmc_tsc.c SRCS+= hwpmc_x86.c hwpmc_uncore.c .endif .if ${MACHINE_CPUARCH} == "arm" SRCS+= hwpmc_arm.c .endif .if ${MACHINE_ARCH} == "armv7" SRCS+= hwpmc_armv7.c .endif .if ${MACHINE_CPUARCH} == "i386" SRCS+= hwpmc_amd.c hwpmc_core.c hwpmc_intel.c SRCS+= hwpmc_tsc.c hwpmc_x86.c hwpmc_uncore.c .endif .if ${MACHINE_CPUARCH} == "powerpc" SRCS+= hwpmc_powerpc.c hwpmc_e500.c hwpmc_mpc7xxx.c hwpmc_ppc970.c \ hwpmc_power8.c .endif .include