Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/amdkfd: Separate doorbell allocation from PASID

PASID management is moving into KGD. Limiting the PASID range to the
number of doorbell pages is no longer practical.

Signed-off-by: Felix Kuehling <Felix.Kuehling@amd.com>
Acked-by: Alex Deucher <alexander.deucher@amd.com>
Reviewed-by: Oded Gabbay <oded.gabbay@gmail.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>

authored by

Felix Kuehling and committed by
Alex Deucher
a91e70e3 f4d6229b

+45 -28
-7
drivers/gpu/drm/amd/amdkfd/kfd_device.c
··· 168 168 pasid_limit = min_t(unsigned int, 169 169 (unsigned int)(1 << kfd->device_info->max_pasid_bits), 170 170 iommu_info.max_pasids); 171 - /* 172 - * last pasid is used for kernel queues doorbells 173 - * in the future the last pasid might be used for a kernel thread. 174 - */ 175 - pasid_limit = min_t(unsigned int, 176 - pasid_limit, 177 - kfd->doorbell_process_limit - 1); 178 171 179 172 err = amd_iommu_init_device(kfd->pdev, pasid_limit); 180 173 if (err < 0) {
+34 -16
drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c
··· 24 24 #include <linux/mman.h> 25 25 #include <linux/slab.h> 26 26 #include <linux/io.h> 27 + #include <linux/idr.h> 27 28 28 29 /* 29 - * This extension supports a kernel level doorbells management for 30 - * the kernel queues. 31 - * Basically the last doorbells page is devoted to kernel queues 32 - * and that's assures that any user process won't get access to the 33 - * kernel doorbells page 30 + * This extension supports a kernel level doorbells management for the 31 + * kernel queues using the first doorbell page reserved for the kernel. 34 32 */ 35 33 36 - #define KERNEL_DOORBELL_PASID 1 34 + static DEFINE_IDA(doorbell_ida); 35 + static unsigned int max_doorbell_slices; 37 36 #define KFD_SIZE_OF_DOORBELL_IN_BYTES 4 38 37 39 38 /* ··· 83 84 (doorbell_aperture_size - doorbell_start_offset) / 84 85 doorbell_process_allocation(); 85 86 else 86 - doorbell_process_limit = 0; 87 + return -ENOSPC; 88 + 89 + if (!max_doorbell_slices || 90 + doorbell_process_limit < max_doorbell_slices) 91 + max_doorbell_slices = doorbell_process_limit; 87 92 88 93 kfd->doorbell_base = kfd->shared_resources.doorbell_physical_address + 89 94 doorbell_start_offset; 90 95 91 96 kfd->doorbell_id_offset = doorbell_start_offset / sizeof(u32); 92 - kfd->doorbell_process_limit = doorbell_process_limit - 1; 93 97 94 98 kfd->doorbell_kernel_ptr = ioremap(kfd->doorbell_base, 95 99 doorbell_process_allocation()); ··· 187 185 return NULL; 188 186 189 187 /* 190 - * Calculating the kernel doorbell offset using "faked" kernel 191 - * pasid that allocated for kernel queues only 188 + * Calculating the kernel doorbell offset using the first 189 + * doorbell page. 192 190 */ 193 - *doorbell_off = KERNEL_DOORBELL_PASID * (doorbell_process_allocation() / 194 - sizeof(u32)) + inx; 191 + *doorbell_off = kfd->doorbell_id_offset + inx; 195 192 196 193 pr_debug("Get kernel queue doorbell\n" 197 194 " doorbell offset == 0x%08X\n" ··· 229 228 { 230 229 /* 231 230 * doorbell_id_offset accounts for doorbells taken by KGD. 232 - * pasid * doorbell_process_allocation/sizeof(u32) adjusts 233 - * to the process's doorbells 231 + * index * doorbell_process_allocation/sizeof(u32) adjusts to 232 + * the process's doorbells. 234 233 */ 235 234 return kfd->doorbell_id_offset + 236 - process->pasid * (doorbell_process_allocation()/sizeof(u32)) + 235 + process->doorbell_index 236 + * doorbell_process_allocation() / sizeof(u32) + 237 237 queue_id; 238 238 } 239 239 ··· 252 250 struct kfd_process *process) 253 251 { 254 252 return dev->doorbell_base + 255 - process->pasid * doorbell_process_allocation(); 253 + process->doorbell_index * doorbell_process_allocation(); 254 + } 255 + 256 + int kfd_alloc_process_doorbells(struct kfd_process *process) 257 + { 258 + int r = ida_simple_get(&doorbell_ida, 1, max_doorbell_slices, 259 + GFP_KERNEL); 260 + if (r > 0) 261 + process->doorbell_index = r; 262 + 263 + return r; 264 + } 265 + 266 + void kfd_free_process_doorbells(struct kfd_process *process) 267 + { 268 + if (process->doorbell_index) 269 + ida_simple_remove(&doorbell_ida, process->doorbell_index); 256 270 }
+5 -5
drivers/gpu/drm/amd/amdkfd/kfd_priv.h
··· 157 157 * to HW doorbell, GFX reserved some 158 158 * at the start) 159 159 */ 160 - size_t doorbell_process_limit; /* Number of processes we have doorbell 161 - * space for. 162 - */ 163 160 u32 __iomem *doorbell_kernel_ptr; /* This is a pointer for a doorbells 164 161 * page used by kernel queue 165 162 */ ··· 492 495 struct rcu_head rcu; 493 496 494 497 unsigned int pasid; 498 + unsigned int doorbell_index; 495 499 496 500 /* 497 501 * List of kfd_process_device structures, ··· 581 583 unsigned int kfd_queue_id_to_doorbell(struct kfd_dev *kfd, 582 584 struct kfd_process *process, 583 585 unsigned int queue_id); 586 + phys_addr_t kfd_get_process_doorbells(struct kfd_dev *dev, 587 + struct kfd_process *process); 588 + int kfd_alloc_process_doorbells(struct kfd_process *process); 589 + void kfd_free_process_doorbells(struct kfd_process *process); 584 590 585 591 /* GTT Sub-Allocator */ 586 592 ··· 696 694 void pm_release_ib(struct packet_manager *pm); 697 695 698 696 uint64_t kfd_get_number_elems(struct kfd_dev *kfd); 699 - phys_addr_t kfd_get_process_doorbells(struct kfd_dev *dev, 700 - struct kfd_process *process); 701 697 702 698 /* Events */ 703 699 extern const struct kfd_event_interrupt_class event_interrupt_class_cik;
+6
drivers/gpu/drm/amd/amdkfd/kfd_process.c
··· 183 183 kfd_event_free_process(p); 184 184 185 185 kfd_pasid_free(p->pasid); 186 + kfd_free_process_doorbells(p); 186 187 187 188 mutex_unlock(&p->mutex); 188 189 ··· 289 288 if (process->pasid == 0) 290 289 goto err_alloc_pasid; 291 290 291 + if (kfd_alloc_process_doorbells(process) < 0) 292 + goto err_alloc_doorbells; 293 + 292 294 mutex_init(&process->mutex); 293 295 294 296 process->mm = thread->mm; ··· 333 329 mmu_notifier_unregister_no_release(&process->mmu_notifier, process->mm); 334 330 err_mmu_notifier: 335 331 mutex_destroy(&process->mutex); 332 + kfd_free_process_doorbells(process); 333 + err_alloc_doorbells: 336 334 kfd_pasid_free(process->pasid); 337 335 err_alloc_pasid: 338 336 kfree(process->queues);