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 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 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