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>
This commit is contained in:
parent
f4d6229b9d
commit
a91e70e30c
|
@ -168,13 +168,6 @@ static bool device_iommu_pasid_init(struct kfd_dev *kfd)
|
||||||
pasid_limit = min_t(unsigned int,
|
pasid_limit = min_t(unsigned int,
|
||||||
(unsigned int)(1 << kfd->device_info->max_pasid_bits),
|
(unsigned int)(1 << kfd->device_info->max_pasid_bits),
|
||||||
iommu_info.max_pasids);
|
iommu_info.max_pasids);
|
||||||
/*
|
|
||||||
* last pasid is used for kernel queues doorbells
|
|
||||||
* in the future the last pasid might be used for a kernel thread.
|
|
||||||
*/
|
|
||||||
pasid_limit = min_t(unsigned int,
|
|
||||||
pasid_limit,
|
|
||||||
kfd->doorbell_process_limit - 1);
|
|
||||||
|
|
||||||
err = amd_iommu_init_device(kfd->pdev, pasid_limit);
|
err = amd_iommu_init_device(kfd->pdev, pasid_limit);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
|
|
|
@ -24,16 +24,15 @@
|
||||||
#include <linux/mman.h>
|
#include <linux/mman.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
|
#include <linux/idr.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This extension supports a kernel level doorbells management for
|
* This extension supports a kernel level doorbells management for the
|
||||||
* the kernel queues.
|
* kernel queues using the first doorbell page reserved for the kernel.
|
||||||
* Basically the last doorbells page is devoted to kernel queues
|
|
||||||
* and that's assures that any user process won't get access to the
|
|
||||||
* kernel doorbells page
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define KERNEL_DOORBELL_PASID 1
|
static DEFINE_IDA(doorbell_ida);
|
||||||
|
static unsigned int max_doorbell_slices;
|
||||||
#define KFD_SIZE_OF_DOORBELL_IN_BYTES 4
|
#define KFD_SIZE_OF_DOORBELL_IN_BYTES 4
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -84,13 +83,16 @@ int kfd_doorbell_init(struct kfd_dev *kfd)
|
||||||
(doorbell_aperture_size - doorbell_start_offset) /
|
(doorbell_aperture_size - doorbell_start_offset) /
|
||||||
doorbell_process_allocation();
|
doorbell_process_allocation();
|
||||||
else
|
else
|
||||||
doorbell_process_limit = 0;
|
return -ENOSPC;
|
||||||
|
|
||||||
|
if (!max_doorbell_slices ||
|
||||||
|
doorbell_process_limit < max_doorbell_slices)
|
||||||
|
max_doorbell_slices = doorbell_process_limit;
|
||||||
|
|
||||||
kfd->doorbell_base = kfd->shared_resources.doorbell_physical_address +
|
kfd->doorbell_base = kfd->shared_resources.doorbell_physical_address +
|
||||||
doorbell_start_offset;
|
doorbell_start_offset;
|
||||||
|
|
||||||
kfd->doorbell_id_offset = doorbell_start_offset / sizeof(u32);
|
kfd->doorbell_id_offset = doorbell_start_offset / sizeof(u32);
|
||||||
kfd->doorbell_process_limit = doorbell_process_limit - 1;
|
|
||||||
|
|
||||||
kfd->doorbell_kernel_ptr = ioremap(kfd->doorbell_base,
|
kfd->doorbell_kernel_ptr = ioremap(kfd->doorbell_base,
|
||||||
doorbell_process_allocation());
|
doorbell_process_allocation());
|
||||||
|
@ -185,11 +187,10 @@ u32 __iomem *kfd_get_kernel_doorbell(struct kfd_dev *kfd,
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Calculating the kernel doorbell offset using "faked" kernel
|
* Calculating the kernel doorbell offset using the first
|
||||||
* pasid that allocated for kernel queues only
|
* doorbell page.
|
||||||
*/
|
*/
|
||||||
*doorbell_off = KERNEL_DOORBELL_PASID * (doorbell_process_allocation() /
|
*doorbell_off = kfd->doorbell_id_offset + inx;
|
||||||
sizeof(u32)) + inx;
|
|
||||||
|
|
||||||
pr_debug("Get kernel queue doorbell\n"
|
pr_debug("Get kernel queue doorbell\n"
|
||||||
" doorbell offset == 0x%08X\n"
|
" doorbell offset == 0x%08X\n"
|
||||||
|
@ -228,11 +229,12 @@ unsigned int kfd_queue_id_to_doorbell(struct kfd_dev *kfd,
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* doorbell_id_offset accounts for doorbells taken by KGD.
|
* doorbell_id_offset accounts for doorbells taken by KGD.
|
||||||
* pasid * doorbell_process_allocation/sizeof(u32) adjusts
|
* index * doorbell_process_allocation/sizeof(u32) adjusts to
|
||||||
* to the process's doorbells
|
* the process's doorbells.
|
||||||
*/
|
*/
|
||||||
return kfd->doorbell_id_offset +
|
return kfd->doorbell_id_offset +
|
||||||
process->pasid * (doorbell_process_allocation()/sizeof(u32)) +
|
process->doorbell_index
|
||||||
|
* doorbell_process_allocation() / sizeof(u32) +
|
||||||
queue_id;
|
queue_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -250,5 +252,21 @@ phys_addr_t kfd_get_process_doorbells(struct kfd_dev *dev,
|
||||||
struct kfd_process *process)
|
struct kfd_process *process)
|
||||||
{
|
{
|
||||||
return dev->doorbell_base +
|
return dev->doorbell_base +
|
||||||
process->pasid * doorbell_process_allocation();
|
process->doorbell_index * doorbell_process_allocation();
|
||||||
|
}
|
||||||
|
|
||||||
|
int kfd_alloc_process_doorbells(struct kfd_process *process)
|
||||||
|
{
|
||||||
|
int r = ida_simple_get(&doorbell_ida, 1, max_doorbell_slices,
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (r > 0)
|
||||||
|
process->doorbell_index = r;
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
void kfd_free_process_doorbells(struct kfd_process *process)
|
||||||
|
{
|
||||||
|
if (process->doorbell_index)
|
||||||
|
ida_simple_remove(&doorbell_ida, process->doorbell_index);
|
||||||
}
|
}
|
||||||
|
|
|
@ -157,9 +157,6 @@ struct kfd_dev {
|
||||||
* to HW doorbell, GFX reserved some
|
* to HW doorbell, GFX reserved some
|
||||||
* at the start)
|
* at the start)
|
||||||
*/
|
*/
|
||||||
size_t doorbell_process_limit; /* Number of processes we have doorbell
|
|
||||||
* space for.
|
|
||||||
*/
|
|
||||||
u32 __iomem *doorbell_kernel_ptr; /* This is a pointer for a doorbells
|
u32 __iomem *doorbell_kernel_ptr; /* This is a pointer for a doorbells
|
||||||
* page used by kernel queue
|
* page used by kernel queue
|
||||||
*/
|
*/
|
||||||
|
@ -495,6 +492,7 @@ struct kfd_process {
|
||||||
struct rcu_head rcu;
|
struct rcu_head rcu;
|
||||||
|
|
||||||
unsigned int pasid;
|
unsigned int pasid;
|
||||||
|
unsigned int doorbell_index;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* List of kfd_process_device structures,
|
* List of kfd_process_device structures,
|
||||||
|
@ -583,6 +581,10 @@ void write_kernel_doorbell(u32 __iomem *db, u32 value);
|
||||||
unsigned int kfd_queue_id_to_doorbell(struct kfd_dev *kfd,
|
unsigned int kfd_queue_id_to_doorbell(struct kfd_dev *kfd,
|
||||||
struct kfd_process *process,
|
struct kfd_process *process,
|
||||||
unsigned int queue_id);
|
unsigned int queue_id);
|
||||||
|
phys_addr_t kfd_get_process_doorbells(struct kfd_dev *dev,
|
||||||
|
struct kfd_process *process);
|
||||||
|
int kfd_alloc_process_doorbells(struct kfd_process *process);
|
||||||
|
void kfd_free_process_doorbells(struct kfd_process *process);
|
||||||
|
|
||||||
/* GTT Sub-Allocator */
|
/* GTT Sub-Allocator */
|
||||||
|
|
||||||
|
@ -694,8 +696,6 @@ int pm_send_unmap_queue(struct packet_manager *pm, enum kfd_queue_type type,
|
||||||
void pm_release_ib(struct packet_manager *pm);
|
void pm_release_ib(struct packet_manager *pm);
|
||||||
|
|
||||||
uint64_t kfd_get_number_elems(struct kfd_dev *kfd);
|
uint64_t kfd_get_number_elems(struct kfd_dev *kfd);
|
||||||
phys_addr_t kfd_get_process_doorbells(struct kfd_dev *dev,
|
|
||||||
struct kfd_process *process);
|
|
||||||
|
|
||||||
/* Events */
|
/* Events */
|
||||||
extern const struct kfd_event_interrupt_class event_interrupt_class_cik;
|
extern const struct kfd_event_interrupt_class event_interrupt_class_cik;
|
||||||
|
|
|
@ -183,6 +183,7 @@ static void kfd_process_wq_release(struct work_struct *work)
|
||||||
kfd_event_free_process(p);
|
kfd_event_free_process(p);
|
||||||
|
|
||||||
kfd_pasid_free(p->pasid);
|
kfd_pasid_free(p->pasid);
|
||||||
|
kfd_free_process_doorbells(p);
|
||||||
|
|
||||||
mutex_unlock(&p->mutex);
|
mutex_unlock(&p->mutex);
|
||||||
|
|
||||||
|
@ -288,6 +289,9 @@ static struct kfd_process *create_process(const struct task_struct *thread)
|
||||||
if (process->pasid == 0)
|
if (process->pasid == 0)
|
||||||
goto err_alloc_pasid;
|
goto err_alloc_pasid;
|
||||||
|
|
||||||
|
if (kfd_alloc_process_doorbells(process) < 0)
|
||||||
|
goto err_alloc_doorbells;
|
||||||
|
|
||||||
mutex_init(&process->mutex);
|
mutex_init(&process->mutex);
|
||||||
|
|
||||||
process->mm = thread->mm;
|
process->mm = thread->mm;
|
||||||
|
@ -329,6 +333,8 @@ static struct kfd_process *create_process(const struct task_struct *thread)
|
||||||
mmu_notifier_unregister_no_release(&process->mmu_notifier, process->mm);
|
mmu_notifier_unregister_no_release(&process->mmu_notifier, process->mm);
|
||||||
err_mmu_notifier:
|
err_mmu_notifier:
|
||||||
mutex_destroy(&process->mutex);
|
mutex_destroy(&process->mutex);
|
||||||
|
kfd_free_process_doorbells(process);
|
||||||
|
err_alloc_doorbells:
|
||||||
kfd_pasid_free(process->pasid);
|
kfd_pasid_free(process->pasid);
|
||||||
err_alloc_pasid:
|
err_alloc_pasid:
|
||||||
kfree(process->queues);
|
kfree(process->queues);
|
||||||
|
|
Loading…
Reference in New Issue