Index: sys/arm64/coresight/coresight.h =================================================================== --- sys/arm64/coresight/coresight.h +++ sys/arm64/coresight/coresight.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2018-2020 Ruslan Bukin + * Copyright (c) 2018-2023 Ruslan Bukin * All rights reserved. * * This software was developed by SRI International and the University of @@ -48,6 +48,8 @@ #include #endif +#include + #define CORESIGHT_ITCTRL 0xf00 #define CORESIGHT_CLAIMSET 0xfa0 #define CORESIGHT_CLAIMCLR 0xfa4 @@ -60,7 +62,8 @@ enum cs_dev_type { CORESIGHT_ETMV4, - CORESIGHT_TMC, + CORESIGHT_TMC_ETF, + CORESIGHT_TMC_ETR, CORESIGHT_DYNAMIC_REPLICATOR, CORESIGHT_FUNNEL, CORESIGHT_CPU_DEBUG, @@ -119,15 +122,13 @@ }; struct etr_state { - boolean_t started; - uint32_t cycle; - uint32_t offset; uint32_t low; uint32_t high; uint32_t bufsize; - uint32_t flags; -#define ETR_FLAG_ALLOCATE (1 << 0) -#define ETR_FLAG_RELEASE (1 << 1) + vm_page_t *pages; + int npages; + int curpage; + vm_offset_t curpage_offset; }; struct coresight_event { @@ -149,16 +150,31 @@ uint8_t excp_level; }; -static MALLOC_DEFINE(M_CORESIGHT, "coresight", "ARM Coresight"); +MALLOC_DECLARE(M_CORESIGHT); struct coresight_platform_data *coresight_fdt_get_platform_data(device_t dev); struct coresight_platform_data *coresight_acpi_get_platform_data(device_t dev); -struct endpoint * coresight_get_output_endpoint(struct coresight_platform_data *pdata); -struct coresight_device * coresight_get_output_device(struct endpoint *endp, struct endpoint **); +struct endpoint * + coresight_get_output_endpoint(struct coresight_platform_data *pdata); +struct coresight_device * + coresight_get_output_device(struct coresight_device *cs_dev, + struct endpoint *endp, struct endpoint **); int coresight_register(struct coresight_desc *desc); -int coresight_init_event(int cpu, struct coresight_event *event); -void coresight_enable(int cpu, struct coresight_event *event); -void coresight_disable(int cpu, struct coresight_event *event); -void coresight_read(int cpu, struct coresight_event *event); + +int coresight_init_event(struct coresight_event *event, int cpu); + +void coresight_setup(struct coresight_event *event, struct hwt_thread *thr); + +void coresight_configure(struct coresight_event *event, struct hwt_thread *thr); +void coresight_deconfigure(struct coresight_event *event); + +void coresight_start(struct coresight_event *event); +void coresight_stop(struct coresight_event *event); + +void coresight_enable(struct coresight_event *event); +void coresight_disable(struct coresight_event *event); + +void coresight_read(struct coresight_event *event); +void coresight_dump(struct coresight_event *event); #endif /* !_ARM64_CORESIGHT_CORESIGHT_H_ */ Index: sys/arm64/coresight/coresight.c =================================================================== --- sys/arm64/coresight/coresight.c +++ sys/arm64/coresight/coresight.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2018-2020 Ruslan Bukin + * Copyright (c) 2018-2023 Ruslan Bukin * All rights reserved. * * This software was developed by SRI International and the University of @@ -39,12 +39,165 @@ #include #include #include +#include #include #include +#include +#include +#include +#include +#include + +#define CORESIGHT_DEBUG +#undef CORESIGHT_DEBUG + +#ifdef CORESIGHT_DEBUG +#define dprintf(fmt, ...) printf(fmt, ##__VA_ARGS__) +#else +#define dprintf(fmt, ...) +#endif + +MALLOC_DEFINE(M_CORESIGHT, "coresight", "ARM Coresight"); + static struct mtx cs_mtx; struct coresight_device_list cs_devs; +static struct hwt_backend_ops coresight_ops; + +static struct hwt_backend backend = { + .ops = &coresight_ops, + .name = "coresight", +}; +static struct coresight_event cs_event[MAXCPU]; + +static void +coresight_backend_init(struct hwt_context *ctx) +{ + struct coresight_event *event; + struct hwt_thread *thr; + int cpu_id; + + /* + * 1. Use buffer from the first thread as Funnel merges traces from + * all CPUs to a single place. + * + * 2. Ctx was just allocated, so the lock is not really needed. + */ + HWT_CTX_LOCK(ctx); + thr = hwt_thread_first(ctx); + HWT_CTX_UNLOCK(ctx); + + for (cpu_id = 0; cpu_id < mp_ncpus; cpu_id++) { + event = &cs_event[cpu_id]; + memset(event, 0, sizeof(struct coresight_event)); + event->etr.low = 0; + event->etr.high = 0; + event->etr.pages = thr->pages; + event->etr.npages = thr->npages; + event->etr.bufsize = thr->npages * PAGE_SIZE; + event->excp_level = 0; /* TODO: User level only for now. */ + event->src = CORESIGHT_ETMV4; + event->sink = CORESIGHT_TMC_ETR; + + coresight_init_event(event, cpu_id); + + coresight_setup(event, thr); + if (cpu_id == 0) + coresight_start(event); + } +} + +static void +coresight_backend_deinit(void) +{ + struct coresight_event *event; + int cpu_id; + + for (cpu_id = 0; cpu_id < mp_ncpus; cpu_id++) { + event = &cs_event[cpu_id]; + coresight_disable(event); + if (cpu_id == 0) + coresight_stop(event); + } +} + +static void +coresight_backend_configure(struct hwt_thread *thr, int cpu_id) +{ + struct coresight_event *event; + + event = &cs_event[cpu_id]; + + /* + * OpenCSD needs a trace ID to distinguish trace sessions + * as they are merged to a single buffer by using funnel + * device. + */ + event->etm.trace_id = thr->thread_id; + coresight_configure(event, thr); +} + +static void +coresight_backend_enable(struct hwt_thread *thr, int cpu_id) +{ + struct coresight_event *event; + + event = &cs_event[cpu_id]; + + coresight_enable(event); +} + +static void +coresight_backend_disable(struct hwt_thread *thr, int cpu_id) +{ + struct coresight_event *event; + + event = &cs_event[cpu_id]; + + coresight_disable(event); +} + +static int +coresight_backend_read(struct hwt_thread *thr, int cpu_id, + int *curpage, vm_offset_t *curpage_offset) +{ + struct coresight_event *event; + + event = &cs_event[cpu_id]; + + KASSERT(event != NULL, ("No event found")); + + coresight_read(event); + + *curpage = event->etr.curpage; + *curpage_offset = event->etr.curpage_offset; + + return (0); +} + +static void +coresight_backend_dump(struct hwt_thread *thr, int cpu_id) +{ + struct coresight_event *event; + + event = &cs_event[cpu_id]; + + coresight_dump(event); +} + +static struct hwt_backend_ops coresight_ops = { + .hwt_backend_init = coresight_backend_init, + .hwt_backend_deinit = coresight_backend_deinit, + + .hwt_backend_configure = coresight_backend_configure, + + .hwt_backend_enable = coresight_backend_enable, + .hwt_backend_disable = coresight_backend_disable, + + .hwt_backend_read = coresight_backend_read, + .hwt_backend_dump = coresight_backend_dump, +}; int coresight_register(struct coresight_desc *desc) @@ -61,6 +214,9 @@ TAILQ_INSERT_TAIL(&cs_devs, cs_dev, link); mtx_unlock(&cs_mtx); + if (desc->dev_type == CORESIGHT_TMC_ETR) + hwt_register(&backend); + return (0); } @@ -81,7 +237,8 @@ } struct coresight_device * -coresight_get_output_device(struct endpoint *endp, struct endpoint **out_endp) +coresight_get_output_device(struct coresight_device *cs_dev0, + struct endpoint *endp, struct endpoint **out_endp) { struct coresight_platform_data *pdata; struct coresight_device *cs_dev; @@ -94,7 +251,11 @@ case CORESIGHT_BUS_FDT: #ifdef FDT if (endp->their_node == endp2->my_node) { - *out_endp = endp2; + *out_endp = + malloc(sizeof(struct endpoint), + M_CORESIGHT, M_WAITOK | M_ZERO); + memcpy(*out_endp, endp2, + sizeof(struct endpoint)); return (cs_dev); } #endif @@ -103,7 +264,11 @@ case CORESIGHT_BUS_ACPI: #ifdef DEV_ACPI if (endp->their_handle == endp2->my_handle) { - *out_endp = endp2; + *out_endp = + malloc(sizeof(struct endpoint), + M_CORESIGHT, M_WAITOK | M_ZERO); + memcpy(*out_endp, endp2, + sizeof(struct endpoint)); return (cs_dev); } #endif Index: sys/arm64/coresight/coresight_cmd.c =================================================================== --- sys/arm64/coresight/coresight_cmd.c +++ sys/arm64/coresight/coresight_cmd.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2018-2020 Ruslan Bukin + * Copyright (c) 2018-2023 Ruslan Bukin * All rights reserved. * * This software was developed by SRI International and the University of @@ -57,7 +57,7 @@ if (endp->input != 0) continue; - out = coresight_get_output_device(endp, &out_endp); + out = coresight_get_output_device(cs_dev, endp, &out_endp); if (out != NULL) { if (LIST_EMPTY(&event->endplist)) { /* Add source device */ @@ -94,7 +94,7 @@ } int -coresight_init_event(int cpu, struct coresight_event *event) +coresight_init_event(struct coresight_event *event, int cpu) { struct coresight_device *cs_dev; struct endpoint *endp; @@ -126,7 +126,55 @@ } void -coresight_enable(int cpu, struct coresight_event *event) +coresight_setup(struct coresight_event *event, struct hwt_thread *thr) +{ + struct coresight_device *cs_dev; + struct endpoint *endp; + + LIST_FOREACH(endp, &event->endplist, endplink) { + cs_dev = endp->cs_dev; + CORESIGHT_SETUP(cs_dev->dev, endp, event); + } +} + +void +coresight_configure(struct coresight_event *event, struct hwt_thread *thr) +{ + struct coresight_device *cs_dev; + struct endpoint *endp; + + LIST_FOREACH(endp, &event->endplist, endplink) { + cs_dev = endp->cs_dev; + CORESIGHT_CONFIGURE(cs_dev->dev, endp, event, thr); + } +} + +void +coresight_start(struct coresight_event *event) +{ + struct coresight_device *cs_dev; + struct endpoint *endp; + + LIST_FOREACH(endp, &event->endplist, endplink) { + cs_dev = endp->cs_dev; + CORESIGHT_START(cs_dev->dev, endp, event); + } +} + +void +coresight_stop(struct coresight_event *event) +{ + struct coresight_device *cs_dev; + struct endpoint *endp; + + LIST_FOREACH(endp, &event->endplist, endplink) { + cs_dev = endp->cs_dev; + CORESIGHT_STOP(cs_dev->dev, endp, event); + } +} + +void +coresight_enable(struct coresight_event *event) { struct coresight_device *cs_dev; struct endpoint *endp; @@ -138,7 +186,7 @@ } void -coresight_disable(int cpu, struct coresight_event *event) +coresight_disable(struct coresight_event *event) { struct coresight_device *cs_dev; struct endpoint *endp; @@ -150,10 +198,25 @@ } void -coresight_read(int cpu, struct coresight_event *event) +coresight_dump(struct coresight_event *event) { + struct coresight_device *cs_dev; struct endpoint *endp; - LIST_FOREACH(endp, &event->endplist, endplink) - CORESIGHT_READ(endp->cs_dev->dev, endp, event); + LIST_FOREACH(endp, &event->endplist, endplink) { + cs_dev = endp->cs_dev; + CORESIGHT_DUMP(cs_dev->dev); + } +} + +void +coresight_read(struct coresight_event *event) +{ + struct coresight_device *cs_dev; + struct endpoint *endp; + + LIST_FOREACH(endp, &event->endplist, endplink) { + cs_dev = endp->cs_dev; + CORESIGHT_READ(cs_dev->dev, endp, event); + } } Index: sys/arm64/coresight/coresight_etm4x.h =================================================================== --- sys/arm64/coresight/coresight_etm4x.h +++ sys/arm64/coresight/coresight_etm4x.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2018-2020 Ruslan Bukin + * Copyright (c) 2018-2023 Ruslan Bukin * All rights reserved. * * This software was developed by BAE Systems, the University of Cambridge @@ -172,7 +172,66 @@ #define TRCPIDR567(n) (0xFD4 + ((n) - 5) * 0x4) /* Management Peripheral ID5 to Peripheral ID7 Registers */ #define TRCCIDR(n) (0xFF0 + (n) * 0x4) /* Management Component IDn Register [n=0-4] */ -DECLARE_CLASS(etm_driver); +/* ETMv4 resources */ +#define ETM_MAX_NR_PE 8 +#define ETMv4_MAX_CNTR 4 +#define ETM_MAX_SEQ_STATES 4 +#define ETM_MAX_EXT_INP_SEL 4 +#define ETM_MAX_EXT_INP 256 +#define ETM_MAX_EXT_OUT 4 +#define ETM_MAX_SINGLE_ADDR_CMP 16 +#define ETM_MAX_ADDR_RANGE_CMP (ETM_MAX_SINGLE_ADDR_CMP / 2) +#define ETM_MAX_DATA_VAL_CMP 8 +#define ETMv4_MAX_CTXID_CMP 8 +#define ETM_MAX_VMID_CMP 8 +#define ETM_MAX_PE_CMP 8 +#define ETM_MAX_RES_SEL 32 +#define ETM_MAX_SS_CMP 8 + +struct etmv4_config { + uint32_t mode; + uint32_t pe_sel; + uint32_t cfg; + uint32_t eventctrl0; + uint32_t eventctrl1; + uint32_t stall_ctrl; + uint32_t ts_ctrl; + uint32_t syncfreq; + uint32_t ccctlr; + uint32_t bb_ctrl; + uint32_t vinst_ctrl; + uint32_t viiectlr; + uint32_t vissctlr; + uint32_t vipcssctlr; + uint8_t seq_idx; + uint32_t seq_ctrl[ETM_MAX_SEQ_STATES]; + uint32_t seq_rst; + uint32_t seq_state; + uint8_t cntr_idx; + uint32_t cntrldvr[ETMv4_MAX_CNTR]; + uint32_t cntr_ctrl[ETMv4_MAX_CNTR]; + uint32_t cntr_val[ETMv4_MAX_CNTR]; + uint8_t res_idx; + uint32_t res_ctrl[ETM_MAX_RES_SEL]; + uint8_t ss_idx; + uint32_t ss_ctrl[ETM_MAX_SS_CMP]; + uint32_t ss_status[ETM_MAX_SS_CMP]; + uint32_t ss_pe_cmp[ETM_MAX_SS_CMP]; + uint8_t addr_idx; + uint64_t addr_val[ETM_MAX_SINGLE_ADDR_CMP]; + uint64_t addr_acc[ETM_MAX_SINGLE_ADDR_CMP]; + uint8_t addr_type[ETM_MAX_SINGLE_ADDR_CMP]; + uint8_t ctxid_idx; + uint64_t ctxid_pid[ETMv4_MAX_CTXID_CMP]; + uint32_t ctxid_mask0; + uint32_t ctxid_mask1; + uint8_t vmid_idx; + uint64_t vmid_val[ETM_MAX_VMID_CMP]; + uint32_t vmid_mask0; + uint32_t vmid_mask1; + uint32_t ext_inp; + uint8_t s_ex_level; +}; struct etm_softc { struct resource *res; @@ -181,4 +240,6 @@ int etm_attach(device_t dev); +DECLARE_CLASS(etm_driver); + #endif /* !_ARM64_CORESIGHT_ETM4X_H_ */ Index: sys/arm64/coresight/coresight_etm4x.c =================================================================== --- sys/arm64/coresight/coresight_etm4x.c +++ sys/arm64/coresight/coresight_etm4x.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2018-2020 Ruslan Bukin + * Copyright (c) 2018-2023 Ruslan Bukin * All rights reserved. * * This software was developed by BAE Systems, the University of Cambridge @@ -43,6 +43,8 @@ #include #include +#include + #include "coresight_if.h" #define ETM_DEBUG @@ -69,12 +71,97 @@ }; static int -etm_prepare(device_t dev, struct coresight_event *event) +etm_configure_etmv4(device_t dev, struct etmv4_config *config) +{ + struct etm_softc *sc; + int cpu; + int i; + + sc = device_get_softc(dev); + + cpu = PCPU_GET(cpuid); + + dprintf("%s_%d\n", __func__, device_get_unit(dev)); + + bus_write_4(sc->res, TRCCONFIGR, config->cfg); + bus_write_4(sc->res, TRCEVENTCTL0R, config->eventctrl0); + bus_write_4(sc->res, TRCEVENTCTL1R, config->eventctrl1); + bus_write_4(sc->res, TRCSTALLCTLR, config->stall_ctrl); + bus_write_4(sc->res, TRCTSCTLR, config->ts_ctrl); + bus_write_4(sc->res, TRCSYNCPR, config->syncfreq); + bus_write_4(sc->res, TRCVICTLR, config->vinst_ctrl); + bus_write_4(sc->res, TRCPROCSELR, cpu); /* Not sure if this is needed.*/ + + /* Address-range filtering. */ + for (i = 0; i < ETM_MAX_SINGLE_ADDR_CMP; i++) { + bus_write_8(sc->res, TRCACVR(i), config->addr_val[i]); + bus_write_8(sc->res, TRCACATR(i), config->addr_acc[i]); + } + bus_write_4(sc->res, TRCVIIECTLR, config->viiectlr); + + bus_write_4(sc->res, TRCVDARCCTLR, 0); + bus_write_4(sc->res, TRCSSCSR(0), 0); + bus_write_4(sc->res, TRCVISSCTLR, config->vissctlr); + bus_write_4(sc->res, TRCVDCTLR, 0); + bus_write_4(sc->res, TRCVDSACCTLR, 0); + +#if 0 + uint32_t mode; + uint32_t pe_sel; + uint32_t cfg; + uint32_t eventctrl0; + uint32_t eventctrl1; + uint32_t stall_ctrl; + uint32_t ts_ctrl; + uint32_t syncfreq; + uint32_t ccctlr; + uint32_t bb_ctrl; + uint32_t vinst_ctrl; + uint32_t viiectlr; + uint32_t vissctlr; + uint32_t vipcssctlr; + uint8_t seq_idx; + uint32_t seq_ctrl[ETM_MAX_SEQ_STATES]; + uint32_t seq_rst; + uint32_t seq_state; + uint8_t cntr_idx; + uint32_t cntrldvr[ETMv4_MAX_CNTR]; + uint32_t cntr_ctrl[ETMv4_MAX_CNTR]; + uint32_t cntr_val[ETMv4_MAX_CNTR]; + uint8_t res_idx; + uint32_t res_ctrl[ETM_MAX_RES_SEL]; + uint8_t ss_idx; + uint32_t ss_ctrl[ETM_MAX_SS_CMP]; + uint32_t ss_status[ETM_MAX_SS_CMP]; + uint32_t ss_pe_cmp[ETM_MAX_SS_CMP]; + uint8_t addr_idx; + uint64_t addr_val[ETM_MAX_SINGLE_ADDR_CMP]; + uint64_t addr_acc[ETM_MAX_SINGLE_ADDR_CMP]; + uint8_t addr_type[ETM_MAX_SINGLE_ADDR_CMP]; + uint8_t ctxid_idx; + uint64_t ctxid_pid[ETMv4_MAX_CTXID_CMP]; + uint32_t ctxid_mask0; + uint32_t ctxid_mask1; + uint8_t vmid_idx; + uint64_t vmid_val[ETM_MAX_VMID_CMP]; + uint32_t vmid_mask0; + uint32_t vmid_mask1; + uint32_t ext_inp; + uint8_t s_ex_level; +#endif + + return (0); +} + +static int +etm_configure_etmv4_default(device_t dev, struct coresight_event *event) { struct etm_softc *sc; uint32_t reg; int i; + dprintf("%s%d\n", __func__, device_get_unit(dev)); + sc = device_get_softc(dev); /* Configure ETM */ @@ -88,6 +175,7 @@ reg |= TRCCONFIGR_INSTP0_LDRSTR; reg |= TRCCONFIGR_COND_ALL; bus_write_4(sc->res, TRCCONFIGR, reg); + dprintf("%s: TRCCONFIGR is %x\n", __func__, reg); /* Disable all event tracing. */ bus_write_4(sc->res, TRCEVENTCTL0R, 0); @@ -99,8 +187,10 @@ /* Enable trace synchronization every 4096 bytes of trace. */ bus_write_4(sc->res, TRCSYNCPR, TRCSYNCPR_4K); - /* Set a value for the trace ID */ - bus_write_4(sc->res, TRCTRACEIDR, event->etm.trace_id); + dprintf("%s: IDR0 is %x\n", __func__, bus_read_4(sc->res, TRCIDR(0))); + dprintf("%s: IDR1 is %x\n", __func__, bus_read_4(sc->res, TRCIDR(1))); + dprintf("%s: IDR2 is %x\n", __func__, bus_read_4(sc->res, TRCIDR(2))); + dprintf("%s: IDR8 is %x\n", __func__, bus_read_4(sc->res, TRCIDR(8))); /* * Disable the timestamp event. The trace unit still generates @@ -169,6 +259,29 @@ return (0); } +static int +etm_configure(device_t dev, struct endpoint *endp, + struct coresight_event *event, struct hwt_thread *thr) +{ + struct etmv4_config *config; + struct hwt_context *ctx; + int error; + + dprintf("%s%d\n", __func__, device_get_unit(dev)); + + ctx = thr->ctx; + + if (ctx->config && + ctx->config_size == sizeof(struct etmv4_config) && + ctx->config_version == 1) { + config = (struct etmv4_config *)ctx->config; + error = etm_configure_etmv4(dev, config); + } else + error = etm_configure_etmv4_default(dev, event); + + return (error); +} + static int etm_init(device_t dev) { @@ -200,15 +313,20 @@ sc = device_get_softc(dev); - etm_prepare(dev, event); + dprintf("%s%d\n", __func__, device_get_unit(dev)); + + /* Set a value for the trace ID */ + bus_write_4(sc->res, TRCTRACEIDR, event->etm.trace_id); /* Enable the trace unit */ - bus_write_4(sc->res, TRCPRGCTLR, TRCPRGCTLR_EN); + reg = bus_read_4(sc->res, TRCPRGCTLR); + reg |= TRCPRGCTLR_EN; + bus_write_4(sc->res, TRCPRGCTLR, reg); /* Wait for an IDLE bit to be LOW */ do { reg = bus_read_4(sc->res, TRCSTATR); - } while ((reg & TRCSTATR_IDLE) == 1); + } while (reg & TRCSTATR_IDLE); if ((bus_read_4(sc->res, TRCPRGCTLR) & TRCPRGCTLR_EN) == 0) panic("etm is not enabled\n"); @@ -225,8 +343,12 @@ sc = device_get_softc(dev); + dprintf("%s%d\n", __func__, device_get_unit(dev)); + /* Disable the trace unit */ - bus_write_4(sc->res, TRCPRGCTLR, 0); + reg = bus_read_4(sc->res, TRCPRGCTLR); + reg &= ~TRCPRGCTLR_EN; + bus_write_4(sc->res, TRCPRGCTLR, reg); /* Wait for an IDLE bit */ do { @@ -258,6 +380,7 @@ static device_method_t etm_methods[] = { /* Coresight interface */ DEVMETHOD(coresight_init, etm_init), + DEVMETHOD(coresight_configure, etm_configure), DEVMETHOD(coresight_enable, etm_enable), DEVMETHOD(coresight_disable, etm_disable), DEVMETHOD_END Index: sys/arm64/coresight/coresight_fdt.c =================================================================== --- sys/arm64/coresight/coresight_fdt.c +++ sys/arm64/coresight/coresight_fdt.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2018-2020 Ruslan Bukin + * Copyright (c) 2018-2023 Ruslan Bukin * All rights reserved. * * This software was developed by SRI International and the University of @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -47,10 +48,10 @@ #include static int -coresight_fdt_get_ports(phandle_t dev_node, - struct coresight_platform_data *pdata) +coresight_fdt_get_ports(phandle_t dev_node, phandle_t node, + struct coresight_platform_data *pdata, bool input) { - phandle_t node, child; + phandle_t child; pcell_t port_reg; phandle_t xref; char *name; @@ -58,12 +59,6 @@ phandle_t endpoint_child; struct endpoint *endp; - child = ofw_bus_find_child(dev_node, "ports"); - if (child) - node = child; - else - node = dev_node; - for (child = OF_child(node); child != 0; child = OF_peer(child)) { ret = OF_getprop_alloc(child, "name", (void **)&name); if (ret == -1) @@ -89,8 +84,8 @@ endp->their_node = OF_node_from_xref(xref); endp->dev_node = dev_node; endp->reg = port_reg; - if (OF_getproplen(endpoint_child, - "slave-mode") >= 0) { + + if (input) { pdata->in_ports++; endp->input = 1; } else @@ -108,19 +103,28 @@ } static int -coresight_fdt_get_cpu(phandle_t node, - struct coresight_platform_data *pdata) +coresight_fdt_get_cpu(phandle_t node, struct coresight_platform_data *pdata) { + struct pcpu *pcpu; phandle_t cpu_node; pcell_t xref; - pcell_t cpu_reg; + pcell_t cpu_reg[2]; + uint64_t mpidr; + int i; if (OF_getencprop(node, "cpu", &xref, sizeof(xref)) != -1) { cpu_node = OF_node_from_xref(xref); if (OF_getencprop(cpu_node, "reg", (void *)&cpu_reg, - sizeof(cpu_reg)) > 0) { - pdata->cpu = cpu_reg; - return (0); + sizeof(cpu_reg)) > 0) { + mpidr = cpu_reg[1]; + mpidr |= ((uint64_t)cpu_reg[0] << 32); + for (i = 0; i < mp_ncpus; i++) { + pcpu = cpuid_to_pcpu[i]; + if (pcpu->pc_mpidr == mpidr) { + pdata->cpu = pcpu->pc_cpuid; + return (0); + } + } } } @@ -131,7 +135,7 @@ coresight_fdt_get_platform_data(device_t dev) { struct coresight_platform_data *pdata; - phandle_t node; + phandle_t node, child; node = ofw_bus_get_node(dev); @@ -143,7 +147,14 @@ TAILQ_INIT(&pdata->endpoints); coresight_fdt_get_cpu(node, pdata); - coresight_fdt_get_ports(node, pdata); + + child = ofw_bus_find_child(node, "in-ports"); + if (child) + coresight_fdt_get_ports(node, child, pdata, true); + + child = ofw_bus_find_child(node, "out-ports"); + if (child) + coresight_fdt_get_ports(node, child, pdata, false); if (bootverbose) printf("Total ports: in %d out %d\n", Index: sys/arm64/coresight/coresight_funnel.c =================================================================== --- sys/arm64/coresight/coresight_funnel.c +++ sys/arm64/coresight/coresight_funnel.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2018-2020 Ruslan Bukin + * Copyright (c) 2018-2023 Ruslan Bukin * All rights reserved. * * This software was developed by BAE Systems, the University of Cambridge @@ -76,8 +76,8 @@ } static int -funnel_enable(device_t dev, struct endpoint *endp, - struct coresight_event *event) +funnel_configure(device_t dev, struct endpoint *endp, + struct coresight_event *event, struct hwt_thread *thr) { struct funnel_softc *sc; uint32_t reg; @@ -96,7 +96,7 @@ } static void -funnel_disable(device_t dev, struct endpoint *endp, +funnel_deconfigure(device_t dev, struct endpoint *endp, struct coresight_event *event) { struct funnel_softc *sc; @@ -135,8 +135,8 @@ static device_method_t funnel_methods[] = { /* Coresight interface */ DEVMETHOD(coresight_init, funnel_init), - DEVMETHOD(coresight_enable, funnel_enable), - DEVMETHOD(coresight_disable, funnel_disable), + DEVMETHOD(coresight_configure, funnel_configure), + DEVMETHOD(coresight_deconfigure,funnel_deconfigure), DEVMETHOD_END }; Index: sys/arm64/coresight/coresight_funnel_fdt.c =================================================================== --- sys/arm64/coresight/coresight_funnel_fdt.c +++ sys/arm64/coresight/coresight_funnel_fdt.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2018-2020 Ruslan Bukin + * Copyright (c) 2018-2023 Ruslan Bukin * All rights reserved. * * This software was developed by BAE Systems, the University of Cambridge @@ -49,7 +49,7 @@ #include "coresight_if.h" static struct ofw_compat_data compat_data[] = { - { "arm,coresight-funnel", HWTYPE_FUNNEL }, + { "arm,coresight-dynamic-funnel", HWTYPE_FUNNEL }, { "arm,coresight-static-funnel", HWTYPE_STATIC_FUNNEL }, { NULL, HWTYPE_NONE } }; Index: sys/arm64/coresight/coresight_if.m =================================================================== --- sys/arm64/coresight/coresight_if.m +++ sys/arm64/coresight/coresight_if.m @@ -1,5 +1,5 @@ #- -# Copyright (c) 2018 Ruslan Bukin +# Copyright (c) 2018-2023 Ruslan Bukin # All rights reserved. # # This software was developed by SRI International and the University of @@ -39,6 +39,37 @@ device_t dev; }; +METHOD int setup { + device_t dev; + struct endpoint *endp; + struct coresight_event *event; +}; + +METHOD int configure { + device_t dev; + struct endpoint *endp; + struct coresight_event *event; + struct hwt_thread *thr; +}; + +METHOD void deconfigure { + device_t dev; + struct endpoint *endp; + struct coresight_event *event; +}; + +METHOD int start { + device_t dev; + struct endpoint *endp; + struct coresight_event *event; +}; + +METHOD void stop { + device_t dev; + struct endpoint *endp; + struct coresight_event *event; +} + METHOD int enable { device_t dev; struct endpoint *endp; @@ -51,6 +82,10 @@ struct coresight_event *event; }; +METHOD void dump { + device_t dev; +}; + METHOD int read { device_t dev; struct endpoint *endp; Index: sys/arm64/coresight/coresight_replicator.c =================================================================== --- sys/arm64/coresight/coresight_replicator.c +++ sys/arm64/coresight/coresight_replicator.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2018-2020 Ruslan Bukin + * Copyright (c) 2018-2023 Ruslan Bukin * All rights reserved. * * This software was developed by BAE Systems, the University of Cambridge @@ -64,8 +64,8 @@ } static int -replicator_enable(device_t dev, struct endpoint *endp, - struct coresight_event *event) +replicator_configure(device_t dev, struct endpoint *endp, + struct coresight_event *event, struct hwt_thread *thr) { struct replicator_softc *sc; @@ -84,7 +84,7 @@ } static void -replicator_disable(device_t dev, struct endpoint *endp, +replicator_deconfigure(device_t dev, struct endpoint *endp, struct coresight_event *event) { struct replicator_softc *sc; @@ -119,8 +119,8 @@ static device_method_t replicator_methods[] = { /* Coresight interface */ DEVMETHOD(coresight_init, replicator_init), - DEVMETHOD(coresight_enable, replicator_enable), - DEVMETHOD(coresight_disable, replicator_disable), + DEVMETHOD(coresight_configure, replicator_configure), + DEVMETHOD(coresight_deconfigure,replicator_deconfigure), DEVMETHOD_END }; Index: sys/arm64/coresight/coresight_tmc.h =================================================================== --- sys/arm64/coresight/coresight_tmc.h +++ sys/arm64/coresight/coresight_tmc.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2018-2020 Ruslan Bukin + * Copyright (c) 2018-2023 Ruslan Bukin * All rights reserved. * * This software was developed by SRI International and the University of @@ -119,19 +119,21 @@ DECLARE_CLASS(tmc_driver); struct tmc_softc { - struct resource *res; + struct resource *res[2]; device_t dev; - uint64_t cycle; struct coresight_platform_data *pdata; uint32_t dev_type; #define CORESIGHT_UNKNOWN 0 #define CORESIGHT_ETR 1 #define CORESIGHT_ETF 2 uint32_t nev; - struct coresight_event *event; boolean_t etf_configured; + boolean_t scatter_gather; + void *intrhand; }; +typedef uint32_t sgte_t; + int tmc_attach(device_t dev); #endif /* !_ARM64_CORESIGHT_CORESIGHT_TMC_H_ */ Index: sys/arm64/coresight/coresight_tmc.c =================================================================== --- sys/arm64/coresight/coresight_tmc.c +++ sys/arm64/coresight/coresight_tmc.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2018-2020 Ruslan Bukin + * Copyright (c) 2018-2023 Ruslan Bukin * All rights reserved. * * This software was developed by SRI International and the University of @@ -39,6 +39,14 @@ #include #include +#include +#include +#include +#include +#include +#include +#include + #include #include @@ -46,63 +54,168 @@ #define TMC_DEBUG #undef TMC_DEBUG - + #ifdef TMC_DEBUG #define dprintf(fmt, ...) printf(fmt, ##__VA_ARGS__) #else #define dprintf(fmt, ...) #endif +#define SG_PT_ENTIRES_PER_PAGE (PAGE_SIZE / sizeof(sgte_t)) +#define ETR_SG_ET_MASK 0x3 +#define ETR_SG_ET_LAST 0x1 +#define ETR_SG_ET_NORMAL 0x2 +#define ETR_SG_ET_LINK 0x3 + +#define ETR_SG_PAGE_SHIFT 12 +#define ETR_SG_ADDR_SHIFT 4 + +#define ETR_SG_ENTRY(addr, type) \ + (sgte_t)((((addr) >> ETR_SG_PAGE_SHIFT) << ETR_SG_ADDR_SHIFT) | \ + (type & ETR_SG_ET_MASK)) + static struct resource_spec tmc_spec[] = { { SYS_RES_MEMORY, 0, RF_ACTIVE }, + { SYS_RES_IRQ, 0, RF_ACTIVE | RF_OPTIONAL }, { -1, 0 } }; static int -tmc_start(device_t dev) +tmc_alloc_pages(struct tmc_softc *sc, vm_page_t *pages, int npages) +{ + vm_paddr_t low, high, boundary; + vm_memattr_t memattr; + int alignment; + vm_pointer_t va; + int pflags; + vm_page_t m; + int tries; + int i; + + alignment = PAGE_SIZE; + low = 0; + high = -1UL; + boundary = 0; + pflags = VM_ALLOC_NORMAL | VM_ALLOC_NOBUSY | VM_ALLOC_WIRED | + VM_ALLOC_ZERO; + memattr = VM_MEMATTR_DEFAULT; + + for (i = 0; i < npages; i++) { + tries = 0; +retry: + m = vm_page_alloc_noobj_contig(pflags, 1, low, high, + alignment, boundary, memattr); + if (m == NULL) { + if (tries < 3) { + if (!vm_page_reclaim_contig(pflags, 1, low, + high, alignment, boundary)) + vm_wait(NULL); + tries++; + goto retry; + } + + return (ENOMEM); + } + + if ((m->flags & PG_ZERO) == 0) + pmap_zero_page(m); + + va = PHYS_TO_DMAP(VM_PAGE_TO_PHYS(m)); + cpu_dcache_wb_range(va, PAGE_SIZE); + cpu_dcache_inv_range(va, PAGE_SIZE); + m->valid = VM_PAGE_BITS_ALL; + m->oflags &= ~VPO_UNMANAGED; + m->flags |= PG_FICTITIOUS; + + pages[i] = m; + } + + return (0); +} + +static int +tmc_enable(device_t dev) { struct tmc_softc *sc; uint32_t reg; sc = device_get_softc(dev); - if (bus_read_4(sc->res, TMC_CTL) & CTL_TRACECAPTEN) + if (sc->dev_type == CORESIGHT_ETR) { + dprintf("%s%d\n", __func__, device_get_unit(dev)); + } + + if (bus_read_4(sc->res[0], TMC_CTL) & CTL_TRACECAPTEN) return (-1); /* Enable TMC */ - bus_write_4(sc->res, TMC_CTL, CTL_TRACECAPTEN); - if ((bus_read_4(sc->res, TMC_CTL) & CTL_TRACECAPTEN) == 0) + bus_write_4(sc->res[0], TMC_CTL, CTL_TRACECAPTEN); + if ((bus_read_4(sc->res[0], TMC_CTL) & CTL_TRACECAPTEN) == 0) panic("Not enabled\n"); do { - reg = bus_read_4(sc->res, TMC_STS); + reg = bus_read_4(sc->res[0], TMC_STS); } while ((reg & STS_TMCREADY) == 1); - if ((bus_read_4(sc->res, TMC_CTL) & CTL_TRACECAPTEN) == 0) + if ((bus_read_4(sc->res[0], TMC_CTL) & CTL_TRACECAPTEN) == 0) panic("Not enabled\n"); + dprintf("%s: enabled\n", __func__); + return (0); } static int -tmc_stop(device_t dev) +tmc_disable(device_t dev) { struct tmc_softc *sc; uint32_t reg; sc = device_get_softc(dev); - reg = bus_read_4(sc->res, TMC_CTL); + dprintf("%s\n", __func__); + + reg = bus_read_4(sc->res[0], TMC_CTL); reg &= ~CTL_TRACECAPTEN; - bus_write_4(sc->res, TMC_CTL, reg); + bus_write_4(sc->res[0], TMC_CTL, reg); do { - reg = bus_read_4(sc->res, TMC_STS); + reg = bus_read_4(sc->res[0], TMC_STS); } while ((reg & STS_TMCREADY) == 1); return (0); } +static void +tmc_dump(device_t dev) +{ + struct tmc_softc *sc; + uint32_t reg; + size_t hi, lo; + size_t rrp, rwp; + + sc = device_get_softc(dev); + + lo = bus_read_4(sc->res[0], TMC_RRP); + hi = bus_read_4(sc->res[0], TMC_RRPHI); + rrp = lo | (hi << 32); + + lo = bus_read_4(sc->res[0], TMC_RWP); + hi = bus_read_4(sc->res[0], TMC_RWPHI); + rwp = lo | (hi << 32); + + reg = bus_read_4(sc->res[0], TMC_DEVID); + if ((reg & DEVID_CONFIGTYPE_M) == DEVID_CONFIGTYPE_ETR) + printf("%s%d: STS %x CTL %x RSZ %x RRP %lx RWP %lx AXICTL %x\n", + __func__, + device_get_unit(dev), + bus_read_4(sc->res[0], TMC_STS), + bus_read_4(sc->res[0], TMC_CTL), + bus_read_4(sc->res[0], TMC_RSZ), + rrp, rwp, + bus_read_4(sc->res[0], TMC_AXICTL)); +} + static int tmc_configure_etf(device_t dev) { @@ -112,23 +225,13 @@ sc = device_get_softc(dev); do { - reg = bus_read_4(sc->res, TMC_STS); + reg = bus_read_4(sc->res[0], TMC_STS); } while ((reg & STS_TMCREADY) == 0); - bus_write_4(sc->res, TMC_MODE, MODE_HW_FIFO); - bus_write_4(sc->res, TMC_FFCR, FFCR_EN_FMT | FFCR_EN_TI); + bus_write_4(sc->res[0], TMC_MODE, MODE_HW_FIFO); + bus_write_4(sc->res[0], TMC_FFCR, FFCR_EN_FMT | FFCR_EN_TI); - tmc_start(dev); - - dprintf("%s: STS %x, CTL %x, RSZ %x, RRP %x, RWP %x, " - "LBUFLEVEL %x, CBUFLEVEL %x\n", __func__, - bus_read_4(sc->res, TMC_STS), - bus_read_4(sc->res, TMC_CTL), - bus_read_4(sc->res, TMC_RSZ), - bus_read_4(sc->res, TMC_RRP), - bus_read_4(sc->res, TMC_RWP), - bus_read_4(sc->res, TMC_CBUFLEVEL), - bus_read_4(sc->res, TMC_LBUFLEVEL)); + tmc_enable(dev); return (0); } @@ -142,44 +245,180 @@ sc = device_get_softc(dev); - tmc_stop(dev); - do { - reg = bus_read_4(sc->res, TMC_STS); + reg = bus_read_4(sc->res[0], TMC_STS); } while ((reg & STS_TMCREADY) == 0); /* Configure TMC */ - bus_write_4(sc->res, TMC_MODE, MODE_CIRCULAR_BUFFER); + bus_write_4(sc->res[0], TMC_MODE, MODE_CIRCULAR_BUFFER); reg = AXICTL_PROT_CTRL_BIT1; reg |= AXICTL_WRBURSTLEN_16; - - /* - * SG operation is broken on DragonBoard 410c - * reg |= AXICTL_SG_MODE; - */ - - reg |= AXICTL_AXCACHE_OS; - bus_write_4(sc->res, TMC_AXICTL, reg); + if (sc->scatter_gather) + reg |= AXICTL_SG_MODE; + /* reg |= AXICTL_AXCACHE_OS; */ + bus_write_4(sc->res[0], TMC_AXICTL, reg); reg = FFCR_EN_FMT | FFCR_EN_TI | FFCR_FON_FLIN | FFCR_FON_TRIG_EVT | FFCR_TRIGON_TRIGIN; - bus_write_4(sc->res, TMC_FFCR, reg); + bus_write_4(sc->res[0], TMC_FFCR, reg); - bus_write_4(sc->res, TMC_TRG, 8); + bus_write_4(sc->res[0], TMC_TRG, 0x3ff); - bus_write_4(sc->res, TMC_DBALO, event->etr.low); - bus_write_4(sc->res, TMC_DBAHI, event->etr.high); - bus_write_4(sc->res, TMC_RSZ, event->etr.bufsize / 4); - - bus_write_4(sc->res, TMC_RRP, event->etr.low); - bus_write_4(sc->res, TMC_RWP, event->etr.low); + if (sc->scatter_gather) { + dprintf("%s: event->etr.pages %p\n", __func__, + event->etr.pages); + dprintf("%s: event->etr.npages %d\n", __func__, + event->etr.npages); + } else { + bus_write_4(sc->res[0], TMC_DBALO, event->etr.low); + bus_write_4(sc->res[0], TMC_DBAHI, event->etr.high); + bus_write_4(sc->res[0], TMC_RSZ, event->etr.bufsize / 4); + bus_write_4(sc->res[0], TMC_RRP, event->etr.low); + bus_write_4(sc->res[0], TMC_RWP, event->etr.low); + } - reg = bus_read_4(sc->res, TMC_STS); + reg = bus_read_4(sc->res[0], TMC_STS); reg &= ~STS_FULL; - bus_write_4(sc->res, TMC_STS, reg); + bus_write_4(sc->res[0], TMC_STS, reg); + + return (0); +} + +static vm_page_t * +tmc_allocate_pgdir(struct tmc_softc *sc, vm_page_t *pages, int nentries, + int npt) +{ + vm_page_t *pt_dir; + vm_paddr_t paddr; + int sgtentry; + sgte_t *ptr; + uint32_t dirpg; + int curpg; + int type; + int error; + int i; + + pt_dir = malloc(sizeof(struct vm_page *) * npt, M_DEVBUF, + M_WAITOK | M_ZERO); + error = tmc_alloc_pages(sc, pt_dir, npt); + if (error) { + printf("%s: could not allocate pages\n", __func__); + return (NULL); + } + + sgtentry = 0; + curpg = 0; + ptr = (sgte_t *)PHYS_TO_DMAP(VM_PAGE_TO_PHYS(pt_dir[0])); + dirpg = 1; + + for (i = 0; i < nentries - 1; i++) { + dprintf("entry %d dirpg %d\n", i, dirpg); + + if (sgtentry == (SG_PT_ENTIRES_PER_PAGE - 1)) { + type = ETR_SG_ET_LINK; + paddr = VM_PAGE_TO_PHYS(pt_dir[dirpg]); + } else { + type = ETR_SG_ET_NORMAL; + paddr = VM_PAGE_TO_PHYS(pages[curpg]); + +#ifdef TMC_DEBUG + if ((i % 100) == 0) + dprintf("%s: entry (%d/%d) type %d dirpg %d " + "curpg %d paddr %lx\n", __func__, i, + nentries, type, dirpg, curpg, paddr); +#endif + + curpg++; + } + + *ptr = ETR_SG_ENTRY(paddr, type); + cpu_dcache_wb_range((vm_pointer_t)ptr, sizeof(sgte_t)); + ptr++; + + /* Take next directory page. */ + if (type == ETR_SG_ET_LINK) { + ptr = (sgte_t *)PHYS_TO_DMAP( + VM_PAGE_TO_PHYS(pt_dir[dirpg])); + dirpg++; + } + + sgtentry = (sgtentry + 1) % SG_PT_ENTIRES_PER_PAGE; + } + + /* Last entry. */ + paddr = VM_PAGE_TO_PHYS(pages[curpg]); + *ptr = ETR_SG_ENTRY(paddr, ETR_SG_ET_LAST); + cpu_dcache_wb_range((vm_pointer_t)ptr, sizeof(sgte_t)); + + return (pt_dir); +} + +static int +tmc_configure(device_t dev, struct endpoint *endp, + struct coresight_event *event, struct hwt_thread *thr) +{ + + return (0); +} + +static int +tmc_setup(device_t dev, struct endpoint *endp, struct coresight_event *event) +{ + struct tmc_softc *sc; + vm_page_t *pt_dir; + vm_page_t *pages; + uint64_t pbase; + uint32_t reg; + int nentries; + int nlinks; + int npages; + int npt; - tmc_start(dev); + sc = device_get_softc(dev); + + reg = bus_read_4(sc->res[0], TMC_DEVID); + if ((reg & DEVID_CONFIGTYPE_M) != DEVID_CONFIGTYPE_ETR) + return (0); + + if (!sc->scatter_gather) + return (0); + + npages = event->etr.npages; + pages = event->etr.pages; + + if (npages == 0 || pages == NULL) + return (EINVAL); + + nlinks = npages / (SG_PT_ENTIRES_PER_PAGE - 1); + if (nlinks && ((npages % (SG_PT_ENTIRES_PER_PAGE - 1)) < 2)) + nlinks--; + nentries = nlinks + npages; + + npt = howmany(nentries, SG_PT_ENTIRES_PER_PAGE); + + dprintf("%s: nentries %d, npt %d\n", __func__, nentries, npt); + + pt_dir = tmc_allocate_pgdir(sc, pages, nentries, npt); + if (pt_dir == NULL) + return (ENOMEM); + +#ifdef TMC_DEBUG + ptr = (sgte_t *)PHYS_TO_DMAP(VM_PAGE_TO_PHYS(pt_dir[0])); + for (i = 0; i < nentries; i++) + dprintf("%s: entry %x\n", __func__, *ptr++); +#endif + + dprintf("%s: event->etr.pages %p\n", __func__, event->etr.pages); + dprintf("%s: event->etr.npages %d\n", __func__, event->etr.npages); + + pbase = (uint64_t)VM_PAGE_TO_PHYS(pt_dir[0]); + + dprintf("%s: pbase %lx\n", __func__, pbase); + + bus_write_4(sc->res[0], TMC_DBALO, pbase & 0xffffffff); + bus_write_4(sc->res[0], TMC_DBAHI, pbase >> 32); + bus_write_4(sc->res[0], TMC_RSZ, (event->etr.npages * 4096) / 4); return (0); } @@ -193,12 +432,12 @@ sc = device_get_softc(dev); /* Unlock Coresight */ - bus_write_4(sc->res, CORESIGHT_LAR, CORESIGHT_UNLOCK); + bus_write_4(sc->res[0], CORESIGHT_LAR, CORESIGHT_UNLOCK); /* Unlock TMC */ - bus_write_4(sc->res, TMC_LAR, CORESIGHT_UNLOCK); + bus_write_4(sc->res[0], TMC_LAR, CORESIGHT_UNLOCK); - reg = bus_read_4(sc->res, TMC_DEVID); + reg = bus_read_4(sc->res[0], TMC_DEVID); reg &= DEVID_CONFIGTYPE_M; switch (reg) { case DEVID_CONFIGTYPE_ETR: @@ -222,94 +461,88 @@ } static int -tmc_enable(device_t dev, struct endpoint *endp, - struct coresight_event *event) +tmc_start(device_t dev, struct endpoint *endp, struct coresight_event *event) { struct tmc_softc *sc; - uint32_t nev; sc = device_get_softc(dev); if (sc->dev_type == CORESIGHT_ETF) return (0); - KASSERT(sc->dev_type == CORESIGHT_ETR, - ("Wrong dev_type")); - - /* - * Multiple CPUs can call this same time. - * We allow only one running configuration. - */ - - if (event->etr.flags & ETR_FLAG_ALLOCATE) { - event->etr.flags &= ~ETR_FLAG_ALLOCATE; - nev = atomic_fetchadd_int(&sc->nev, 1); - if (nev == 0) { - sc->event = event; - tmc_stop(dev); - tmc_configure_etr(dev, endp, event); - tmc_start(dev); - } - } + KASSERT(sc->dev_type == CORESIGHT_ETR, ("Wrong dev_type")); + + tmc_configure_etr(dev, endp, event); + tmc_enable(dev); return (0); } -static void -tmc_disable(device_t dev, struct endpoint *endp, - struct coresight_event *event) +static int +tmc_read(device_t dev, struct endpoint *endp, struct coresight_event *event) { struct tmc_softc *sc; - uint32_t nev; + vm_page_t page; + bool found; + uint64_t lo, hi; + uint64_t ptr; + int i; sc = device_get_softc(dev); - - /* ETF configuration is static */ if (sc->dev_type == CORESIGHT_ETF) - return; + return (0); - KASSERT(sc->dev_type == CORESIGHT_ETR, ("Wrong dev_type")); + lo = bus_read_4(sc->res[0], TMC_RWP); + hi = bus_read_4(sc->res[0], TMC_RWPHI); + ptr = lo | (hi << 32); + + page = PHYS_TO_VM_PAGE(ptr); + + found = false; - if (event->etr.flags & ETR_FLAG_RELEASE) { - event->etr.flags &= ~ETR_FLAG_RELEASE; - nev = atomic_fetchadd_int(&sc->nev, -1); - if (nev == 1) { - tmc_stop(dev); - sc->event = NULL; + for (i = 0; i < event->etr.npages; i++) { + if (event->etr.pages[i] == page) { + found = true; + break; } } + + if (found) { + event->etr.curpage = i; + event->etr.curpage_offset = ptr & 0xfff; + dprintf("CUR_PTR %lx, page %d of %d, offset %ld\n", + ptr, i, event->etr.npages, event->etr.curpage_offset); + } + + return (0); } -static int -tmc_read(device_t dev, struct endpoint *endp, - struct coresight_event *event) +static void +tmc_stop(device_t dev, struct endpoint *endp, struct coresight_event *event) { struct tmc_softc *sc; - uint32_t cur_ptr; sc = device_get_softc(dev); + /* ETF configuration is static */ if (sc->dev_type == CORESIGHT_ETF) - return (0); + return; - /* - * Ensure the event we are reading information for - * is currently configured one. - */ - if (sc->event != event) - return (0); + KASSERT(sc->dev_type == CORESIGHT_ETR, ("Wrong dev_type")); - if (bus_read_4(sc->res, TMC_STS) & STS_FULL) { - event->etr.offset = 0; - event->etr.cycle++; - tmc_stop(dev); - tmc_start(dev); - } else { - cur_ptr = bus_read_4(sc->res, TMC_RWP); - event->etr.offset = (cur_ptr - event->etr.low); - } + /* Make final readings before stopping TMC. */ + tmc_read(dev, endp, event); - return (0); + tmc_disable(dev); +} + +static void +tmc_intr(void *arg) +{ + + /* TODO */ + + panic("unhandled interrupt"); } int @@ -317,18 +550,36 @@ { struct coresight_desc desc; struct tmc_softc *sc; + uint32_t reg; sc = device_get_softc(dev); sc->dev = dev; - if (bus_alloc_resources(dev, tmc_spec, &sc->res) != 0) { + if (bus_alloc_resources(dev, tmc_spec, sc->res) != 0) { device_printf(dev, "cannot allocate resources for device\n"); return (ENXIO); } + if (sc->res[1] != NULL) { + if (bus_setup_intr(dev, sc->res[1], + INTR_TYPE_MISC | INTR_MPSAFE, NULL, tmc_intr, sc, + &sc->intrhand)) { + bus_release_resources(dev, tmc_spec, sc->res); + device_printf(dev, "cannot setup interrupt handler\n"); + return (ENXIO); + } + } + desc.pdata = sc->pdata; desc.dev = dev; - desc.dev_type = CORESIGHT_TMC; + + reg = bus_read_4(sc->res[0], TMC_DEVID); + reg &= DEVID_CONFIGTYPE_M; + if (reg == DEVID_CONFIGTYPE_ETR) + desc.dev_type = CORESIGHT_TMC_ETR; + else + desc.dev_type = CORESIGHT_TMC_ETF; + coresight_register(&desc); return (0); @@ -340,8 +591,11 @@ /* Coresight interface */ DEVMETHOD(coresight_init, tmc_init), - DEVMETHOD(coresight_enable, tmc_enable), - DEVMETHOD(coresight_disable, tmc_disable), + DEVMETHOD(coresight_setup, tmc_setup), + DEVMETHOD(coresight_configure, tmc_configure), + DEVMETHOD(coresight_start, tmc_start), + DEVMETHOD(coresight_stop, tmc_stop), + DEVMETHOD(coresight_dump, tmc_dump), DEVMETHOD(coresight_read, tmc_read), DEVMETHOD_END }; Index: sys/arm64/coresight/coresight_tmc_fdt.c =================================================================== --- sys/arm64/coresight/coresight_tmc_fdt.c +++ sys/arm64/coresight/coresight_tmc_fdt.c @@ -71,10 +71,20 @@ tmc_fdt_attach(device_t dev) { struct tmc_softc *sc; + phandle_t node; + ssize_t len; sc = device_get_softc(dev); sc->pdata = coresight_fdt_get_platform_data(dev); + node = ofw_bus_get_node(dev); + + len = OF_getproplen(node, "arm,scatter-gather"); + if (len >= 0) + sc->scatter_gather = true; + else + sc->scatter_gather = false; + return (tmc_attach(dev)); } Index: sys/conf/files.arm64 =================================================================== --- sys/conf/files.arm64 +++ sys/conf/files.arm64 @@ -139,24 +139,24 @@ # ANX6345 RGB to eDP bridge dev/drm/bridges/anx6345/anx6345.c optional fdt anx6345 compile-with "${DRM_C}" -arm64/coresight/coresight.c standard -arm64/coresight/coresight_acpi.c optional acpi -arm64/coresight/coresight_fdt.c optional fdt -arm64/coresight/coresight_if.m standard -arm64/coresight/coresight_cmd.c standard -arm64/coresight/coresight_cpu_debug.c optional fdt -arm64/coresight/coresight_etm4x.c standard -arm64/coresight/coresight_etm4x_acpi.c optional acpi -arm64/coresight/coresight_etm4x_fdt.c optional fdt -arm64/coresight/coresight_funnel.c standard -arm64/coresight/coresight_funnel_acpi.c optional acpi -arm64/coresight/coresight_funnel_fdt.c optional fdt -arm64/coresight/coresight_replicator.c standard -arm64/coresight/coresight_replicator_acpi.c optional acpi -arm64/coresight/coresight_replicator_fdt.c optional fdt -arm64/coresight/coresight_tmc.c standard -arm64/coresight/coresight_tmc_acpi.c optional acpi -arm64/coresight/coresight_tmc_fdt.c optional fdt +arm64/coresight/coresight.c optional hwt +arm64/coresight/coresight_acpi.c optional hwt acpi +arm64/coresight/coresight_fdt.c optional hwt fdt +arm64/coresight/coresight_if.m optional hwt +arm64/coresight/coresight_cmd.c optional hwt +arm64/coresight/coresight_cpu_debug.c optional hwt fdt +arm64/coresight/coresight_etm4x.c optional hwt +arm64/coresight/coresight_etm4x_acpi.c optional hwt acpi +arm64/coresight/coresight_etm4x_fdt.c optional hwt fdt +arm64/coresight/coresight_funnel.c optional hwt +arm64/coresight/coresight_funnel_acpi.c optional hwt acpi +arm64/coresight/coresight_funnel_fdt.c optional hwt fdt +arm64/coresight/coresight_replicator.c optional hwt +arm64/coresight/coresight_replicator_acpi.c optional hwt acpi +arm64/coresight/coresight_replicator_fdt.c optional hwt fdt +arm64/coresight/coresight_tmc.c optional hwt +arm64/coresight/coresight_tmc_acpi.c optional hwt acpi +arm64/coresight/coresight_tmc_fdt.c optional hwt fdt dev/smbios/smbios_subr.c standard Index: sys/dts/arm64/arm/morello-coresight.dtsi =================================================================== --- /dev/null +++ sys/dts/arm64/arm/morello-coresight.dtsi @@ -0,0 +1,349 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include + +/ { + cpu_debug0: cpu-debug@402010000 { + compatible = "arm,coresight-cpu-debug", "arm,primecell"; + cpu = <&cpu0>; + reg = <0x4 0x02010000 0x0 0x1000>; + }; + + etm0: etm@402040000 { + compatible = "arm,coresight-etm4x", "arm,primecell"; + cpu = <&cpu0>; + reg = <0x4 0x02040000 0 0x1000>; + + out-ports { + port { + cluster0_etm0_out_port: endpoint { + remote-endpoint = <&cluster0_static_funnel_in_port0>; + }; + }; + }; + }; + + cpu_debug1: cpu-debug@402110000 { + compatible = "arm,coresight-cpu-debug", "arm,primecell"; + cpu = <&cpu1>; + reg = <0x4 0x02110000 0x0 0x1000>; + }; + etm1: etm@402140000 { + compatible = "arm,coresight-etm4x", "arm,primecell"; + cpu = <&cpu1>; + reg = <0x4 0x02140000 0 0x1000>; + + out-ports { + port { + cluster0_etm1_out_port: endpoint { + remote-endpoint = <&cluster0_static_funnel_in_port1>; + }; + }; + }; + }; + + cpu_debug2: cpu-debug@403010000 { + compatible = "arm,coresight-cpu-debug", "arm,primecell"; + cpu = <&cpu2>; + reg = <0x4 0x03010000 0x0 0x1000>; + }; + + etm2: etm@403040000 { + compatible = "arm,coresight-etm4x", "arm,primecell"; + cpu = <&cpu2>; + reg = <0x4 0x03040000 0 0x1000>; + + out-ports { + port { + cluster1_etm0_out_port: endpoint { + remote-endpoint = <&cluster1_static_funnel_in_port0>; + }; + }; + }; + }; + + cpu_debug3: cpu-debug@403110000 { + compatible = "arm,coresight-cpu-debug", "arm,primecell"; + cpu = <&cpu3>; + reg = <0x4 0x03110000 0x0 0x1000>; + }; + + etm3: etm@403140000 { + compatible = "arm,coresight-etm4x", "arm,primecell"; + cpu = <&cpu3>; + reg = <0x4 0x03140000 0 0x1000>; + + out-ports { + port { + cluster1_etm1_out_port: endpoint { + remote-endpoint = <&cluster1_static_funnel_in_port1>; + }; + }; + }; + }; + + sfunnel0: funnel@0 { + compatible = "arm,coresight-static-funnel"; + + out-ports { + port { + cluster0_static_funnel_out_port: endpoint { + remote-endpoint = <&etf0_in_port>; + }; + }; + }; + + in-ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + cluster0_static_funnel_in_port0: endpoint { + remote-endpoint = <&cluster0_etm0_out_port>; + }; + }; + + port@1 { + reg = <1>; + cluster0_static_funnel_in_port1: endpoint { + remote-endpoint = <&cluster0_etm1_out_port>; + }; + }; + }; + }; + + sfunnel1: funnel@1 { + compatible = "arm,coresight-static-funnel"; + + out-ports { + port { + cluster1_static_funnel_out_port: endpoint { + remote-endpoint = <&etf1_in_port>; + }; + }; + }; + + in-ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + cluster1_static_funnel_in_port0: endpoint { + remote-endpoint = <&cluster1_etm0_out_port>; + }; + }; + + port@1 { + reg = <1>; + cluster1_static_funnel_in_port1: endpoint { + remote-endpoint = <&cluster1_etm1_out_port>; + }; + }; + }; + }; + + tpiu@400130000 { + compatible = "arm,coresight-tpiu", "arm,primecell"; + reg = <0x4 0x00130000 0 0x1000>; + + in-ports { + port { + tpiu_in_port: endpoint { + remote-endpoint = <&replicator_out_port0>; + }; + }; + }; + }; + + master_funnel: funnel@4000a0000 { + compatible = "arm,coresight-dynamic-funnel", "arm,primecell"; + reg = <0x4 0x000a0000 0 0x1000>; + + out-ports { + port { + master_funnel_out_port: endpoint { + remote-endpoint = <&replicator_in_port>; + }; + }; + }; + + master_funnel_in_ports: in-ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + master_funnel_in_port0: endpoint { + remote-endpoint = <&cluster_funnel_out_port>; + }; + }; + + port@5 { + reg = <5>; + master_funnel_in_port5: endpoint { + remote-endpoint = <&etf2_out_port>; + }; + }; + }; + }; + + etr@400120000 { + compatible = "arm,coresight-tmc", "arm,primecell"; + reg = <0x4 0x00120000 0 0x1000>; + interrupts = ; + interrupt-names = "etrbufint"; + + arm,scatter-gather; + in-ports { + port { + etr_in_port: endpoint { + remote-endpoint = <&replicator_out_port1>; + }; + }; + }; + }; + + replicator@400110000 { + compatible = "arm,coresight-dynamic-replicator", "arm,primecell"; + reg = <0x4 0x00110000 0 0x1000>; + + out-ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + replicator_out_port0: endpoint { + remote-endpoint = <&tpiu_in_port>; + }; + }; + + port@1 { + reg = <1>; + replicator_out_port1: endpoint { + remote-endpoint = <&etr_in_port>; + }; + }; + }; + in-ports { + port { + replicator_in_port: endpoint { + remote-endpoint = <&master_funnel_out_port>; + }; + }; + }; + }; + + cluster_funnel: funnel@4000b0000 { + compatible = "arm,coresight-dynamic-funnel", "arm,primecell"; + reg = <0x4 0x000b0000 0 0x1000>; + + out-ports { + port { + cluster_funnel_out_port: endpoint { + remote-endpoint = <&master_funnel_in_port0>; + }; + }; + }; + + in-ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + cluster_funnel_in_port0: endpoint { + remote-endpoint = <&etf0_out_port>; + }; + }; + + port@1 { + reg = <1>; + cluster_funnel_in_port1: endpoint { + remote-endpoint = <&etf1_out_port>; + }; + }; + }; + }; + + etf0: etf@400410000 { + compatible = "arm,coresight-tmc", "arm,primecell"; + reg = <0x4 0x00410000 0 0x1000>; + + in-ports { + port { + etf0_in_port: endpoint { + remote-endpoint = <&cluster0_static_funnel_out_port>; + }; + }; + }; + + out-ports { + port { + etf0_out_port: endpoint { + remote-endpoint = <&cluster_funnel_in_port0>; + }; + }; + }; + }; + + etf1: etf@400420000 { + compatible = "arm,coresight-tmc", "arm,primecell"; + reg = <0x4 0x00420000 0 0x1000>; + + in-ports { + port { + etf1_in_port: endpoint { + remote-endpoint = <&cluster1_static_funnel_out_port>; + }; + }; + }; + + out-ports { + port { + etf1_out_port: endpoint { + remote-endpoint = <&cluster_funnel_in_port1>; + }; + }; + }; + }; + + stm_etf: etf@400010000 { + compatible = "arm,coresight-tmc", "arm,primecell"; + reg = <0x4 0x00010000 0 0x1000>; + + in-ports { + port { + etf2_in_port: endpoint { + remote-endpoint = <&stm_out_port>; + }; + }; + }; + + out-ports { + port { + etf2_out_port: endpoint { + remote-endpoint = <&master_funnel_in_port5>; + }; + }; + }; + }; + + stm@400800000 { + compatible = "arm,coresight-stm", "arm,primecell"; + reg = <4 0x00800000 0 0x1000>, + <0 0x4d000000 0 0x1000000>; + reg-names = "stm-base", "stm-stimulus-base"; + + out-ports { + port { + stm_out_port: endpoint { + remote-endpoint = <&etf2_in_port>; + }; + }; + }; + }; +}; Index: sys/dts/arm64/arm/morello-soc.dts =================================================================== --- sys/dts/arm64/arm/morello-soc.dts +++ sys/dts/arm64/arm/morello-soc.dts @@ -6,6 +6,7 @@ /dts-v1/; #include "morello.dtsi" +#include "morello-coresight.dtsi" / { @@ -27,28 +28,28 @@ cpus { #address-cells = <2>; #size-cells = <0>; - cpu0@0 { + cpu0: cpu0@0 { compatible = "arm,armv8"; reg = <0x0 0x0>; device_type = "cpu"; enable-method = "psci"; clocks = <&scmi_dvfs 0>; }; - cpu1@100 { + cpu1: cpu1@100 { compatible = "arm,armv8"; reg = <0x0 0x100>; device_type = "cpu"; enable-method = "psci"; clocks = <&scmi_dvfs 0>; }; - cpu2@10000 { + cpu2: cpu2@10000 { compatible = "arm,armv8"; reg = <0x0 0x10000>; device_type = "cpu"; enable-method = "psci"; clocks = <&scmi_dvfs 1>; }; - cpu3@10100 { + cpu3: cpu3@10100 { compatible = "arm,armv8"; reg = <0x0 0x10100>; device_type = "cpu";