Skip to content

Commit

Permalink
drm/amdgpu: Return -EPROBE_DEFER when amdkfd not loaded
Browse files Browse the repository at this point in the history
amdgpu must load only after amdkfd's loading has been completed. If that
is not enforced, then amdgpu's call into amdkfd's functions will cause a
kernel BUG.

When amdgpu and amdkfd are built as kernel modules, that rule is enforced
by the kernel's modules loading mechanism. When amdgpu and amdkfd are
built inside the kernel image, that rule is enforced by ordering in the
drm Makefile (amdkfd before amdgpu).

Instead of using drm Makefile ordering, we can now use deferred loading
as amdkfd now returns -EPROBE_DEFER in kgd2kfd_init() when it is not yet
loaded.

This patch defers amdgpu loading by propagating -EPROBE_DEFER to the
kernel's drivers loading infrastructure. That will put amdgpu into the
pending drivers list (see description in dd.c). Once amdkfd is loaded,
a call to kgd2kfd_init() will return successfully and amdgpu will be able
to load.

Signed-off-by: Oded Gabbay <oded.gabbay@gmail.com>
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
  • Loading branch information
Oded Gabbay committed Feb 27, 2016
1 parent 412c8f7 commit efb1c65
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 39 deletions.
57 changes: 21 additions & 36 deletions drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,25 +30,38 @@ const struct kfd2kgd_calls *kfd2kgd;
const struct kgd2kfd_calls *kgd2kfd;
bool (*kgd2kfd_init_p)(unsigned, const struct kgd2kfd_calls**);

bool amdgpu_amdkfd_init(void)
int amdgpu_amdkfd_init(void)
{
int ret;

#if defined(CONFIG_HSA_AMD_MODULE)
bool (*kgd2kfd_init_p)(unsigned, const struct kgd2kfd_calls**);
int (*kgd2kfd_init_p)(unsigned, const struct kgd2kfd_calls**);

kgd2kfd_init_p = symbol_request(kgd2kfd_init);

if (kgd2kfd_init_p == NULL)
return false;
return -ENOENT;

ret = kgd2kfd_init_p(KFD_INTERFACE_VERSION, &kgd2kfd);
if (ret) {
symbol_put(kgd2kfd_init);
kgd2kfd = NULL;
}

#elif defined(CONFIG_HSA_AMD)
ret = kgd2kfd_init(KFD_INTERFACE_VERSION, &kgd2kfd);
if (ret)
kgd2kfd = NULL;

#else
ret = -ENOENT;
#endif
return true;

return ret;
}

bool amdgpu_amdkfd_load_interface(struct amdgpu_device *rdev)
{
#if defined(CONFIG_HSA_AMD_MODULE)
bool (*kgd2kfd_init_p)(unsigned, const struct kgd2kfd_calls**);
#endif

switch (rdev->asic_type) {
#ifdef CONFIG_DRM_AMDGPU_CIK
case CHIP_KAVERI:
Expand All @@ -62,35 +75,7 @@ bool amdgpu_amdkfd_load_interface(struct amdgpu_device *rdev)
return false;
}

#if defined(CONFIG_HSA_AMD_MODULE)
kgd2kfd_init_p = symbol_request(kgd2kfd_init);

if (kgd2kfd_init_p == NULL) {
kfd2kgd = NULL;
return false;
}

if (kgd2kfd_init_p(KFD_INTERFACE_VERSION, &kgd2kfd)) {
symbol_put(kgd2kfd_init);
kfd2kgd = NULL;
kgd2kfd = NULL;

return false;
}

return true;
#elif defined(CONFIG_HSA_AMD)
if (kgd2kfd_init(KFD_INTERFACE_VERSION, &kgd2kfd)) {
kfd2kgd = NULL;
kgd2kfd = NULL;
return false;
}

return true;
#else
kfd2kgd = NULL;
return false;
#endif
}

void amdgpu_amdkfd_fini(void)
Expand Down
2 changes: 1 addition & 1 deletion drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ struct kgd_mem {
void *cpu_ptr;
};

bool amdgpu_amdkfd_init(void);
int amdgpu_amdkfd_init(void);
void amdgpu_amdkfd_fini(void);

bool amdgpu_amdkfd_load_interface(struct amdgpu_device *rdev);
Expand Down
10 changes: 8 additions & 2 deletions drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,14 @@ static int amdgpu_pci_probe(struct pci_dev *pdev,
return -ENODEV;
}

/*
* Initialize amdkfd before starting radeon. If it was not loaded yet,
* defer radeon probing
*/
ret = amdgpu_amdkfd_init();
if (ret == -EPROBE_DEFER)
return ret;

/* Get rid of things like offb */
ret = amdgpu_kick_out_firmware_fb(pdev);
if (ret)
Expand Down Expand Up @@ -552,8 +560,6 @@ static int __init amdgpu_init(void)
driver->num_ioctls = amdgpu_max_kms_ioctl;
amdgpu_register_atpx_handler();

amdgpu_amdkfd_init();

/* let modprobe override vga console setting */
return drm_pci_init(driver, pdriver);
}
Expand Down

0 comments on commit efb1c65

Please sign in to comment.