1b1670691SRuslan Bukin /*-
2c9ea007cSRuslan Bukin * Copyright (c) 2018-2020 Ruslan Bukin <br@bsdpad.com>
3b1670691SRuslan Bukin * All rights reserved.
4b1670691SRuslan Bukin *
5b1670691SRuslan Bukin * This software was developed by BAE Systems, the University of Cambridge
6b1670691SRuslan Bukin * Computer Laboratory, and Memorial University under DARPA/AFRL contract
7b1670691SRuslan Bukin * FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent Computing
8b1670691SRuslan Bukin * (TC) research program.
9b1670691SRuslan Bukin *
10b1670691SRuslan Bukin * Redistribution and use in source and binary forms, with or without
11b1670691SRuslan Bukin * modification, are permitted provided that the following conditions
12b1670691SRuslan Bukin * are met:
13b1670691SRuslan Bukin * 1. Redistributions of source code must retain the above copyright
14b1670691SRuslan Bukin * notice, this list of conditions and the following disclaimer.
15b1670691SRuslan Bukin * 2. Redistributions in binary form must reproduce the above copyright
16b1670691SRuslan Bukin * notice, this list of conditions and the following disclaimer in the
17b1670691SRuslan Bukin * documentation and/or other materials provided with the distribution.
18b1670691SRuslan Bukin *
19b1670691SRuslan Bukin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20b1670691SRuslan Bukin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21b1670691SRuslan Bukin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22b1670691SRuslan Bukin * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23b1670691SRuslan Bukin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24b1670691SRuslan Bukin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25b1670691SRuslan Bukin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26b1670691SRuslan Bukin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27b1670691SRuslan Bukin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28b1670691SRuslan Bukin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29b1670691SRuslan Bukin * SUCH DAMAGE.
30b1670691SRuslan Bukin */
31b1670691SRuslan Bukin
32b1670691SRuslan Bukin #include <sys/param.h>
33b1670691SRuslan Bukin #include <sys/systm.h>
34b1670691SRuslan Bukin #include <sys/bus.h>
35b1670691SRuslan Bukin #include <sys/rman.h>
36b1670691SRuslan Bukin #include <sys/kernel.h>
37b1670691SRuslan Bukin #include <sys/module.h>
38b1670691SRuslan Bukin #include <machine/bus.h>
39b1670691SRuslan Bukin
40b1670691SRuslan Bukin #include <arm64/coresight/coresight.h>
41b1670691SRuslan Bukin #include <arm64/coresight/coresight_etm4x.h>
42b1670691SRuslan Bukin
43b1670691SRuslan Bukin #include "coresight_if.h"
44b1670691SRuslan Bukin
45b1670691SRuslan Bukin #define ETM_DEBUG
46b1670691SRuslan Bukin #undef ETM_DEBUG
47b1670691SRuslan Bukin
48b1670691SRuslan Bukin #ifdef ETM_DEBUG
49b1670691SRuslan Bukin #define dprintf(fmt, ...) printf(fmt, ##__VA_ARGS__)
50b1670691SRuslan Bukin #else
51b1670691SRuslan Bukin #define dprintf(fmt, ...)
52b1670691SRuslan Bukin #endif
53b1670691SRuslan Bukin
54b1670691SRuslan Bukin /*
55b1670691SRuslan Bukin * Typical trace flow:
56b1670691SRuslan Bukin *
57b1670691SRuslan Bukin * CPU0 -> ETM0 -> funnel1 -> funnel0 -> ETF -> replicator -> ETR -> DRAM
58b1670691SRuslan Bukin * CPU1 -> ETM1 -> funnel1 -^
59b1670691SRuslan Bukin * CPU2 -> ETM2 -> funnel1 -^
60b1670691SRuslan Bukin * CPU3 -> ETM3 -> funnel1 -^
61b1670691SRuslan Bukin */
62b1670691SRuslan Bukin
63b1670691SRuslan Bukin static struct resource_spec etm_spec[] = {
64b1670691SRuslan Bukin { SYS_RES_MEMORY, 0, RF_ACTIVE },
65b1670691SRuslan Bukin { -1, 0 }
66b1670691SRuslan Bukin };
67b1670691SRuslan Bukin
68b1670691SRuslan Bukin static int
etm_prepare(device_t dev,struct coresight_event * event)69b1670691SRuslan Bukin etm_prepare(device_t dev, struct coresight_event *event)
70b1670691SRuslan Bukin {
71b1670691SRuslan Bukin struct etm_softc *sc;
72b1670691SRuslan Bukin uint32_t reg;
73b1670691SRuslan Bukin int i;
74b1670691SRuslan Bukin
75b1670691SRuslan Bukin sc = device_get_softc(dev);
76b1670691SRuslan Bukin
77b1670691SRuslan Bukin /* Configure ETM */
78b1670691SRuslan Bukin
79b1670691SRuslan Bukin /*
80b1670691SRuslan Bukin * Enable the return stack, global timestamping,
81b1670691SRuslan Bukin * Context ID, and Virtual context identifier tracing.
82b1670691SRuslan Bukin */
83b1670691SRuslan Bukin reg = TRCCONFIGR_RS | TRCCONFIGR_TS;
84b1670691SRuslan Bukin reg |= TRCCONFIGR_CID | TRCCONFIGR_VMID;
85b1670691SRuslan Bukin reg |= TRCCONFIGR_INSTP0_LDRSTR;
86b1670691SRuslan Bukin reg |= TRCCONFIGR_COND_ALL;
87b1670691SRuslan Bukin bus_write_4(sc->res, TRCCONFIGR, reg);
88b1670691SRuslan Bukin
89b1670691SRuslan Bukin /* Disable all event tracing. */
90b1670691SRuslan Bukin bus_write_4(sc->res, TRCEVENTCTL0R, 0);
91b1670691SRuslan Bukin bus_write_4(sc->res, TRCEVENTCTL1R, 0);
92b1670691SRuslan Bukin
93b1670691SRuslan Bukin /* Disable stalling, if implemented. */
94b1670691SRuslan Bukin bus_write_4(sc->res, TRCSTALLCTLR, 0);
95b1670691SRuslan Bukin
96b1670691SRuslan Bukin /* Enable trace synchronization every 4096 bytes of trace. */
97b1670691SRuslan Bukin bus_write_4(sc->res, TRCSYNCPR, TRCSYNCPR_4K);
98b1670691SRuslan Bukin
99b1670691SRuslan Bukin /* Set a value for the trace ID */
100b1670691SRuslan Bukin bus_write_4(sc->res, TRCTRACEIDR, event->etm.trace_id);
101b1670691SRuslan Bukin
102b1670691SRuslan Bukin /*
103b1670691SRuslan Bukin * Disable the timestamp event. The trace unit still generates
104b1670691SRuslan Bukin * timestamps due to other reasons such as trace synchronization.
105b1670691SRuslan Bukin */
106b1670691SRuslan Bukin bus_write_4(sc->res, TRCTSCTLR, 0);
107b1670691SRuslan Bukin
108b1670691SRuslan Bukin /*
109b1670691SRuslan Bukin * Enable ViewInst to trace everything, with the start/stop
110b1670691SRuslan Bukin * logic started.
111b1670691SRuslan Bukin */
112b1670691SRuslan Bukin reg = TRCVICTLR_SSSTATUS;
113b1670691SRuslan Bukin
114b1670691SRuslan Bukin /* The number of the single resource used to activate the event. */
115b1670691SRuslan Bukin reg |= (1 << EVENT_SEL_S);
116b1670691SRuslan Bukin
117b1670691SRuslan Bukin if (event->excp_level > 2)
118b1670691SRuslan Bukin return (-1);
119b1670691SRuslan Bukin
120b1670691SRuslan Bukin reg |= TRCVICTLR_EXLEVEL_NS_M;
121b1670691SRuslan Bukin reg &= ~TRCVICTLR_EXLEVEL_NS(event->excp_level);
122b1670691SRuslan Bukin reg |= TRCVICTLR_EXLEVEL_S_M;
123b1670691SRuslan Bukin reg &= ~TRCVICTLR_EXLEVEL_S(event->excp_level);
124b1670691SRuslan Bukin bus_write_4(sc->res, TRCVICTLR, reg);
125b1670691SRuslan Bukin
126b1670691SRuslan Bukin for (i = 0; i < event->naddr * 2; i++) {
127b1670691SRuslan Bukin dprintf("configure range %d, address %lx\n",
128b1670691SRuslan Bukin i, event->addr[i]);
129b1670691SRuslan Bukin bus_write_8(sc->res, TRCACVR(i), event->addr[i]);
130b1670691SRuslan Bukin
131b1670691SRuslan Bukin reg = 0;
132b1670691SRuslan Bukin /* Secure state */
133b1670691SRuslan Bukin reg |= TRCACATR_EXLEVEL_S_M;
134b1670691SRuslan Bukin reg &= ~TRCACATR_EXLEVEL_S(event->excp_level);
135b1670691SRuslan Bukin /* Non-secure state */
136b1670691SRuslan Bukin reg |= TRCACATR_EXLEVEL_NS_M;
137b1670691SRuslan Bukin reg &= ~TRCACATR_EXLEVEL_NS(event->excp_level);
138b1670691SRuslan Bukin bus_write_4(sc->res, TRCACATR(i), reg);
139b1670691SRuslan Bukin
140b1670691SRuslan Bukin /* Address range is included */
141b1670691SRuslan Bukin reg = bus_read_4(sc->res, TRCVIIECTLR);
142b1670691SRuslan Bukin reg |= (1 << (TRCVIIECTLR_INCLUDE_S + i / 2));
143b1670691SRuslan Bukin bus_write_4(sc->res, TRCVIIECTLR, reg);
144b1670691SRuslan Bukin }
145b1670691SRuslan Bukin
146b1670691SRuslan Bukin /* No address filtering for ViewData. */
147b1670691SRuslan Bukin bus_write_4(sc->res, TRCVDARCCTLR, 0);
148b1670691SRuslan Bukin
149b1670691SRuslan Bukin /* Clear the STATUS bit to zero */
150b1670691SRuslan Bukin bus_write_4(sc->res, TRCSSCSR(0), 0);
151b1670691SRuslan Bukin
152b1670691SRuslan Bukin if (event->naddr == 0) {
153b1670691SRuslan Bukin /* No address range filtering for ViewInst. */
154b1670691SRuslan Bukin bus_write_4(sc->res, TRCVIIECTLR, 0);
155b1670691SRuslan Bukin }
156b1670691SRuslan Bukin
157b1670691SRuslan Bukin /* No start or stop points for ViewInst. */
158b1670691SRuslan Bukin bus_write_4(sc->res, TRCVISSCTLR, 0);
159b1670691SRuslan Bukin
160b1670691SRuslan Bukin /* Disable ViewData */
161b1670691SRuslan Bukin bus_write_4(sc->res, TRCVDCTLR, 0);
162b1670691SRuslan Bukin
163b1670691SRuslan Bukin /* No address filtering for ViewData. */
164b1670691SRuslan Bukin bus_write_4(sc->res, TRCVDSACCTLR, 0);
165b1670691SRuslan Bukin
166b1670691SRuslan Bukin return (0);
167b1670691SRuslan Bukin }
168b1670691SRuslan Bukin
169b1670691SRuslan Bukin static int
etm_init(device_t dev)170b1670691SRuslan Bukin etm_init(device_t dev)
171b1670691SRuslan Bukin {
172b1670691SRuslan Bukin struct etm_softc *sc;
173*67f6cad3SJohn Baldwin uint32_t reg __unused;
174b1670691SRuslan Bukin
175b1670691SRuslan Bukin sc = device_get_softc(dev);
176b1670691SRuslan Bukin
177b1670691SRuslan Bukin /* Unlocking Coresight */
178b1670691SRuslan Bukin bus_write_4(sc->res, CORESIGHT_LAR, CORESIGHT_UNLOCK);
179b1670691SRuslan Bukin
180b1670691SRuslan Bukin /* Unlocking ETM */
181b1670691SRuslan Bukin bus_write_4(sc->res, TRCOSLAR, 0);
182b1670691SRuslan Bukin
183b1670691SRuslan Bukin reg = bus_read_4(sc->res, TRCIDR(1));
184b1670691SRuslan Bukin dprintf("ETM Version: %d.%d\n",
185b1670691SRuslan Bukin (reg & TRCIDR1_TRCARCHMAJ_M) >> TRCIDR1_TRCARCHMAJ_S,
186b1670691SRuslan Bukin (reg & TRCIDR1_TRCARCHMIN_M) >> TRCIDR1_TRCARCHMIN_S);
187b1670691SRuslan Bukin
188b1670691SRuslan Bukin return (0);
189b1670691SRuslan Bukin }
190b1670691SRuslan Bukin
191b1670691SRuslan Bukin static int
etm_enable(device_t dev,struct endpoint * endp,struct coresight_event * event)192b1670691SRuslan Bukin etm_enable(device_t dev, struct endpoint *endp,
193b1670691SRuslan Bukin struct coresight_event *event)
194b1670691SRuslan Bukin {
195b1670691SRuslan Bukin struct etm_softc *sc;
196b1670691SRuslan Bukin uint32_t reg;
197b1670691SRuslan Bukin
198b1670691SRuslan Bukin sc = device_get_softc(dev);
199b1670691SRuslan Bukin
200b1670691SRuslan Bukin etm_prepare(dev, event);
201b1670691SRuslan Bukin
202b1670691SRuslan Bukin /* Enable the trace unit */
203b1670691SRuslan Bukin bus_write_4(sc->res, TRCPRGCTLR, TRCPRGCTLR_EN);
204b1670691SRuslan Bukin
205b1670691SRuslan Bukin /* Wait for an IDLE bit to be LOW */
206b1670691SRuslan Bukin do {
207b1670691SRuslan Bukin reg = bus_read_4(sc->res, TRCSTATR);
208b1670691SRuslan Bukin } while ((reg & TRCSTATR_IDLE) == 1);
209b1670691SRuslan Bukin
210b1670691SRuslan Bukin if ((bus_read_4(sc->res, TRCPRGCTLR) & TRCPRGCTLR_EN) == 0)
211b1670691SRuslan Bukin panic("etm is not enabled\n");
212b1670691SRuslan Bukin
213b1670691SRuslan Bukin return (0);
214b1670691SRuslan Bukin }
215b1670691SRuslan Bukin
216b1670691SRuslan Bukin static void
etm_disable(device_t dev,struct endpoint * endp,struct coresight_event * event)217b1670691SRuslan Bukin etm_disable(device_t dev, struct endpoint *endp,
218b1670691SRuslan Bukin struct coresight_event *event)
219b1670691SRuslan Bukin {
220b1670691SRuslan Bukin struct etm_softc *sc;
221b1670691SRuslan Bukin uint32_t reg;
222b1670691SRuslan Bukin
223b1670691SRuslan Bukin sc = device_get_softc(dev);
224b1670691SRuslan Bukin
225b1670691SRuslan Bukin /* Disable the trace unit */
226b1670691SRuslan Bukin bus_write_4(sc->res, TRCPRGCTLR, 0);
227b1670691SRuslan Bukin
228b1670691SRuslan Bukin /* Wait for an IDLE bit */
229b1670691SRuslan Bukin do {
230b1670691SRuslan Bukin reg = bus_read_4(sc->res, TRCSTATR);
231b1670691SRuslan Bukin } while ((reg & TRCSTATR_IDLE) == 0);
232b1670691SRuslan Bukin }
233b1670691SRuslan Bukin
234c9ea007cSRuslan Bukin int
etm_attach(device_t dev)235b1670691SRuslan Bukin etm_attach(device_t dev)
236b1670691SRuslan Bukin {
237b1670691SRuslan Bukin struct coresight_desc desc;
238b1670691SRuslan Bukin struct etm_softc *sc;
239b1670691SRuslan Bukin
240b1670691SRuslan Bukin sc = device_get_softc(dev);
241b1670691SRuslan Bukin
242b1670691SRuslan Bukin if (bus_alloc_resources(dev, etm_spec, &sc->res) != 0) {
243b1670691SRuslan Bukin device_printf(dev, "cannot allocate resources for device\n");
244b1670691SRuslan Bukin return (ENXIO);
245b1670691SRuslan Bukin }
246b1670691SRuslan Bukin
247b1670691SRuslan Bukin desc.pdata = sc->pdata;
248b1670691SRuslan Bukin desc.dev = dev;
249b1670691SRuslan Bukin desc.dev_type = CORESIGHT_ETMV4;
250b1670691SRuslan Bukin coresight_register(&desc);
251b1670691SRuslan Bukin
252b1670691SRuslan Bukin return (0);
253b1670691SRuslan Bukin }
254b1670691SRuslan Bukin
255b1670691SRuslan Bukin static device_method_t etm_methods[] = {
256b1670691SRuslan Bukin /* Coresight interface */
257b1670691SRuslan Bukin DEVMETHOD(coresight_init, etm_init),
258b1670691SRuslan Bukin DEVMETHOD(coresight_enable, etm_enable),
259b1670691SRuslan Bukin DEVMETHOD(coresight_disable, etm_disable),
260b1670691SRuslan Bukin DEVMETHOD_END
261b1670691SRuslan Bukin };
262b1670691SRuslan Bukin
263b6f7bae4SRuslan Bukin DEFINE_CLASS_0(etm, etm_driver, etm_methods, sizeof(struct etm_softc));
264