1 // SPDX-License-Identifier: MIT 2 /* 3 * Copyright © 2025 Intel Corporation 4 */ 5 6 #include <linux/debugfs.h> 7 8 #include "xe_bo.h" 9 #include "xe_device.h" 10 #include "xe_configfs.h" 11 #include "xe_psmi.h" 12 13 /* 14 * PSMI capture support 15 * 16 * Requirement for PSMI capture is to have a physically contiguous buffer. The 17 * PSMI tool owns doing all necessary configuration (MMIO register writes are 18 * done from user-space). However, KMD needs to provide the PSMI tool with the 19 * required physical address of the base of PSMI buffer in case of VRAM. 20 * 21 * VRAM backed PSMI buffer: 22 * Buffer is allocated as GEM object and with XE_BO_CREATE_PINNED_BIT flag which 23 * creates a contiguous allocation. The physical address is returned from 24 * psmi_debugfs_capture_addr_show(). PSMI tool can mmap the buffer via the 25 * PCIBAR through sysfs. 26 * 27 * SYSTEM memory backed PSMI buffer: 28 * Interface here does not support allocating from SYSTEM memory region. The 29 * PSMI tool needs to allocate memory themselves using hugetlbfs. In order to 30 * get the physical address, user-space can query /proc/[pid]/pagemap. As an 31 * alternative, CMA debugfs could also be used to allocate reserved CMA memory. 32 */ 33 34 static bool psmi_enabled(struct xe_device *xe) 35 { 36 return xe_configfs_get_psmi_enabled(to_pci_dev(xe->drm.dev)); 37 } 38 39 static void psmi_free_object(struct xe_bo *bo) 40 { 41 xe_bo_lock(bo, NULL); 42 xe_bo_unpin(bo); 43 xe_bo_unlock(bo); 44 xe_bo_put(bo); 45 } 46 47 /* 48 * Free PSMI capture buffer objects. 49 */ 50 static void psmi_cleanup(struct xe_device *xe) 51 { 52 unsigned long id, region_mask = xe->psmi.region_mask; 53 struct xe_bo *bo; 54 55 for_each_set_bit(id, ®ion_mask, 56 ARRAY_SIZE(xe->psmi.capture_obj)) { 57 /* smem should never be set */ 58 xe_assert(xe, id); 59 60 bo = xe->psmi.capture_obj[id]; 61 if (bo) { 62 psmi_free_object(bo); 63 xe->psmi.capture_obj[id] = NULL; 64 } 65 } 66 } 67 68 static struct xe_bo *psmi_alloc_object(struct xe_device *xe, 69 unsigned int id, size_t bo_size) 70 { 71 struct xe_bo *bo = NULL; 72 struct xe_tile *tile; 73 int err; 74 75 if (!id || !bo_size) 76 return NULL; 77 78 tile = &xe->tiles[id - 1]; 79 80 /* VRAM: Allocate GEM object for the capture buffer */ 81 bo = xe_bo_create_locked(xe, tile, NULL, bo_size, 82 ttm_bo_type_kernel, 83 XE_BO_FLAG_VRAM_IF_DGFX(tile) | 84 XE_BO_FLAG_PINNED | 85 XE_BO_FLAG_PINNED_LATE_RESTORE | 86 XE_BO_FLAG_NEEDS_CPU_ACCESS); 87 88 if (!IS_ERR(bo)) { 89 /* Buffer written by HW, ensure stays resident */ 90 err = xe_bo_pin(bo); 91 if (err) 92 bo = ERR_PTR(err); 93 xe_bo_unlock(bo); 94 } 95 96 return bo; 97 } 98 99 /* 100 * Allocate PSMI capture buffer objects (via debugfs set function), based on 101 * which regions the user has selected in region_mask. @size: size in bytes 102 * (should be power of 2) 103 * 104 * Always release/free the current buffer objects before attempting to allocate 105 * new ones. Size == 0 will free all current buffers. 106 * 107 * Note, we don't write any registers as the capture tool is already configuring 108 * all PSMI registers itself via mmio space. 109 */ 110 static int psmi_resize_object(struct xe_device *xe, size_t size) 111 { 112 unsigned long id, region_mask = xe->psmi.region_mask; 113 struct xe_bo *bo = NULL; 114 int err = 0; 115 116 /* if resizing, free currently allocated buffers first */ 117 psmi_cleanup(xe); 118 119 /* can set size to 0, in which case, now done */ 120 if (!size) 121 return 0; 122 123 for_each_set_bit(id, ®ion_mask, 124 ARRAY_SIZE(xe->psmi.capture_obj)) { 125 /* smem should never be set */ 126 xe_assert(xe, id); 127 128 bo = psmi_alloc_object(xe, id, size); 129 if (IS_ERR(bo)) { 130 err = PTR_ERR(bo); 131 break; 132 } 133 xe->psmi.capture_obj[id] = bo; 134 135 drm_info(&xe->drm, 136 "PSMI capture size requested: %zu bytes, allocated: %lu:%zu\n", 137 size, id, bo ? xe_bo_size(bo) : 0); 138 } 139 140 /* on error, reverse what was allocated */ 141 if (err) 142 psmi_cleanup(xe); 143 144 return err; 145 } 146 147 /* 148 * Returns an address for the capture tool to use to find start of capture 149 * buffer. Capture tool requires the capability to have a buffer allocated per 150 * each tile (VRAM region), thus we return an address for each region. 151 */ 152 static int psmi_debugfs_capture_addr_show(struct seq_file *m, void *data) 153 { 154 struct xe_device *xe = m->private; 155 unsigned long id, region_mask; 156 struct xe_bo *bo; 157 u64 val; 158 159 region_mask = xe->psmi.region_mask; 160 for_each_set_bit(id, ®ion_mask, 161 ARRAY_SIZE(xe->psmi.capture_obj)) { 162 /* smem should never be set */ 163 xe_assert(xe, id); 164 165 /* VRAM region */ 166 bo = xe->psmi.capture_obj[id]; 167 if (!bo) 168 continue; 169 170 /* pinned, so don't need bo_lock */ 171 val = __xe_bo_addr(bo, 0, PAGE_SIZE); 172 seq_printf(m, "%ld: 0x%llx\n", id, val); 173 } 174 175 return 0; 176 } 177 178 /* 179 * Return capture buffer size, using the size from first allocated object that 180 * is found. This works because all objects must be of the same size. 181 */ 182 static int psmi_debugfs_capture_size_get(void *data, u64 *val) 183 { 184 unsigned long id, region_mask; 185 struct xe_device *xe = data; 186 struct xe_bo *bo; 187 188 region_mask = xe->psmi.region_mask; 189 for_each_set_bit(id, ®ion_mask, 190 ARRAY_SIZE(xe->psmi.capture_obj)) { 191 /* smem should never be set */ 192 xe_assert(xe, id); 193 194 bo = xe->psmi.capture_obj[id]; 195 if (bo) { 196 *val = xe_bo_size(bo); 197 return 0; 198 } 199 } 200 201 /* no capture objects are allocated */ 202 *val = 0; 203 204 return 0; 205 } 206 207 /* 208 * Set size of PSMI capture buffer. This triggers the allocation of capture 209 * buffer in each memory region as specified with prior write to 210 * psmi_capture_region_mask. 211 */ 212 static int psmi_debugfs_capture_size_set(void *data, u64 val) 213 { 214 struct xe_device *xe = data; 215 216 /* user must have specified at least one region */ 217 if (!xe->psmi.region_mask) 218 return -EINVAL; 219 220 return psmi_resize_object(xe, val); 221 } 222 223 static int psmi_debugfs_capture_region_mask_get(void *data, u64 *val) 224 { 225 struct xe_device *xe = data; 226 227 *val = xe->psmi.region_mask; 228 229 return 0; 230 } 231 232 /* 233 * Select VRAM regions for multi-tile devices, only allowed when buffer is not 234 * currently allocated. 235 */ 236 static int psmi_debugfs_capture_region_mask_set(void *data, u64 region_mask) 237 { 238 struct xe_device *xe = data; 239 u64 size = 0; 240 241 /* SMEM is not supported (see comments at top of file) */ 242 if (region_mask & 0x1) 243 return -EOPNOTSUPP; 244 245 /* input bitmask should contain only valid TTM regions */ 246 if (!region_mask || region_mask & ~xe->info.mem_region_mask) 247 return -EINVAL; 248 249 /* only allow setting mask if buffer is not yet allocated */ 250 psmi_debugfs_capture_size_get(xe, &size); 251 if (size) 252 return -EBUSY; 253 254 xe->psmi.region_mask = region_mask; 255 256 return 0; 257 } 258 259 DEFINE_SHOW_ATTRIBUTE(psmi_debugfs_capture_addr); 260 261 DEFINE_DEBUGFS_ATTRIBUTE(psmi_debugfs_capture_region_mask_fops, 262 psmi_debugfs_capture_region_mask_get, 263 psmi_debugfs_capture_region_mask_set, 264 "0x%llx\n"); 265 266 DEFINE_DEBUGFS_ATTRIBUTE(psmi_debugfs_capture_size_fops, 267 psmi_debugfs_capture_size_get, 268 psmi_debugfs_capture_size_set, 269 "%lld\n"); 270 271 void xe_psmi_debugfs_register(struct xe_device *xe) 272 { 273 struct drm_minor *minor; 274 275 if (!psmi_enabled(xe)) 276 return; 277 278 minor = xe->drm.primary; 279 if (!minor->debugfs_root) 280 return; 281 282 debugfs_create_file("psmi_capture_addr", 283 0400, minor->debugfs_root, xe, 284 &psmi_debugfs_capture_addr_fops); 285 286 debugfs_create_file("psmi_capture_region_mask", 287 0600, minor->debugfs_root, xe, 288 &psmi_debugfs_capture_region_mask_fops); 289 290 debugfs_create_file("psmi_capture_size", 291 0600, minor->debugfs_root, xe, 292 &psmi_debugfs_capture_size_fops); 293 } 294 295 static void psmi_fini(void *arg) 296 { 297 psmi_cleanup(arg); 298 } 299 300 int xe_psmi_init(struct xe_device *xe) 301 { 302 if (!psmi_enabled(xe)) 303 return 0; 304 305 return devm_add_action(xe->drm.dev, psmi_fini, xe); 306 } 307