1/*-
2 * Copyright (c) 2018 Ruslan Bukin <br@bsdpad.com>
3 * All rights reserved.
4 *
5 * This software was developed by SRI International and the University of
6 * Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237
7 * ("CTSRD"), as part of the DARPA CRASH research programme.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31#include <sys/cdefs.h>
32__FBSDID("$FreeBSD$");
33
34#include <sys/param.h>
35#include <sys/systm.h>
36#include <sys/bus.h>
37#include <sys/rman.h>
38#include <sys/kernel.h>
39#include <sys/module.h>
40#include <machine/bus.h>
41
42#include <arm64/coresight/coresight.h>
43
44#include "coresight_if.h"
45
46extern struct coresight_device_list cs_devs;
47
48static struct coresight_device *
49coresight_next_device(struct coresight_device *cs_dev,
50    struct coresight_event *event)
51{
52	struct coresight_device *out;
53	struct endpoint *out_endp;
54	struct endpoint *endp;
55
56	TAILQ_FOREACH(endp, &cs_dev->pdata->endpoints, link) {
57		if (endp->slave != 0)
58			continue;
59
60		out = coresight_get_output_device(endp, &out_endp);
61		if (out != NULL) {
62			if (LIST_EMPTY(&event->endplist)) {
63				/* Add source device */
64				endp->cs_dev = cs_dev;
65				LIST_INSERT_HEAD(&event->endplist, endp,
66				    endplink);
67			}
68
69			/* Add output device */
70			out_endp->cs_dev = out;
71			LIST_INSERT_HEAD(&event->endplist, out_endp, endplink);
72
73			return (out);
74		}
75	}
76
77	return (NULL);
78}
79
80static int
81coresight_build_list(struct coresight_device *cs_dev,
82    struct coresight_event *event)
83{
84	struct coresight_device *out;
85
86	out = cs_dev;
87	while (out != NULL)
88		out = coresight_next_device(out, event);
89
90	return (0);
91}
92
93int
94coresight_init_event(int cpu, struct coresight_event *event)
95{
96	struct coresight_device *cs_dev;
97	struct endpoint *endp;
98
99	/* Start building path from source device */
100	TAILQ_FOREACH(cs_dev, &cs_devs, link) {
101		if (cs_dev->dev_type == event->src &&
102		    cs_dev->pdata->cpu == cpu) {
103			LIST_INIT(&event->endplist);
104			coresight_build_list(cs_dev, event);
105			break;
106		}
107	}
108
109	/* Ensure Coresight is initialized for the CPU */
110	TAILQ_FOREACH(cs_dev, &cs_devs, link) {
111		if (cs_dev->dev_type == CORESIGHT_CPU_DEBUG &&
112		    cs_dev->pdata->cpu == cpu)
113			CORESIGHT_INIT(cs_dev->dev);
114	}
115
116	/* Init all devices in the path */
117	LIST_FOREACH(endp, &event->endplist, endplink) {
118		cs_dev = endp->cs_dev;
119		CORESIGHT_INIT(cs_dev->dev);
120	}
121
122	return (0);
123}
124
125void
126coresight_enable(int cpu, struct coresight_event *event)
127{
128	struct coresight_device *cs_dev;
129	struct endpoint *endp;
130
131	LIST_FOREACH(endp, &event->endplist, endplink) {
132		cs_dev = endp->cs_dev;
133		CORESIGHT_ENABLE(cs_dev->dev, endp, event);
134	}
135}
136
137void
138coresight_disable(int cpu, struct coresight_event *event)
139{
140	struct coresight_device *cs_dev;
141	struct endpoint *endp;
142
143	LIST_FOREACH(endp, &event->endplist, endplink) {
144		cs_dev = endp->cs_dev;
145		CORESIGHT_DISABLE(cs_dev->dev, endp, event);
146	}
147}
148
149void
150coresight_read(int cpu, struct coresight_event *event)
151{
152	struct endpoint *endp;
153
154	LIST_FOREACH(endp, &event->endplist, endplink)
155		CORESIGHT_READ(endp->cs_dev->dev, endp, event);
156}
157