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

drm/amdgpu: Return -EPROBE_DEFER when amdkfd not loaded

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>

+30 -39
+21 -36
drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
··· 30 30 const struct kgd2kfd_calls *kgd2kfd; 31 31 bool (*kgd2kfd_init_p)(unsigned, const struct kgd2kfd_calls**); 32 32 33 - bool amdgpu_amdkfd_init(void) 33 + int amdgpu_amdkfd_init(void) 34 34 { 35 + int ret; 36 + 35 37 #if defined(CONFIG_HSA_AMD_MODULE) 36 - bool (*kgd2kfd_init_p)(unsigned, const struct kgd2kfd_calls**); 38 + int (*kgd2kfd_init_p)(unsigned, const struct kgd2kfd_calls**); 37 39 38 40 kgd2kfd_init_p = symbol_request(kgd2kfd_init); 39 41 40 42 if (kgd2kfd_init_p == NULL) 41 - return false; 43 + return -ENOENT; 44 + 45 + ret = kgd2kfd_init_p(KFD_INTERFACE_VERSION, &kgd2kfd); 46 + if (ret) { 47 + symbol_put(kgd2kfd_init); 48 + kgd2kfd = NULL; 49 + } 50 + 51 + #elif defined(CONFIG_HSA_AMD) 52 + ret = kgd2kfd_init(KFD_INTERFACE_VERSION, &kgd2kfd); 53 + if (ret) 54 + kgd2kfd = NULL; 55 + 56 + #else 57 + ret = -ENOENT; 42 58 #endif 43 - return true; 59 + 60 + return ret; 44 61 } 45 62 46 63 bool amdgpu_amdkfd_load_interface(struct amdgpu_device *rdev) 47 64 { 48 - #if defined(CONFIG_HSA_AMD_MODULE) 49 - bool (*kgd2kfd_init_p)(unsigned, const struct kgd2kfd_calls**); 50 - #endif 51 - 52 65 switch (rdev->asic_type) { 53 66 #ifdef CONFIG_DRM_AMDGPU_CIK 54 67 case CHIP_KAVERI: ··· 75 62 return false; 76 63 } 77 64 78 - #if defined(CONFIG_HSA_AMD_MODULE) 79 - kgd2kfd_init_p = symbol_request(kgd2kfd_init); 80 - 81 - if (kgd2kfd_init_p == NULL) { 82 - kfd2kgd = NULL; 83 - return false; 84 - } 85 - 86 - if (kgd2kfd_init_p(KFD_INTERFACE_VERSION, &kgd2kfd)) { 87 - symbol_put(kgd2kfd_init); 88 - kfd2kgd = NULL; 89 - kgd2kfd = NULL; 90 - 91 - return false; 92 - } 93 - 94 65 return true; 95 - #elif defined(CONFIG_HSA_AMD) 96 - if (kgd2kfd_init(KFD_INTERFACE_VERSION, &kgd2kfd)) { 97 - kfd2kgd = NULL; 98 - kgd2kfd = NULL; 99 - return false; 100 - } 101 - 102 - return true; 103 - #else 104 - kfd2kgd = NULL; 105 - return false; 106 - #endif 107 66 } 108 67 109 68 void amdgpu_amdkfd_fini(void)
+1 -1
drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
··· 36 36 void *cpu_ptr; 37 37 }; 38 38 39 - bool amdgpu_amdkfd_init(void); 39 + int amdgpu_amdkfd_init(void); 40 40 void amdgpu_amdkfd_fini(void); 41 41 42 42 bool amdgpu_amdkfd_load_interface(struct amdgpu_device *rdev);
+8 -2
drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
··· 310 310 return -ENODEV; 311 311 } 312 312 313 + /* 314 + * Initialize amdkfd before starting radeon. If it was not loaded yet, 315 + * defer radeon probing 316 + */ 317 + ret = amdgpu_amdkfd_init(); 318 + if (ret == -EPROBE_DEFER) 319 + return ret; 320 + 313 321 /* Get rid of things like offb */ 314 322 ret = amdgpu_kick_out_firmware_fb(pdev); 315 323 if (ret) ··· 559 551 driver->driver_features |= DRIVER_MODESET; 560 552 driver->num_ioctls = amdgpu_max_kms_ioctl; 561 553 amdgpu_register_atpx_handler(); 562 - 563 - amdgpu_amdkfd_init(); 564 554 565 555 /* let modprobe override vga console setting */ 566 556 return drm_pci_init(driver, pdriver);