1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2024 Arm Ltd
5 * Copyright (c) 2022 The FreeBSD Foundation
6 *
7 * Portions of this software were developed by Andrew Turner under sponsorship
8 * from the FreeBSD Foundation.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 #ifndef _ARM64_ARM_SPE_DEV_H_
33 #define _ARM64_ARM_SPE_DEV_H_
34
35 #include <sys/mutex.h>
36 #include <sys/taskqueue.h>
37
38 #include <vm/vm.h>
39
40 #include <arm64/spe/arm_spe.h>
41
42 #include <dev/hwt/hwt_context.h>
43
44 #define ARM_SPE_DEBUG
45 #undef ARM_SPE_DEBUG
46
47 #ifdef ARM_SPE_DEBUG
48 #define dprintf(fmt, ...) printf(fmt, ##__VA_ARGS__)
49 #else
50 #define dprintf(fmt, ...)
51 #endif
52
53 DECLARE_CLASS(arm_spe_driver);
54
55 struct cdev;
56 struct resource;
57
58 extern bool arm64_pid_in_contextidr;
59
60 int spe_register(device_t dev);
61 void arm_spe_disable(void *arg __unused);
62 int spe_backend_disable_smp(struct hwt_context *ctx);
63 void arm_spe_send_buffer(void *arg, int pending __unused);
64
65 /*
66 PSB CSYNC is a Profiling Synchronization Barrier encoded in the hint space
67 * so it is a NOP on earlier architecture.
68 */
69 #define psb_csync() __asm __volatile("hint #17" ::: "memory");
70
71 struct arm_spe_softc {
72 device_t dev;
73
74 struct resource *sc_irq_res;
75 void *sc_irq_cookie;
76 struct cdev *sc_cdev;
77 struct mtx sc_lock;
78 struct task task;
79
80 int64_t sc_pmsidr;
81 int kqueue_fd;
82 struct thread *hwt_td;
83 struct arm_spe_info **spe_info;
84 struct hwt_context *ctx;
85 STAILQ_HEAD(, arm_spe_queue) pending;
86 uint64_t npending;
87
88 uint64_t pmbidr;
89 uint64_t pmsidr;
90
91 uint16_t kva_align;
92 };
93
94 struct arm_spe_buf_info {
95 struct arm_spe_info *info;
96 uint64_t pmbptr;
97 uint8_t buf_idx : 1;
98 bool buf_svc : 1;
99 bool buf_wait : 1;
100 bool partial_rec : 1;
101 };
102
103 struct arm_spe_info {
104 int ident; /* tid or cpu_id */
105 struct mtx lock;
106 struct arm_spe_softc *sc;
107 struct task task[2];
108 struct task flush_task;
109 bool enabled : 1;
110 bool stopped : 1;
111
112 /* buffer is split in half as a ping-pong buffer */
113 vm_object_t bufobj;
114 vm_offset_t kvaddr;
115 size_t buf_size;
116 uint8_t buf_idx : 1; /* 0 = first half of buf, 1 = 2nd half */
117 struct arm_spe_buf_info buf_info[2];
118
119 /* config */
120 enum arm_spe_profiling_level level;
121 enum arm_spe_ctx_field ctx_field;
122 /* filters */
123 uint64_t pmsfcr;
124 uint64_t pmsevfr;
125 uint64_t pmslatfr;
126 /* interval */
127 uint64_t pmsirr;
128 uint64_t pmsicr;
129 /* control */
130 uint64_t pmscr;
131 };
132
133 struct arm_spe_queue {
134 int ident;
135 u_int buf_idx : 1;
136 bool partial_rec : 1;
137 bool final_buf : 1;
138 vm_offset_t offset;
139 STAILQ_ENTRY(arm_spe_queue) next;
140 };
141
buf_start_addr(u_int buf_idx,struct arm_spe_info * info)142 static inline vm_offset_t buf_start_addr(u_int buf_idx, struct arm_spe_info *info)
143 {
144 vm_offset_t addr;
145 if (buf_idx == 0)
146 addr = info->kvaddr;
147 if (buf_idx == 1)
148 addr = info->kvaddr + (info->buf_size/2);
149
150 return (addr);
151 }
152
buf_end_addr(u_int buf_idx,struct arm_spe_info * info)153 static inline vm_offset_t buf_end_addr(u_int buf_idx, struct arm_spe_info *info)
154 {
155 vm_offset_t addr;
156 if (buf_idx == 0)
157 addr = info->kvaddr + (info->buf_size/2);
158 if (buf_idx == 1)
159 addr = info->kvaddr + info->buf_size;
160
161 return (addr);
162 }
163
164 #endif /* _ARM64_ARM_SPE_DEV_H_ */
165