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 @@ -46,6 +46,8 @@ #include #endif +#include + #define CORESIGHT_ITCTRL 0xf00 #define CORESIGHT_CLAIMSET 0xfa0 #define CORESIGHT_CLAIMCLR 0xfa4 @@ -58,7 +60,8 @@ enum cs_dev_type { CORESIGHT_ETMV4, - CORESIGHT_TMC, + CORESIGHT_TMC_ETF, + CORESIGHT_TMC_ETR, CORESIGHT_DYNAMIC_REPLICATOR, CORESIGHT_FUNNEL, CORESIGHT_CPU_DEBUG, @@ -90,7 +93,7 @@ boolean_t input; int reg; struct coresight_device *cs_dev; - LIST_ENTRY(endpoint) endplink; + TAILQ_ENTRY(endpoint) endplink; }; struct coresight_platform_data { @@ -117,19 +120,20 @@ }; 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; + + vm_page_t *pt_dir; + int npt; }; -struct coresight_event { - LIST_HEAD(, endpoint) endplist; +struct coresight_pipeline { + TAILQ_HEAD(endplistname, endpoint) endplist; uint64_t addr[ETM_N_COMPRATOR]; uint32_t naddr; @@ -147,16 +151,36 @@ 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); +void coresight_fdt_release_platform_data(struct coresight_platform_data *pdata); + 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_pipeline(struct coresight_pipeline *pipeline, int cpu); +void coresight_deinit_pipeline(struct coresight_pipeline *pipeline); + +int coresight_setup(struct coresight_pipeline *pipeline); +int coresight_configure(struct coresight_pipeline *pipeline, + struct hwt_context *ctx); +void coresight_deconfigure(struct coresight_pipeline *pipeline); + +int coresight_start(struct coresight_pipeline *pipeline); +void coresight_stop(struct coresight_pipeline *pipeline); + +void coresight_enable(struct coresight_pipeline *pipeline); +void coresight_disable(struct coresight_pipeline *pipeline); + +int coresight_read(struct coresight_pipeline *pipeline); +void coresight_dump(struct coresight_pipeline *pipeline); + +int coresight_unregister(device_t dev); #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 @@ -36,17 +36,282 @@ #include #include #include +#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_pipeline cs_pipeline[MAXCPU]; + +/* + * Example pipeline (SoC-dependent). + * https://people.freebsd.org/~br/coresight_diagram.png + */ + +static int +coresight_backend_init_thread(struct hwt_context *ctx) +{ + struct coresight_pipeline *pipeline; + struct hwt_thread *thr; + struct hwt_vm *vm; + int cpu_id; + int error; + + /* + * 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); + + vm = thr->vm; + + for (cpu_id = 0; cpu_id < mp_ncpus; cpu_id++) { + pipeline = &cs_pipeline[cpu_id]; + memset(pipeline, 0, sizeof(struct coresight_pipeline)); + pipeline->excp_level = 0; + pipeline->src = CORESIGHT_ETMV4; + pipeline->sink = CORESIGHT_TMC_ETR; + + error = coresight_init_pipeline(pipeline, cpu_id); + if (error) + return (error); + } + + /* + * These methods are TMC-ETR only. We have single + * TMC-ETR per system, so call them on first pipeline + * only. The request will reach destination. + */ + pipeline = &cs_pipeline[0]; + pipeline->etr.low = 0; + pipeline->etr.high = 0; + pipeline->etr.pages = vm->pages; + pipeline->etr.npages = vm->npages; + pipeline->etr.bufsize = vm->npages * PAGE_SIZE; + + error = coresight_setup(pipeline); + if (error) + return (error); + + error = coresight_start(pipeline); + if (error) + return (error); + + return (0); +} + +static int +coresight_backend_init_cpu(struct hwt_context *ctx) +{ + struct coresight_pipeline *pipeline; + struct hwt_vm *vm; + int error; + int cpu_id; + + CPU_FOREACH(cpu_id) { + pipeline = &cs_pipeline[cpu_id]; + memset(pipeline, 0, sizeof(struct coresight_pipeline)); + + pipeline->excp_level = 1; + pipeline->src = CORESIGHT_ETMV4; + pipeline->sink = CORESIGHT_TMC_ETR; + + error = coresight_init_pipeline(pipeline, cpu_id); + if (error) + return (error); + } + + /* + * The following is TMC (ETR) only, so pick vm from the first CPU. + */ + pipeline = &cs_pipeline[0]; + + HWT_CTX_LOCK(ctx); + vm = hwt_cpu_first(ctx)->vm; + HWT_CTX_UNLOCK(ctx); + + /* TMC(ETR) configuration. */ + pipeline->etr.low = 0; + pipeline->etr.high = 0; + pipeline->etr.pages = vm->pages; + pipeline->etr.npages = vm->npages; + pipeline->etr.bufsize = vm->npages * PAGE_SIZE; + + error = coresight_setup(pipeline); + if (error) + return (error); + + error = coresight_start(pipeline); + if (error) + return (error); + + return (0); +} + +static int +coresight_backend_init(struct hwt_context *ctx) +{ + int error; + + /* Coresight does not require kva, since TMC uses raw pages */ + ctx->kva_req = 0; + + if (ctx->mode == HWT_MODE_THREAD) + error = coresight_backend_init_thread(ctx); + else + error = coresight_backend_init_cpu(ctx); + + return (error); +} + +static void +coresight_backend_deinit(struct hwt_context *ctx) +{ + struct coresight_pipeline *pipeline; + int cpu_id; + + for (cpu_id = 0; cpu_id < mp_ncpus; cpu_id++) { + pipeline = &cs_pipeline[cpu_id]; + coresight_disable(pipeline); + } + + /* Now as TMC-ETF buffers flushed, stop TMC-ETR. */ + pipeline = &cs_pipeline[0]; + coresight_stop(pipeline); + + for (cpu_id = 0; cpu_id < mp_ncpus; cpu_id++) { + pipeline = &cs_pipeline[cpu_id]; + coresight_deinit_pipeline(pipeline); + } +} + +static int +coresight_backend_configure(struct hwt_context *ctx, int cpu_id, int session_id) +{ + struct coresight_pipeline *pipeline; + int error; + + pipeline = &cs_pipeline[cpu_id]; + + /* + * OpenCSD needs a trace ID to distinguish trace sessions + * as they are merged to a single buffer by using funnel + * device. + * + * etmv4 session_id can't be 0. + */ + pipeline->etm.trace_id = session_id + 1; + + error = coresight_configure(pipeline, ctx); + + return (error); +} + +static void +coresight_backend_enable(struct hwt_context *ctx, int cpu_id) +{ + struct coresight_pipeline *pipeline; + + pipeline = &cs_pipeline[cpu_id]; + + coresight_enable(pipeline); +} + +static void +coresight_backend_disable(struct hwt_context *ctx, int cpu_id) +{ + struct coresight_pipeline *pipeline; + + pipeline = &cs_pipeline[cpu_id]; + + coresight_disable(pipeline); +} + +static int +coresight_backend_read(int cpu_id, int *curpage, vm_offset_t *curpage_offset) +{ + struct coresight_pipeline *pipeline; + int error; + + /* + * coresight_read() is TMC(ETR) only method. Also, we have a single + * TMC(ETR) per system configured from pipeline 0. So read data from + * pipeline 0. + */ + + pipeline = &cs_pipeline[0]; + + KASSERT(pipeline != NULL, ("No pipeline found")); + + error = coresight_read(pipeline); + if (error == 0) { + *curpage = pipeline->etr.curpage; + *curpage_offset = pipeline->etr.curpage_offset; + } + + return (error); +} + +static void +coresight_backend_dump(int cpu_id) +{ + struct coresight_pipeline *pipeline; + + pipeline = &cs_pipeline[cpu_id]; + + coresight_dump(pipeline); +} + +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) { struct coresight_device *cs_dev; + int error; cs_dev = malloc(sizeof(struct coresight_device), M_CORESIGHT, M_WAITOK | M_ZERO); @@ -54,6 +319,14 @@ cs_dev->pdata = desc->pdata; cs_dev->dev_type = desc->dev_type; + if (desc->dev_type == CORESIGHT_TMC_ETR) { + error = hwt_backend_register(&backend); + if (error != 0) { + free(cs_dev, M_CORESIGHT); + return (error); + } + } + mtx_lock(&cs_mtx); TAILQ_INSERT_TAIL(&cs_devs, cs_dev, link); mtx_unlock(&cs_mtx); @@ -61,6 +334,27 @@ return (0); } +int +coresight_unregister(device_t dev) +{ + struct coresight_device *cs_dev, *tmp; + + mtx_lock(&cs_mtx); + TAILQ_FOREACH_SAFE(cs_dev, &cs_devs, link, tmp) { + if (cs_dev->dev == dev) { + TAILQ_REMOVE(&cs_devs, cs_dev, link); + mtx_unlock(&cs_mtx); + if (cs_dev->dev_type == CORESIGHT_TMC_ETR) + hwt_backend_unregister(&backend); + free(cs_dev, M_CORESIGHT); + return (0); + } + } + mtx_unlock(&cs_mtx); + + return (ENOENT); +} + struct endpoint * coresight_get_output_endpoint(struct coresight_platform_data *pdata) { @@ -78,7 +372,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; @@ -91,7 +386,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 @@ -100,7 +399,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 @@ -112,12 +415,31 @@ return (NULL); } -static void -coresight_init(void) +static int +coresight_modevent(module_t mod, int type, void *data) { - mtx_init(&cs_mtx, "ARM Coresight", NULL, MTX_DEF); - TAILQ_INIT(&cs_devs); + switch (type) { + case MOD_LOAD: + mtx_init(&cs_mtx, "ARM Coresight", NULL, MTX_DEF); + TAILQ_INIT(&cs_devs); + break; + case MOD_UNLOAD: + mtx_destroy(&cs_mtx); + break; + default: + break; + } + + return (0); } -SYSINIT(coresight, SI_SUB_DRIVERS, SI_ORDER_FIRST, coresight_init, NULL); +static moduledata_t coresight_mod = { + "coresight", + coresight_modevent, + NULL +}; + +DECLARE_MODULE(coresight, coresight_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST); +MODULE_DEPEND(coresight, hwt, 1, 1, 1); +MODULE_VERSION(coresight, 1); 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 @@ -44,22 +44,27 @@ static struct coresight_device * coresight_next_device(struct coresight_device *cs_dev, - struct coresight_event *event) + struct coresight_pipeline *pipeline) { struct coresight_device *out; - struct endpoint *out_endp; + struct endpoint *out_endp, *src_endp; struct endpoint *endp; TAILQ_FOREACH(endp, &cs_dev->pdata->endpoints, link) { 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)) { + if (TAILQ_EMPTY(&pipeline->endplist)) { + /* Add source device */ - endp->cs_dev = cs_dev; - LIST_INSERT_HEAD(&event->endplist, endp, + src_endp = malloc(sizeof(struct endpoint), + M_CORESIGHT, M_WAITOK | M_ZERO); + memcpy(src_endp, endp, sizeof(struct endpoint)); + + src_endp->cs_dev = cs_dev; + TAILQ_INSERT_TAIL(&pipeline->endplist, src_endp, endplink); } @@ -68,7 +73,8 @@ printf("Adding device %s to the chain\n", device_get_nameunit(out->dev)); out_endp->cs_dev = out; - LIST_INSERT_HEAD(&event->endplist, out_endp, endplink); + TAILQ_INSERT_TAIL(&pipeline->endplist, out_endp, + endplink); return (out); } @@ -78,30 +84,31 @@ } static int -coresight_build_list(struct coresight_device *cs_dev, - struct coresight_event *event) +coresight_build_pipeline(struct coresight_device *cs_dev, + struct coresight_pipeline *pipeline) { struct coresight_device *out; out = cs_dev; while (out != NULL) - out = coresight_next_device(out, event); + out = coresight_next_device(out, pipeline); return (0); } int -coresight_init_event(int cpu, struct coresight_event *event) +coresight_init_pipeline(struct coresight_pipeline *pipeline, int cpu) { struct coresight_device *cs_dev; struct endpoint *endp; + int error; /* Start building path from source device */ TAILQ_FOREACH(cs_dev, &cs_devs, link) { - if (cs_dev->dev_type == event->src && + if (cs_dev->dev_type == pipeline->src && cs_dev->pdata->cpu == cpu) { - LIST_INIT(&event->endplist); - coresight_build_list(cs_dev, event); + TAILQ_INIT(&pipeline->endplist); + coresight_build_pipeline(cs_dev, pipeline); break; } } @@ -109,48 +116,153 @@ /* Ensure Coresight is initialized for the CPU */ TAILQ_FOREACH(cs_dev, &cs_devs, link) { if (cs_dev->dev_type == CORESIGHT_CPU_DEBUG && - cs_dev->pdata->cpu == cpu) - CORESIGHT_INIT(cs_dev->dev); + cs_dev->pdata->cpu == cpu) { + error = CORESIGHT_INIT(cs_dev->dev); + if (error != ENXIO && error != 0) + return (error); + } } /* Init all devices in the path */ - LIST_FOREACH(endp, &event->endplist, endplink) { + TAILQ_FOREACH(endp, &pipeline->endplist, endplink) { cs_dev = endp->cs_dev; - CORESIGHT_INIT(cs_dev->dev); + error = CORESIGHT_INIT(cs_dev->dev); + if (error != ENXIO && error != 0) + return (error); } return (0); } void -coresight_enable(int cpu, struct coresight_event *event) +coresight_deinit_pipeline(struct coresight_pipeline *pipeline) +{ + struct coresight_device *cs_dev; + struct endpoint *endp, *tmp; + + TAILQ_FOREACH_SAFE(endp, &pipeline->endplist, endplink, tmp) { + cs_dev = endp->cs_dev; + CORESIGHT_DEINIT(cs_dev->dev); + + TAILQ_REMOVE(&pipeline->endplist, endp, endplink); + free(endp, M_CORESIGHT); + } +} + +int +coresight_setup(struct coresight_pipeline *pipeline) { struct coresight_device *cs_dev; struct endpoint *endp; + int error; - LIST_FOREACH(endp, &event->endplist, endplink) { + TAILQ_FOREACH(endp, &pipeline->endplist, endplink) { cs_dev = endp->cs_dev; - CORESIGHT_ENABLE(cs_dev->dev, endp, event); + error = CORESIGHT_SETUP(cs_dev->dev, endp, pipeline); + if (error != ENXIO && error != 0) + return (error); + } + + return (0); +} + +int +coresight_configure(struct coresight_pipeline *pipeline, + struct hwt_context *ctx) +{ + struct coresight_device *cs_dev; + struct endpoint *endp; + int error; + + TAILQ_FOREACH(endp, &pipeline->endplist, endplink) { + cs_dev = endp->cs_dev; + error = CORESIGHT_CONFIGURE(cs_dev->dev, endp, pipeline, ctx); + if (error != ENXIO && error != 0) + return (error); + } + + return (0); +} + +int +coresight_start(struct coresight_pipeline *pipeline) +{ + struct coresight_device *cs_dev; + struct endpoint *endp; + int error; + + TAILQ_FOREACH_REVERSE(endp, &pipeline->endplist, endplistname, + endplink) { + cs_dev = endp->cs_dev; + error = CORESIGHT_START(cs_dev->dev, endp, pipeline); + if (error != ENXIO && error != 0) + return (error); + } + + return (0); +} + +void +coresight_stop(struct coresight_pipeline *pipeline) +{ + struct coresight_device *cs_dev; + struct endpoint *endp; + + TAILQ_FOREACH(endp, &pipeline->endplist, endplink) { + cs_dev = endp->cs_dev; + CORESIGHT_STOP(cs_dev->dev, endp, pipeline); + } +} + +void +coresight_enable(struct coresight_pipeline *pipeline) +{ + struct coresight_device *cs_dev; + struct endpoint *endp; + + TAILQ_FOREACH(endp, &pipeline->endplist, endplink) { + cs_dev = endp->cs_dev; + CORESIGHT_ENABLE(cs_dev->dev, endp, pipeline); } } void -coresight_disable(int cpu, struct coresight_event *event) +coresight_disable(struct coresight_pipeline *pipeline) { struct coresight_device *cs_dev; struct endpoint *endp; - LIST_FOREACH(endp, &event->endplist, endplink) { + TAILQ_FOREACH(endp, &pipeline->endplist, endplink) { cs_dev = endp->cs_dev; - CORESIGHT_DISABLE(cs_dev->dev, endp, event); + CORESIGHT_DISABLE(cs_dev->dev, endp, pipeline); } } void -coresight_read(int cpu, struct coresight_event *event) +coresight_dump(struct coresight_pipeline *pipeline) { + struct coresight_device *cs_dev; struct endpoint *endp; - LIST_FOREACH(endp, &event->endplist, endplink) - CORESIGHT_READ(endp->cs_dev->dev, endp, event); + TAILQ_FOREACH(endp, &pipeline->endplist, endplink) { + cs_dev = endp->cs_dev; + CORESIGHT_DUMP(cs_dev->dev); + } +} + +int +coresight_read(struct coresight_pipeline *pipeline) +{ + struct coresight_device *cs_dev; + struct endpoint *endp; + int error; + + TAILQ_FOREACH(endp, &pipeline->endplist, endplink) { + cs_dev = endp->cs_dev; + error = CORESIGHT_READ(cs_dev->dev, endp, pipeline); + if (error != ENXIO && error != 0) + return (error); + } + + return (0); } Index: sys/arm64/coresight/coresight_cpu_debug.c =================================================================== --- sys/arm64/coresight/coresight_cpu_debug.c +++ sys/arm64/coresight/coresight_cpu_debug.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,6 +76,7 @@ { struct debug_softc *sc; uint32_t reg; + int timeout; sc = device_get_softc(dev); @@ -94,9 +95,14 @@ reg |= EDPRCR_COREPURQ; bus_write_4(sc->res, EDPRCR, reg); + timeout = 10000; + do { reg = bus_read_4(sc->res, EDPRSR); - } while ((reg & EDPRCR_CORENPDRQ) == 0); + } while ((reg & EDPRCR_CORENPDRQ) == 0 && timeout--); + + if (timeout <= 0) + return (EINTEGRITY); return (0); } @@ -138,10 +144,32 @@ return (0); } +static int +debug_detach(device_t dev) +{ + struct debug_softc *sc; + int error; + + sc = device_get_softc(dev); + + error = coresight_unregister(dev); + if (error) + return (error); + + coresight_fdt_release_platform_data(sc->pdata); + + sc->pdata = NULL; + + bus_release_resources(dev, debug_spec, &sc->res); + + return (0); +} + static device_method_t debug_methods[] = { /* Device interface */ DEVMETHOD(device_probe, debug_probe), DEVMETHOD(device_attach, debug_attach), + DEVMETHOD(device_detach, debug_detach), /* Coresight interface */ DEVMETHOD(coresight_init, debug_init), @@ -149,11 +177,12 @@ }; static driver_t debug_driver = { - "debug", + "coresight_cpu_debug", debug_methods, sizeof(struct debug_softc), }; -EARLY_DRIVER_MODULE(debug, simplebus, debug_driver, 0, 0, +EARLY_DRIVER_MODULE(coresight_cpu_debug, simplebus, debug_driver, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_LATE); -MODULE_VERSION(debug, 1); +MODULE_VERSION(coresight_cpu_debug, 1); +MODULE_DEPEND(coresight_cpu_debug, coresight, 1, 1, 1); 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 @@ -170,13 +170,76 @@ #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; struct coresight_platform_data *pdata; + uint32_t id_regs[14]; }; int etm_attach(device_t dev); +int etm_detach(device_t dev); + +DECLARE_CLASS(coresight_etm4x_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 @@ -40,6 +40,8 @@ #include #include +#include + #include "coresight_if.h" #define ETM_DEBUG @@ -66,12 +68,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_pipeline *pipeline) { 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 */ @@ -85,6 +172,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); @@ -96,8 +184,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 @@ -114,27 +204,27 @@ /* The number of the single resource used to activate the event. */ reg |= (1 << EVENT_SEL_S); - if (event->excp_level > 2) + if (pipeline->excp_level > 2) return (-1); reg |= TRCVICTLR_EXLEVEL_NS_M; - reg &= ~TRCVICTLR_EXLEVEL_NS(event->excp_level); + reg &= ~TRCVICTLR_EXLEVEL_NS(pipeline->excp_level); reg |= TRCVICTLR_EXLEVEL_S_M; - reg &= ~TRCVICTLR_EXLEVEL_S(event->excp_level); + reg &= ~TRCVICTLR_EXLEVEL_S(pipeline->excp_level); bus_write_4(sc->res, TRCVICTLR, reg); - for (i = 0; i < event->naddr * 2; i++) { + for (i = 0; i < pipeline->naddr * 2; i++) { dprintf("configure range %d, address %lx\n", - i, event->addr[i]); - bus_write_8(sc->res, TRCACVR(i), event->addr[i]); + i, pipeline->addr[i]); + bus_write_8(sc->res, TRCACVR(i), pipeline->addr[i]); reg = 0; /* Secure state */ reg |= TRCACATR_EXLEVEL_S_M; - reg &= ~TRCACATR_EXLEVEL_S(event->excp_level); + reg &= ~TRCACATR_EXLEVEL_S(pipeline->excp_level); /* Non-secure state */ reg |= TRCACATR_EXLEVEL_NS_M; - reg &= ~TRCACATR_EXLEVEL_NS(event->excp_level); + reg &= ~TRCACATR_EXLEVEL_NS(pipeline->excp_level); bus_write_4(sc->res, TRCACATR(i), reg); /* Address range is included */ @@ -149,7 +239,7 @@ /* Clear the STATUS bit to zero */ bus_write_4(sc->res, TRCSSCSR(0), 0); - if (event->naddr == 0) { + if (pipeline->naddr == 0) { /* No address range filtering for ViewInst. */ bus_write_4(sc->res, TRCVIIECTLR, 0); } @@ -166,6 +256,26 @@ return (0); } +static int +etm_configure(device_t dev, struct endpoint *endp, + struct coresight_pipeline *pipeline, struct hwt_context *ctx) +{ + struct etmv4_config *config; + int error; + + dprintf("%s%d\n", __func__, device_get_unit(dev)); + + 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, pipeline); + + return (error); +} + static int etm_init(device_t dev) { @@ -174,6 +284,8 @@ sc = device_get_softc(dev); + dprintf("%s%d\n", __func__, device_get_unit(dev)); + /* Unlocking Coresight */ bus_write_4(sc->res, CORESIGHT_LAR, CORESIGHT_UNLOCK); @@ -190,40 +302,53 @@ static int etm_enable(device_t dev, struct endpoint *endp, - struct coresight_event *event) + struct coresight_pipeline *pipeline) { struct etm_softc *sc; uint32_t reg; 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, pipeline->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 */ + + /* TODO: add timeout */ 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"); + if ((bus_read_4(sc->res, TRCPRGCTLR) & TRCPRGCTLR_EN) == 0) { + printf("%s: etm is not enabled\n", __func__); + return (ENXIO); + } return (0); } static void etm_disable(device_t dev, struct endpoint *endp, - struct coresight_event *event) + struct coresight_pipeline *pipeline) { struct etm_softc *sc; uint32_t reg; 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 { @@ -236,6 +361,8 @@ { struct coresight_desc desc; struct etm_softc *sc; + char name[16]; + int i; sc = device_get_softc(dev); @@ -249,15 +376,43 @@ desc.dev_type = CORESIGHT_ETMV4; coresight_register(&desc); + for (i = 0; i < 14; i++) { + snprintf(name, 16, "idr%d", i); + sc->id_regs[i] = bus_read_4(sc->res, TRCIDR(i)); + SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), + SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), + OID_AUTO, name, CTLFLAG_RD, + &sc->id_regs[i], 0, "id register"); + } + + return (0); +} + +int +etm_detach(device_t dev) +{ + struct etm_softc *sc; + int error; + + sc = device_get_softc(dev); + + error = coresight_unregister(dev); + if (error) + return (error); + + bus_release_resources(dev, etm_spec, &sc->res); + return (0); } 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 }; -DEFINE_CLASS_0(etm, etm_driver, etm_methods, sizeof(struct etm_softc)); +DEFINE_CLASS_0(coresight_etm4x, coresight_etm4x_driver, etm_methods, + sizeof(struct etm_softc)); Index: sys/arm64/coresight/coresight_etm4x_acpi.c =================================================================== --- sys/arm64/coresight/coresight_etm4x_acpi.c +++ sys/arm64/coresight/coresight_etm4x_acpi.c @@ -80,8 +80,8 @@ DEVMETHOD_END }; -DEFINE_CLASS_1(etm, etm_acpi_driver, etm_acpi_methods, - sizeof(struct etm_softc), etm_driver); +DEFINE_CLASS_1(coresight_etm4x, coresight_etm4x_acpi_driver, etm_acpi_methods, + sizeof(struct etm_softc), coresight_etm4x_driver); -EARLY_DRIVER_MODULE(etm, acpi, etm_acpi_driver, 0, 0, +EARLY_DRIVER_MODULE(coresight_etm4x, acpi, coresight_etm4x_acpi_driver, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE); Index: sys/arm64/coresight/coresight_etm4x_fdt.c =================================================================== --- sys/arm64/coresight/coresight_etm4x_fdt.c +++ sys/arm64/coresight/coresight_etm4x_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 @@ -75,15 +75,32 @@ return (etm_attach(dev)); } +static int +etm_fdt_detach(device_t dev) +{ + struct etm_softc *sc; + + sc = device_get_softc(dev); + + coresight_fdt_release_platform_data(sc->pdata); + + sc->pdata = NULL; + + return (etm_detach(dev)); +} + static device_method_t etm_fdt_methods[] = { /* Device interface */ DEVMETHOD(device_probe, etm_fdt_probe), DEVMETHOD(device_attach, etm_fdt_attach), + DEVMETHOD(device_detach, etm_fdt_detach), DEVMETHOD_END }; -DEFINE_CLASS_1(etm, etm_fdt_driver, etm_fdt_methods, - sizeof(struct etm_softc), etm_driver); +DEFINE_CLASS_1(coresight_etm4x, coresight_etm4x_fdt_driver, etm_fdt_methods, + sizeof(struct etm_softc), coresight_etm4x_driver); -EARLY_DRIVER_MODULE(etm, simplebus, etm_fdt_driver, 0, 0, - BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE); +EARLY_DRIVER_MODULE(coresight_etm4x, simplebus, coresight_etm4x_fdt_driver, + 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE); +MODULE_DEPEND(coresight_etm4x, coresight, 1, 1, 1); +MODULE_VERSION(coresight_etm4x, 1); 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 @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -44,10 +45,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; @@ -55,12 +56,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) @@ -86,8 +81,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 @@ -105,19 +100,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); + } + } } } @@ -128,7 +132,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); @@ -140,7 +144,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", @@ -148,3 +159,16 @@ return (pdata); } + +void +coresight_fdt_release_platform_data(struct coresight_platform_data *pdata) +{ + struct endpoint *endp, *tmp; + + TAILQ_FOREACH_SAFE(endp, &pdata->endpoints, link, tmp) { + TAILQ_REMOVE(&pdata->endpoints, endp, link); + free(endp, M_CORESIGHT); + } + + free(pdata, M_CORESIGHT); +} Index: sys/arm64/coresight/coresight_funnel.h =================================================================== --- sys/arm64/coresight/coresight_funnel.h +++ sys/arm64/coresight/coresight_funnel.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 @@ -65,7 +65,7 @@ #define HWTYPE_FUNNEL 1 #define HWTYPE_STATIC_FUNNEL 2 -DECLARE_CLASS(funnel_driver); +DECLARE_CLASS(coresight_funnel_driver); struct funnel_softc { struct resource *res; @@ -74,5 +74,6 @@ }; int funnel_attach(device_t dev); +int funnel_detach(device_t dev); #endif /* !_ARM64_CORESIGHT_CORESIGHT_FUNNEL_H_ */ 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 @@ -73,8 +73,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_pipeline *pipeline, struct hwt_context *ctx) { struct funnel_softc *sc; uint32_t reg; @@ -93,8 +93,8 @@ } static void -funnel_disable(device_t dev, struct endpoint *endp, - struct coresight_event *event) +funnel_deconfigure(device_t dev, struct endpoint *endp, + struct coresight_pipeline *pipeline) { struct funnel_softc *sc; uint32_t reg; @@ -129,13 +129,30 @@ return (0); } +int +funnel_detach(device_t dev) +{ + struct funnel_softc *sc; + int error; + + sc = device_get_softc(dev); + + error = coresight_unregister(dev); + if (error) + return (error); + + bus_release_resources(dev, funnel_spec, &sc->res); + + return (0); +} + 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 }; -DEFINE_CLASS_0(funnel, funnel_driver, funnel_methods, +DEFINE_CLASS_0(coresight_funnel, coresight_funnel_driver, funnel_methods, sizeof(struct funnel_softc)); Index: sys/arm64/coresight/coresight_funnel_acpi.c =================================================================== --- sys/arm64/coresight/coresight_funnel_acpi.c +++ sys/arm64/coresight/coresight_funnel_acpi.c @@ -96,8 +96,8 @@ DEVMETHOD_END }; -DEFINE_CLASS_1(funnel, funnel_acpi_driver, funnel_acpi_methods, - sizeof(struct funnel_softc), funnel_driver); +DEFINE_CLASS_1(coresight_funnel, coresight_funnel_acpi_driver, funnel_acpi_methods, + sizeof(struct funnel_softc), coresight_funnel_driver); -EARLY_DRIVER_MODULE(funnel, acpi, funnel_acpi_driver, 0, 0, +EARLY_DRIVER_MODULE(coresight_funnel, acpi, coresight_funnel_acpi_driver, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE); 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 @@ -46,7 +46,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 } }; @@ -87,15 +87,32 @@ return (funnel_attach(dev)); } +static int +funnel_fdt_detach(device_t dev) +{ + struct funnel_softc *sc; + + sc = device_get_softc(dev); + coresight_fdt_release_platform_data(sc->pdata); + + sc->pdata = NULL; + + return (funnel_detach(dev)); +} + static device_method_t funnel_fdt_methods[] = { /* Device interface */ DEVMETHOD(device_probe, funnel_fdt_probe), DEVMETHOD(device_attach, funnel_fdt_attach), + DEVMETHOD(device_detach, funnel_fdt_detach), DEVMETHOD_END }; -DEFINE_CLASS_1(funnel, funnel_fdt_driver, funnel_fdt_methods, - sizeof(struct funnel_softc), funnel_driver); +DEFINE_CLASS_1(coresight_funnel, coresight_funnel_fdt_driver, + funnel_fdt_methods, sizeof(struct funnel_softc), + coresight_funnel_driver); -EARLY_DRIVER_MODULE(funnel, simplebus, funnel_fdt_driver, 0, 0, - BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE); +EARLY_DRIVER_MODULE(coresight_funnel, simplebus, coresight_funnel_fdt_driver, + 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE); +MODULE_DEPEND(coresight_funnel, coresight, 1, 1, 1); +MODULE_VERSION(coresight_funnel, 1); 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 @@ -38,20 +38,59 @@ device_t dev; }; +METHOD int deinit { + device_t dev; +}; + +METHOD int setup { + device_t dev; + struct endpoint *endp; + struct coresight_pipeline *pipeline; +}; + +METHOD int configure { + device_t dev; + struct endpoint *endp; + struct coresight_pipeline *pipeline; + struct hwt_context *ctx; +}; + +METHOD void deconfigure { + device_t dev; + struct endpoint *endp; + struct coresight_pipeline *pipeline; +}; + +METHOD int start { + device_t dev; + struct endpoint *endp; + struct coresight_pipeline *pipeline; +}; + +METHOD void stop { + device_t dev; + struct endpoint *endp; + struct coresight_pipeline *pipeline; +} + METHOD int enable { device_t dev; struct endpoint *endp; - struct coresight_event *event; + struct coresight_pipeline *pipeline; }; METHOD void disable { device_t dev; struct endpoint *endp; - struct coresight_event *event; + struct coresight_pipeline *pipeline; +}; + +METHOD void dump { + device_t dev; }; METHOD int read { device_t dev; struct endpoint *endp; - struct coresight_event *event; + struct coresight_pipeline *pipeline; }; Index: sys/arm64/coresight/coresight_replicator.h =================================================================== --- sys/arm64/coresight/coresight_replicator.h +++ sys/arm64/coresight/coresight_replicator.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2020 Ruslan Bukin + * Copyright (c) 2023 Ruslan Bukin * All rights reserved. * * This software was developed by SRI International and the University of @@ -34,7 +34,7 @@ #define REPLICATOR_IDFILTER0 0x00 #define REPLICATOR_IDFILTER1 0x04 -DECLARE_CLASS(replicator_driver); +DECLARE_CLASS(coresight_replicator_driver); struct replicator_softc { struct resource *res; @@ -42,5 +42,6 @@ }; int replicator_attach(device_t dev); +int replicator_detach(device_t dev); #endif /* !_ARM64_CORESIGHT_CORESIGHT_REPLICATOR_H_ */ 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 @@ -61,8 +61,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_pipeline *pipeline, struct hwt_context *ctx) { struct replicator_softc *sc; @@ -81,8 +81,8 @@ } static void -replicator_disable(device_t dev, struct endpoint *endp, - struct coresight_event *event) +replicator_deconfigure(device_t dev, struct endpoint *endp, + struct coresight_pipeline *pipeline) { struct replicator_softc *sc; @@ -113,13 +113,30 @@ return (0); } +int +replicator_detach(device_t dev) +{ + struct replicator_softc *sc; + int error; + + sc = device_get_softc(dev); + + error = coresight_unregister(dev); + if (error) + return (error); + + bus_release_resources(dev, replicator_spec, &sc->res); + + return (0); +} + 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 }; -DEFINE_CLASS_0(replicator, replicator_driver, replicator_methods, - sizeof(struct replicator_softc)); +DEFINE_CLASS_0(coresight_replicator, coresight_replicator_driver, + replicator_methods, sizeof(struct replicator_softc)); Index: sys/arm64/coresight/coresight_replicator_acpi.c =================================================================== --- sys/arm64/coresight/coresight_replicator_acpi.c +++ sys/arm64/coresight/coresight_replicator_acpi.c @@ -81,8 +81,8 @@ DEVMETHOD_END }; -DEFINE_CLASS_1(replicator, replicator_acpi_driver, replicator_acpi_methods, - sizeof(struct replicator_softc), replicator_driver); +DEFINE_CLASS_1(coresight_replicator, coresight_replicator_acpi_driver, replicator_acpi_methods, + sizeof(struct replicator_softc), coresight_replicator_driver); -EARLY_DRIVER_MODULE(replicator, acpi, replicator_acpi_driver, 0, 0, +EARLY_DRIVER_MODULE(coresight_replicator, acpi, coresight_replicator_acpi_driver, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE); Index: sys/arm64/coresight/coresight_replicator_fdt.c =================================================================== --- sys/arm64/coresight/coresight_replicator_fdt.c +++ sys/arm64/coresight/coresight_replicator_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 @@ -75,15 +75,34 @@ return (replicator_attach(dev)); } +static int +replicator_fdt_detach(device_t dev) +{ + struct replicator_softc *sc; + + sc = device_get_softc(dev); + + coresight_fdt_release_platform_data(sc->pdata); + + sc->pdata = NULL; + + return (replicator_detach(dev)); +} + static device_method_t replicator_fdt_methods[] = { /* Device interface */ DEVMETHOD(device_probe, replicator_fdt_probe), DEVMETHOD(device_attach, replicator_fdt_attach), + DEVMETHOD(device_detach, replicator_fdt_detach), DEVMETHOD_END }; -DEFINE_CLASS_1(replicator, replicator_fdt_driver, replicator_fdt_methods, - sizeof(struct replicator_softc), replicator_driver); +DEFINE_CLASS_1(coresight_replicator, coresight_replicator_fdt_driver, + replicator_fdt_methods, sizeof(struct replicator_softc), + coresight_replicator_driver); -EARLY_DRIVER_MODULE(replicator, simplebus, replicator_fdt_driver, 0, 0, +EARLY_DRIVER_MODULE(coresight_replicator, simplebus, + coresight_replicator_fdt_driver, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE); +MODULE_DEPEND(coresight_replicator, coresight, 1, 1, 1); +MODULE_VERSION(coresight_replicator, 1); 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 @@ -77,6 +77,7 @@ #define FFCR_FON_TRIG_EVT (1 << 5) #define FFCR_FLUSH_MAN (1 << 6) #define FFCR_TRIGON_TRIGIN (1 << 8) +#define FFCR_STOP_ON_FLUSH (1 << 12) #define TMC_PSCR 0x308 /* Periodic Synchronization Counter Register */ #define TMC_ITATBMDATA0 0xED0 /* Integration Test ATB Master Data Register 0 */ #define TMC_ITATBMCTR2 0xED4 /* Integration Test ATB Master Interface Control 2 Register */ @@ -114,22 +115,25 @@ #define TMC_COMPID2 0xFF8 /* Component ID2 Register */ #define TMC_COMPID3 0xFFC /* Component ID3 Register */ -DECLARE_CLASS(tmc_driver); +DECLARE_CLASS(coresight_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); +int tmc_detach(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 @@ -36,6 +36,15 @@ #include #include +#include +#include +#include +#include +#include +#include +#include +#include + #include #include @@ -43,140 +52,390 @@ #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 MALLOC_DEFINE(M_CORESIGHT_TMC, "coresight_tmc", "Coresight TMC"); + 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_wait_for_tmcready(struct tmc_softc *sc) { - struct tmc_softc *sc; uint32_t reg; + int timeout; - sc = device_get_softc(dev); + timeout = 10000; - if (bus_read_4(sc->res, TMC_CTL) & CTL_TRACECAPTEN) - return (-1); + do { + reg = bus_read_4(sc->res[0], TMC_STS); + if (reg & STS_TMCREADY) + break; + } while (timeout--); + + if (timeout <= 0) { + printf("%s: Error: TMC type %d is running\n", __func__, + sc->dev_type); + return (EINTEGRITY); + } - /* Enable TMC */ - bus_write_4(sc->res, TMC_CTL, CTL_TRACECAPTEN); - if ((bus_read_4(sc->res, TMC_CTL) & CTL_TRACECAPTEN) == 0) - panic("Not enabled\n"); + return (0); +} - do { - reg = bus_read_4(sc->res, TMC_STS); - } while ((reg & STS_TMCREADY) == 1); +static int +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; + uintptr_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 ((bus_read_4(sc->res, TMC_CTL) & CTL_TRACECAPTEN) == 0) - panic("Not enabled\n"); + 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 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); + if (sc->dev_type == CORESIGHT_ETF) + return; + + 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_stop(device_t dev) +tmc_configure_etf(device_t dev) { struct tmc_softc *sc; uint32_t reg; sc = device_get_softc(dev); - reg = bus_read_4(sc->res, TMC_CTL); - reg &= ~CTL_TRACECAPTEN; - bus_write_4(sc->res, TMC_CTL, reg); + dprintf("%s%d\n", __func__, device_get_unit(dev)); - do { - reg = bus_read_4(sc->res, TMC_STS); - } while ((reg & STS_TMCREADY) == 1); + bus_write_4(sc->res[0], TMC_MODE, MODE_HW_FIFO); + reg = FFCR_EN_FMT | FFCR_EN_TI; + bus_write_4(sc->res[0], TMC_FFCR, reg); return (0); } static int -tmc_configure_etf(device_t dev) +tmc_configure_etr(device_t dev, struct endpoint *endp, + struct coresight_pipeline *pipeline) { struct tmc_softc *sc; uint32_t reg; sc = device_get_softc(dev); - do { - reg = bus_read_4(sc->res, TMC_STS); - } while ((reg & STS_TMCREADY) == 0); + dprintf("%s%d\n", __func__, device_get_unit(dev)); + + /* Configure TMC */ + bus_write_4(sc->res[0], TMC_MODE, MODE_CIRCULAR_BUFFER); + + reg = AXICTL_PROT_CTRL_BIT1; + reg |= AXICTL_WRBURSTLEN_16; + if (sc->scatter_gather) + reg |= AXICTL_SG_MODE; + /* reg |= AXICTL_AXCACHE_OS; */ + bus_write_4(sc->res[0], TMC_AXICTL, reg); - bus_write_4(sc->res, TMC_MODE, MODE_HW_FIFO); - bus_write_4(sc->res, TMC_FFCR, FFCR_EN_FMT | FFCR_EN_TI); + reg = FFCR_EN_FMT | FFCR_EN_TI | FFCR_FON_FLIN | + FFCR_FON_TRIG_EVT | FFCR_TRIGON_TRIGIN; + bus_write_4(sc->res[0], TMC_FFCR, reg); - tmc_start(dev); + bus_write_4(sc->res[0], TMC_TRG, 0x3ff); - 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)); + if (sc->scatter_gather) { + dprintf("%s: pipeline->etr.pages %p\n", __func__, + pipeline->etr.pages); + dprintf("%s: pipeline->etr.npages %d\n", __func__, + pipeline->etr.npages); + } else { + bus_write_4(sc->res[0], TMC_DBALO, pipeline->etr.low); + bus_write_4(sc->res[0], TMC_DBAHI, pipeline->etr.high); + bus_write_4(sc->res[0], TMC_RSZ, pipeline->etr.bufsize / 4); + bus_write_4(sc->res[0], TMC_RRP, pipeline->etr.low); + bus_write_4(sc->res[0], TMC_RWP, pipeline->etr.low); + } + + reg = bus_read_4(sc->res[0], TMC_STS); + reg &= ~STS_FULL; + 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_CORESIGHT_TMC, + 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((uintptr_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((uintptr_t)ptr, sizeof(sgte_t)); + + return (pt_dir); +} + +static void +tmc_deallocate_pgdir(struct coresight_pipeline *pipeline) +{ + vm_page_t *pg_dir; + vm_page_t m; + int npages; + int i; + + pg_dir = pipeline->etr.pt_dir; + npages = pipeline->etr.npt; + + for (i = 0; i < npages; i++) { + m = pg_dir[i]; + if (m == NULL) + break; + + vm_page_lock(m); + m->oflags |= VPO_UNMANAGED; + m->flags &= ~PG_FICTITIOUS; + vm_page_unwire_noq(m); + vm_page_free(m); + vm_page_unlock(m); + } + + free(pg_dir, M_CORESIGHT_TMC); +} + static int -tmc_configure_etr(device_t dev, struct endpoint *endp, - struct coresight_event *event) +tmc_setup(device_t dev, struct endpoint *endp, + struct coresight_pipeline *pipeline) { struct tmc_softc *sc; - uint32_t reg; + vm_page_t *pt_dir; + vm_page_t *pages; + uint64_t pbase; + int nentries; + int nlinks; + int npages; + int npt; + int error; sc = device_get_softc(dev); + if (sc->dev_type == CORESIGHT_ETF) + return (0); - tmc_stop(dev); + if (!sc->scatter_gather) + return (0); - do { - reg = bus_read_4(sc->res, TMC_STS); - } while ((reg & STS_TMCREADY) == 0); + error = tmc_wait_for_tmcready(sc); + if (error) + return (error); - /* Configure TMC */ - bus_write_4(sc->res, TMC_MODE, MODE_CIRCULAR_BUFFER); + npages = pipeline->etr.npages; + pages = pipeline->etr.pages; - reg = AXICTL_PROT_CTRL_BIT1; - reg |= AXICTL_WRBURSTLEN_16; + if (npages == 0 || pages == NULL) + return (EINVAL); - /* - * SG operation is broken on DragonBoard 410c - * reg |= AXICTL_SG_MODE; - */ + nlinks = npages / (SG_PT_ENTIRES_PER_PAGE - 1); + if (nlinks && ((npages % (SG_PT_ENTIRES_PER_PAGE - 1)) < 2)) + nlinks--; + nentries = nlinks + npages; - reg |= AXICTL_AXCACHE_OS; - bus_write_4(sc->res, TMC_AXICTL, reg); + npt = howmany(nentries, SG_PT_ENTIRES_PER_PAGE); - 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); + dprintf("%s: nentries %d, npt %d\n", __func__, nentries, npt); - bus_write_4(sc->res, TMC_TRG, 8); + pt_dir = tmc_allocate_pgdir(sc, pages, nentries, npt); + if (pt_dir == NULL) + return (ENOMEM); + pipeline->etr.pt_dir = pt_dir; + pipeline->etr.npt = npt; - 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); +#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 - bus_write_4(sc->res, TMC_RRP, event->etr.low); - bus_write_4(sc->res, TMC_RWP, event->etr.low); + dprintf("%s: pipeline->etr.pages %p\n", __func__, pipeline->etr.pages); + dprintf("%s: pipeline->etr.npages %d\n", __func__, + pipeline->etr.npages); - reg = bus_read_4(sc->res, TMC_STS); - reg &= ~STS_FULL; - bus_write_4(sc->res, TMC_STS, reg); + pbase = (uint64_t)VM_PAGE_TO_PHYS(pt_dir[0]); + + dprintf("%s: pbase %lx\n", __func__, pbase); - tmc_start(dev); + 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, (pipeline->etr.npages * 4096) / 4); + + return (0); +} + +static int +tmc_enable_hw(device_t dev) +{ + struct tmc_softc *sc; + + sc = device_get_softc(dev); + + if (bus_read_4(sc->res[0], TMC_CTL) & CTL_TRACECAPTEN) { + printf("%s: TMC is already enabled\n", __func__); + return (ENXIO); + } + + /* Enable TMC */ + bus_write_4(sc->res[0], TMC_CTL, CTL_TRACECAPTEN); + + if ((bus_read_4(sc->res[0], TMC_CTL) & CTL_TRACECAPTEN) == 0) { + printf("%s: could not enable TMC\n", __func__); + return (ENXIO); + } + + dprintf("%s: tmc type %d enabled\n", __func__, sc->dev_type); return (0); } @@ -189,13 +448,15 @@ sc = device_get_softc(dev); + dprintf("%s%d\n", __func__, device_get_unit(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: @@ -207,6 +468,7 @@ dprintf(dev, "ETF configuration found\n"); if (sc->etf_configured == false) { tmc_configure_etf(dev); + tmc_enable_hw(dev); sc->etf_configured = true; } break; @@ -219,128 +481,260 @@ } static int -tmc_enable(device_t dev, struct endpoint *endp, - struct coresight_event *event) +tmc_flush(struct tmc_softc *sc, int stop_on_flush) { - struct tmc_softc *sc; - uint32_t nev; + uint32_t reg; + int timeout; - sc = device_get_softc(dev); + reg = bus_read_4(sc->res[0], TMC_FFCR); - if (sc->dev_type == CORESIGHT_ETF) - return (0); + if (stop_on_flush) { + reg |= FFCR_STOP_ON_FLUSH; + bus_write_4(sc->res[0], TMC_FFCR, reg); + } - 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); - } + reg |= FFCR_FLUSH_MAN; + bus_write_4(sc->res[0], TMC_FFCR, reg); + + /* Wait for the flush to complete. */ + timeout = 10000; + + do { + reg = bus_read_4(sc->res[0], TMC_FFCR); + if ((reg & FFCR_FLUSH_MAN) == 0) + break; + } while (timeout--); + + if (timeout <= 0) { + printf("%s: could not flush TMC\n", __func__); + return (EINTEGRITY); } return (0); } +static void +tmc_disable_hw(device_t dev) +{ + struct tmc_softc *sc; + int error; + + sc = device_get_softc(dev); + + error = tmc_flush(sc, 1); + if (error) + printf("%s: could not flush TMC\n", __func__); + + error = tmc_wait_for_tmcready(sc); + if (error) + printf("%s: could not get TMC ready\n", __func__); + + bus_write_4(sc->res[0], TMC_CTL, 0); + + dprintf("%s: tmc type %d disabled\n", __func__, sc->dev_type); +} + static void tmc_disable(device_t dev, struct endpoint *endp, - struct coresight_event *event) + struct coresight_pipeline *pipeline) { struct tmc_softc *sc; - uint32_t nev; sc = device_get_softc(dev); - /* ETF configuration is static */ - if (sc->dev_type == CORESIGHT_ETF) + if (sc->dev_type == CORESIGHT_ETR) return; - KASSERT(sc->dev_type == CORESIGHT_ETR, ("Wrong dev_type")); + tmc_flush(sc, 0); +} - 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; - } +static int +tmc_deinit(device_t dev) +{ + struct tmc_softc *sc; + + sc = device_get_softc(dev); + + if (sc->dev_type == CORESIGHT_ETR) + return (0); + + if (sc->etf_configured == true) { + sc->etf_configured = false; + tmc_disable_hw(dev); } + + return (0); } static int -tmc_read(device_t dev, struct endpoint *endp, - struct coresight_event *event) +tmc_start(device_t dev, struct endpoint *endp, + struct coresight_pipeline *pipeline) { struct tmc_softc *sc; - uint32_t cur_ptr; + int error; sc = device_get_softc(dev); - if (sc->dev_type == CORESIGHT_ETF) return (0); - /* - * Ensure the event we are reading information for - * is currently configured one. - */ - if (sc->event != event) - return (0); + dprintf("%s%d type %d\n", __func__, device_get_unit(dev), sc->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); - } + error = tmc_wait_for_tmcready(sc); + if (error) + return (error); + + tmc_configure_etr(dev, endp, pipeline); + tmc_enable_hw(dev); return (0); } +static int +tmc_read(device_t dev, struct endpoint *endp, + struct coresight_pipeline *pipeline) +{ + struct tmc_softc *sc; + vm_page_t page; + bool found; + uint64_t lo, hi; + uint64_t ptr; + int i; + + sc = device_get_softc(dev); + if (sc->dev_type == CORESIGHT_ETF) + return (ENXIO); + + 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; + + for (i = 0; i < pipeline->etr.npages; i++) { + if (pipeline->etr.pages[i] == page) { + found = true; + break; + } + } + + if (found) { + pipeline->etr.curpage = i; + pipeline->etr.curpage_offset = ptr & 0xfff; + dprintf("CUR_PTR %lx, page %d of %d, offset %ld\n", + ptr, i, pipeline->etr.npages, pipeline->etr.curpage_offset); + + return (0); + } else + dprintf("CUR_PTR not found\n"); + + return (ENOENT); +} + +static void +tmc_stop(device_t dev, struct endpoint *endp, + struct coresight_pipeline *pipeline) +{ + struct tmc_softc *sc; + + sc = device_get_softc(dev); + if (sc->dev_type == CORESIGHT_ETF) + return; + + dprintf("%s%d type %d\n", __func__, device_get_unit(dev), sc->dev_type); + + /* Make final readings before we stop TMC-ETR. */ + tmc_read(dev, endp, pipeline); + tmc_disable_hw(dev); + tmc_deallocate_pgdir(pipeline); +} + +static void +tmc_intr(void *arg) +{ + + /* TODO */ + + panic("unhandled interrupt"); +} + int tmc_attach(device_t dev) { 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); } -static device_method_t tmc_methods[] = { - /* Device interface */ - DEVMETHOD(device_attach, tmc_attach), +int +tmc_detach(device_t dev) +{ + struct tmc_softc *sc; + int error; + + sc = device_get_softc(dev); + + error = coresight_unregister(dev); + if (error) + return (error); + + if (sc->intrhand != NULL) + bus_teardown_intr(dev, sc->res[1], sc->intrhand); + + bus_release_resources(dev, tmc_spec, sc->res); + return (0); +} + +static device_method_t tmc_methods[] = { /* Coresight interface */ DEVMETHOD(coresight_init, tmc_init), - DEVMETHOD(coresight_enable, tmc_enable), + + /* ETF only. */ + DEVMETHOD(coresight_deinit, tmc_deinit), DEVMETHOD(coresight_disable, tmc_disable), + + /* ETR only. */ + DEVMETHOD(coresight_setup, tmc_setup), + DEVMETHOD(coresight_start, tmc_start), + DEVMETHOD(coresight_stop, tmc_stop), DEVMETHOD(coresight_read, tmc_read), + DEVMETHOD(coresight_dump, tmc_dump), DEVMETHOD_END }; -DEFINE_CLASS_0(tmc, tmc_driver, tmc_methods, sizeof(struct tmc_softc)); +DEFINE_CLASS_0(coresight_tmc, coresight_tmc_driver, tmc_methods, + sizeof(struct tmc_softc)); Index: sys/arm64/coresight/coresight_tmc_acpi.c =================================================================== --- sys/arm64/coresight/coresight_tmc_acpi.c +++ sys/arm64/coresight/coresight_tmc_acpi.c @@ -80,8 +80,8 @@ DEVMETHOD_END }; -DEFINE_CLASS_1(tmc, tmc_acpi_driver, tmc_acpi_methods, - sizeof(struct tmc_softc), tmc_driver); +DEFINE_CLASS_1(coresight_tmc, coresight_tmc_acpi_driver, tmc_acpi_methods, + sizeof(struct tmc_softc), coresight_tmc_driver); -EARLY_DRIVER_MODULE(tmc, acpi, tmc_acpi_driver, 0, 0, +EARLY_DRIVER_MODULE(coresight_tmc, acpi, coresight_tmc_acpi_driver, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE); Index: sys/arm64/coresight/coresight_tmc_fdt.c =================================================================== --- sys/arm64/coresight/coresight_tmc_fdt.c +++ sys/arm64/coresight/coresight_tmc_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 @@ -68,22 +68,56 @@ 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)); } +static int +tmc_fdt_detach(device_t dev) +{ + struct tmc_softc *sc; + int error; + + sc = device_get_softc(dev); + + coresight_fdt_release_platform_data(sc->pdata); + + sc->pdata = NULL; + + error = tmc_detach(dev); + + return (error); +} + static device_method_t tmc_fdt_methods[] = { /* Device interface */ DEVMETHOD(device_probe, tmc_fdt_probe), DEVMETHOD(device_attach, tmc_fdt_attach), + DEVMETHOD(device_detach, tmc_fdt_detach), DEVMETHOD_END }; -DEFINE_CLASS_1(tmc, tmc_fdt_driver, tmc_fdt_methods, - sizeof(struct tmc_softc), tmc_driver); +DEFINE_CLASS_1(coresight_tmc, tmc_fdt_driver, tmc_fdt_methods, + sizeof(struct tmc_softc), coresight_tmc_driver); -EARLY_DRIVER_MODULE(tmc, simplebus, tmc_fdt_driver, 0, 0, +EARLY_DRIVER_MODULE(coresight_tmc, simplebus, tmc_fdt_driver, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE); +MODULE_DEPEND(coresight_tmc, coresight, 1, 1, 1); +MODULE_DEPEND(coresight_tmc, coresight_cpu_debug, 1, 1, 1); +MODULE_DEPEND(coresight_tmc, coresight_etm4x, 1, 1, 1); +MODULE_DEPEND(coresight_tmc, coresight_funnel, 1, 1, 1); +MODULE_DEPEND(coresight_tmc, coresight_replicator, 1, 1, 1); +MODULE_VERSION(coresight_tmc, 1); Index: sys/conf/files.arm64 =================================================================== --- sys/conf/files.arm64 +++ sys/conf/files.arm64 @@ -85,24 +85,24 @@ arm64/arm64/vfp.c standard arm64/arm64/vm_machdep.c standard -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 coresight +arm64/coresight/coresight_acpi.c optional hwt coresight acpi +arm64/coresight/coresight_fdt.c optional hwt coresight fdt +arm64/coresight/coresight_if.m optional hwt coresight +arm64/coresight/coresight_cmd.c optional hwt coresight +arm64/coresight/coresight_cpu_debug.c optional hwt coresight fdt +arm64/coresight/coresight_etm4x.c optional hwt coresight +arm64/coresight/coresight_etm4x_acpi.c optional hwt coresight acpi +arm64/coresight/coresight_etm4x_fdt.c optional hwt coresight fdt +arm64/coresight/coresight_funnel.c optional hwt coresight +arm64/coresight/coresight_funnel_acpi.c optional hwt coresight acpi +arm64/coresight/coresight_funnel_fdt.c optional hwt coresight fdt +arm64/coresight/coresight_replicator.c optional hwt coresight +arm64/coresight/coresight_replicator_acpi.c optional hwt coresight acpi +arm64/coresight/coresight_replicator_fdt.c optional hwt coresight fdt +arm64/coresight/coresight_tmc.c optional hwt coresight +arm64/coresight/coresight_tmc_acpi.c optional hwt coresight acpi +arm64/coresight/coresight_tmc_fdt.c optional hwt coresight fdt dev/smbios/smbios_subr.c standard Index: sys/modules/Makefile =================================================================== --- sys/modules/Makefile +++ sys/modules/Makefile @@ -84,6 +84,7 @@ ${_cfi} \ ${_chromebook_platform} \ ${_ciss} \ + ${_coresight} \ ${_coretemp} \ ${_cpsw} \ ${_cpuctl} \ @@ -139,6 +140,7 @@ ${_hptnr} \ ${_hptrr} \ hwpmc \ + hwt \ ${_hyperv} \ i2c \ ${_iavf} \ @@ -653,6 +655,12 @@ .endif .endif +.if ${MACHINE_CPUARCH} == "aarch64" +.if !empty(OPT_FDT) +_coresight= coresight +.endif +.endif + .if ${MACHINE_CPUARCH} == "aarch64" || ${MACHINE_CPUARCH} == "arm" || \ ${MACHINE_CPUARCH} == "riscv" .if !empty(OPT_FDT) Index: sys/modules/coresight/Makefile =================================================================== --- /dev/null +++ sys/modules/coresight/Makefile @@ -0,0 +1,11 @@ +# $FreeBSD$ + +SUBDIR = \ + coresight \ + cpu_debug \ + etm4x \ + funnel \ + replicator \ + tmc + +.include Index: sys/modules/coresight/coresight/Makefile =================================================================== --- /dev/null +++ sys/modules/coresight/coresight/Makefile @@ -0,0 +1,14 @@ +# $FreeBSD$ + +.PATH: ${SRCTOP}/sys/arm64/coresight + +KMOD = coresight +SRCS = \ + coresight.c \ + coresight_acpi.c \ + coresight_cmd.c \ + coresight_fdt.c \ + coresight_if.c \ + coresight_if.h + +.include Index: sys/modules/coresight/cpu_debug/Makefile =================================================================== --- /dev/null +++ sys/modules/coresight/cpu_debug/Makefile @@ -0,0 +1,8 @@ +# $FreeBSD$ + +.PATH: ${SRCTOP}/sys/arm64/coresight + +KMOD = coresight_cpu_debug +SRCS = coresight_cpu_debug.c coresight_if.h + +.include Index: sys/modules/coresight/etm4x/Makefile =================================================================== --- /dev/null +++ sys/modules/coresight/etm4x/Makefile @@ -0,0 +1,8 @@ +# $FreeBSD$ + +.PATH: ${SRCTOP}/sys/arm64/coresight + +KMOD = coresight_etm4x +SRCS = coresight_etm4x.c coresight_etm4x_fdt.c coresight_if.h + +.include Index: sys/modules/coresight/funnel/Makefile =================================================================== --- /dev/null +++ sys/modules/coresight/funnel/Makefile @@ -0,0 +1,8 @@ +# $FreeBSD$ + +.PATH: ${SRCTOP}/sys/arm64/coresight + +KMOD = coresight_funnel +SRCS = coresight_funnel.c coresight_funnel_fdt.c coresight_if.h + +.include Index: sys/modules/coresight/replicator/Makefile =================================================================== --- /dev/null +++ sys/modules/coresight/replicator/Makefile @@ -0,0 +1,8 @@ +# $FreeBSD$ + +.PATH: ${SRCTOP}/sys/arm64/coresight + +KMOD = coresight_replicator +SRCS = coresight_replicator.c coresight_replicator_fdt.c coresight_if.h + +.include Index: sys/modules/coresight/tmc/Makefile =================================================================== --- /dev/null +++ sys/modules/coresight/tmc/Makefile @@ -0,0 +1,8 @@ +# $FreeBSD$ + +.PATH: ${SRCTOP}/sys/arm64/coresight + +KMOD = coresight_tmc +SRCS = coresight_tmc.c coresight_tmc_fdt.c coresight_if.h + +.include