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 bool enabled : 1;
109
110 /* buffer is split in half as a ping-pong buffer */
111 vm_object_t bufobj;
112 vm_offset_t kvaddr;
113 size_t buf_size;
114 uint8_t buf_idx : 1; /* 0 = first half of buf, 1 = 2nd half */
115 struct arm_spe_buf_info buf_info[2];
116
117 /* config */
118 enum arm_spe_profiling_level level;
119 enum arm_spe_ctx_field ctx_field;
120 /* filters */
121 uint64_t pmsfcr;
122 uint64_t pmsevfr;
123 uint64_t pmslatfr;
124 /* interval */
125 uint64_t pmsirr;
126 uint64_t pmsicr;
127 /* control */
128 uint64_t pmscr;
129 };
130
131 struct arm_spe_queue {
132 int ident;
133 u_int buf_idx : 1;
134 bool partial_rec : 1;
135 bool final_buf : 1;
136 vm_offset_t offset;
137 STAILQ_ENTRY(arm_spe_queue) next;
138 };
139
buf_start_addr(u_int buf_idx,struct arm_spe_info * info)140 static inline vm_offset_t buf_start_addr(u_int buf_idx, struct arm_spe_info *info)
141 {
142 vm_offset_t addr;
143 if (buf_idx == 0)
144 addr = info->kvaddr;
145 if (buf_idx == 1)
146 addr = info->kvaddr + (info->buf_size/2);
147
148 return (addr);
149 }
150
buf_end_addr(u_int buf_idx,struct arm_spe_info * info)151 static inline vm_offset_t buf_end_addr(u_int buf_idx, struct arm_spe_info *info)
152 {
153 vm_offset_t addr;
154 if (buf_idx == 0)
155 addr = info->kvaddr + (info->buf_size/2);
156 if (buf_idx == 1)
157 addr = info->kvaddr + info->buf_size;
158
159 return (addr);
160 }
161
162 #endif /* _ARM64_ARM_SPE_DEV_H_ */
163