turnip: Refactor device loading

1) Allow the two different entrypoints for drm vs non-drm (kgsl) to
   coexist.
2) Split the generic drm related device initialization from the msm
   specifics.  This will simplify adding support for additional drm
   based kernel mode drivers (ie. virtgpu)

Signed-off-by: Rob Clark <robdclark@chromium.org>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/21394>
This commit is contained in:
Rob Clark 2023-02-17 11:10:24 -08:00 committed by Marge Bot
parent 3b3882d4c5
commit 407e4929de
5 changed files with 170 additions and 118 deletions

View file

@ -468,12 +468,9 @@ tu_CreateInstance(const VkInstanceCreateInfo *pCreateInfo,
return vk_error(NULL, result);
}
#ifndef TU_USE_KGSL
instance->vk.physical_devices.try_create_for_drm =
tu_physical_device_try_create;
#else
instance->vk.physical_devices.enumerate = tu_enumerate_devices;
#endif
instance->vk.physical_devices.destroy = tu_destroy_physical_device;
if (TU_DEBUG(STARTUP))

View file

@ -7,6 +7,18 @@
* Copyright © 2015 Intel Corporation
*/
#include <fcntl.h>
#ifdef HAVE_LIBDRM
#include <xf86drm.h>
#endif
#ifdef MAJOR_IN_MKDEV
#include <sys/mkdev.h>
#endif
#ifdef MAJOR_IN_SYSMACROS
#include <sys/sysmacros.h>
#endif
#include "tu_device.h"
#include "tu_knl.h"
@ -100,3 +112,145 @@ tu_queue_submit(struct vk_queue *vk_queue, struct vk_queue_submit *submit)
struct tu_queue *queue = container_of(vk_queue, struct tu_queue, vk);
return queue->device->instance->knl->queue_submit(queue, submit);
}
/**
* Enumeration entrypoint specific to non-drm devices (ie. kgsl)
*/
VkResult
tu_enumerate_devices(struct vk_instance *vk_instance)
{
#ifdef TU_USE_KGSL
struct tu_instance *instance =
container_of(vk_instance, struct tu_instance, vk);
static const char path[] = "/dev/kgsl-3d0";
int fd;
fd = open(path, O_RDWR | O_CLOEXEC);
if (fd < 0) {
if (errno == ENOENT)
return VK_ERROR_INCOMPATIBLE_DRIVER;
return vk_errorf(instance, VK_ERROR_INITIALIZATION_FAILED,
"failed to open device %s", path);
}
VkResult result = tu_knl_kgsl_load(instance, fd);
if (result != VK_SUCCESS) {
close(fd);
return result;
}
if (TU_DEBUG(STARTUP))
mesa_logi("Found compatible device '%s'.", path);
return result;
#else
return VK_ERROR_INCOMPATIBLE_DRIVER;
#endif
}
/**
* Enumeration entrypoint for drm devices
*/
VkResult
tu_physical_device_try_create(struct vk_instance *vk_instance,
struct _drmDevice *drm_device,
struct vk_physical_device **out)
{
#ifdef HAVE_LIBDRM
struct tu_instance *instance =
container_of(vk_instance, struct tu_instance, vk);
if (!(drm_device->available_nodes & (1 << DRM_NODE_RENDER)) ||
drm_device->bustype != DRM_BUS_PLATFORM)
return VK_ERROR_INCOMPATIBLE_DRIVER;
const char *primary_path = drm_device->nodes[DRM_NODE_PRIMARY];
const char *path = drm_device->nodes[DRM_NODE_RENDER];
VkResult result = VK_SUCCESS;
drmVersionPtr version;
int fd;
int master_fd = -1;
fd = open(path, O_RDWR | O_CLOEXEC);
if (fd < 0) {
return vk_startup_errorf(instance, VK_ERROR_INCOMPATIBLE_DRIVER,
"failed to open device %s", path);
}
version = drmGetVersion(fd);
if (!version) {
close(fd);
return vk_startup_errorf(instance, VK_ERROR_INCOMPATIBLE_DRIVER,
"failed to query kernel driver version for device %s",
path);
}
struct tu_physical_device *device = NULL;
if (strcmp(version->name, "msm") == 0) {
result = tu_knl_drm_msm_load(instance, fd, version, &device);
} else {
result = vk_startup_errorf(instance, VK_ERROR_INCOMPATIBLE_DRIVER,
"device %s (%s) is not compatible with turnip",
path, version->name);
}
if (result != VK_SUCCESS)
goto out;
assert(device);
if (instance->vk.enabled_extensions.KHR_display) {
master_fd = open(primary_path, O_RDWR | O_CLOEXEC);
}
device->master_fd = master_fd;
struct stat st;
if (stat(primary_path, &st) == 0) {
device->has_master = true;
device->master_major = major(st.st_rdev);
device->master_minor = minor(st.st_rdev);
} else {
device->has_master = false;
device->master_major = 0;
device->master_minor = 0;
}
if (stat(path, &st) == 0) {
device->has_local = true;
device->local_major = major(st.st_rdev);
device->local_minor = minor(st.st_rdev);
} else {
result = vk_errorf(instance, VK_ERROR_INITIALIZATION_FAILED,
"failed to stat DRM render node %s", path);
goto out;
}
result = tu_physical_device_init(device, instance);
if (result != VK_SUCCESS)
goto out;
if (TU_DEBUG(STARTUP))
mesa_logi("Found compatible device '%s' (%s).", path, version->name);
*out = &device->vk;
out:
if (result != VK_SUCCESS) {
if (master_fd != -1)
close(master_fd);
close(fd);
vk_free(&instance->vk.alloc, device);
}
drmFreeVersion(version);
return result;
#else
return VK_ERROR_INCOMPATIBLE_DRIVER;
#endif
}

View file

@ -123,14 +123,20 @@ tu_bo_get_ref(struct tu_bo *bo)
}
#ifdef TU_USE_KGSL
VkResult tu_knl_kgsl_load(struct tu_instance *instance, int fd);
#endif
struct _drmVersion;
VkResult tu_knl_drm_msm_load(struct tu_instance *instance,
int fd, struct _drmVersion *version,
struct tu_physical_device **out);
VkResult
tu_enumerate_devices(struct vk_instance *vk_instance);
#else
VkResult
tu_physical_device_try_create(struct vk_instance *vk_instance,
struct _drmDevice *drm_device,
struct vk_physical_device **out);
#endif
int
tu_device_get_gpu_timestamp(struct tu_device *dev,

View file

@ -12,13 +12,6 @@
#include <sys/mman.h>
#include <xf86drm.h>
#ifdef MAJOR_IN_MKDEV
#include <sys/mkdev.h>
#endif
#ifdef MAJOR_IN_SYSMACROS
#include <sys/sysmacros.h>
#endif
#include "vk_util.h"
#include "drm-uapi/msm_drm.h"
@ -1187,60 +1180,24 @@ const struct vk_sync_type tu_timeline_sync_type = {
};
VkResult
tu_physical_device_try_create(struct vk_instance *vk_instance,
struct _drmDevice *drm_device,
struct vk_physical_device **out)
tu_knl_drm_msm_load(struct tu_instance *instance,
int fd, struct _drmVersion *version,
struct tu_physical_device **out)
{
struct tu_instance *instance =
container_of(vk_instance, struct tu_instance, vk);
if (!(drm_device->available_nodes & (1 << DRM_NODE_RENDER)) ||
drm_device->bustype != DRM_BUS_PLATFORM)
return VK_ERROR_INCOMPATIBLE_DRIVER;
const char *primary_path = drm_device->nodes[DRM_NODE_PRIMARY];
const char *path = drm_device->nodes[DRM_NODE_RENDER];
VkResult result = VK_SUCCESS;
drmVersionPtr version;
int fd;
int master_fd = -1;
fd = open(path, O_RDWR | O_CLOEXEC);
if (fd < 0) {
return vk_startup_errorf(instance, VK_ERROR_INCOMPATIBLE_DRIVER,
"failed to open device %s", path);
}
/* Version 1.6 added SYNCOBJ support. */
const int min_version_major = 1;
const int min_version_minor = 6;
version = drmGetVersion(fd);
if (!version) {
close(fd);
return vk_startup_errorf(instance, VK_ERROR_INCOMPATIBLE_DRIVER,
"failed to query kernel driver version for device %s",
path);
}
if (strcmp(version->name, "msm")) {
drmFreeVersion(version);
close(fd);
return vk_startup_errorf(instance, VK_ERROR_INCOMPATIBLE_DRIVER,
"device %s does not use the msm kernel driver",
path);
}
if (version->version_major != min_version_major ||
version->version_minor < min_version_minor) {
result = vk_startup_errorf(instance, VK_ERROR_INCOMPATIBLE_DRIVER,
"kernel driver for device %s has version %d.%d, "
"but Vulkan requires version >= %d.%d",
path,
version->name,
version->version_major, version->version_minor,
min_version_major, min_version_minor);
drmFreeVersion(version);
close(fd);
return result;
}
@ -1249,28 +1206,13 @@ tu_physical_device_try_create(struct vk_instance *vk_instance,
VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
if (!device) {
result = vk_error(instance, VK_ERROR_OUT_OF_HOST_MEMORY);
drmFreeVersion(version);
goto fail;
}
device->msm_major_version = version->version_major;
device->msm_minor_version = version->version_minor;
drmFreeVersion(version);
if (TU_DEBUG(STARTUP))
mesa_logi("Found compatible device '%s'.", path);
device->instance = instance;
if (instance->vk.enabled_extensions.KHR_display) {
master_fd = open(primary_path, O_RDWR | O_CLOEXEC);
if (master_fd >= 0) {
/* TODO: free master_fd is accel is not working? */
}
}
device->master_fd = master_fd;
device->local_fd = fd;
if (tu_drm_get_gpu_id(device, &device->dev_id.gpu_id)) {
@ -1311,28 +1253,6 @@ tu_physical_device_try_create(struct vk_instance *vk_instance,
*/
device->has_set_iova = false;
struct stat st;
if (stat(primary_path, &st) == 0) {
device->has_master = true;
device->master_major = major(st.st_rdev);
device->master_minor = minor(st.st_rdev);
} else {
device->has_master = false;
device->master_major = 0;
device->master_minor = 0;
}
if (stat(path, &st) == 0) {
device->has_local = true;
device->local_major = major(st.st_rdev);
device->local_minor = minor(st.st_rdev);
} else {
result = vk_errorf(instance, VK_ERROR_INITIALIZATION_FAILED,
"failed to stat DRM render node %s", path);
goto fail;
}
int ret = tu_drm_get_param(device, MSM_PARAM_FAULTS, &device->fault_count);
if (ret != 0) {
result = vk_startup_errorf(instance, VK_ERROR_INITIALIZATION_FAILED,
@ -1357,18 +1277,11 @@ tu_physical_device_try_create(struct vk_instance *vk_instance,
instance->knl = &msm_knl_funcs;
result = tu_physical_device_init(device, instance);
*out = device;
if (result == VK_SUCCESS) {
*out = &device->vk;
return result;
}
return VK_SUCCESS;
fail:
if (device)
vk_free(&instance->vk.alloc, device);
close(fd);
if (master_fd != -1)
close(master_fd);
vk_free(&instance->vk.alloc, device);
return result;
}

View file

@ -827,28 +827,13 @@ static const struct tu_knl kgsl_knl_funcs = {
};
VkResult
tu_enumerate_devices(struct vk_instance *vk_instance)
tu_knl_kgsl_load(struct tu_instance *instance, int fd)
{
struct tu_instance *instance =
container_of(vk_instance, struct tu_instance, vk);
static const char path[] = "/dev/kgsl-3d0";
int fd;
if (instance->vk.enabled_extensions.KHR_display) {
return vk_errorf(instance, VK_ERROR_INITIALIZATION_FAILED,
"I can't KHR_display");
}
fd = open(path, O_RDWR | O_CLOEXEC);
if (fd < 0) {
if (errno == ENOENT)
return VK_ERROR_INCOMPATIBLE_DRIVER;
return vk_errorf(instance, VK_ERROR_INITIALIZATION_FAILED,
"failed to open device %s", path);
}
struct tu_physical_device *device =
vk_zalloc(&instance->vk.alloc, sizeof(*device), 8,
VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
@ -867,9 +852,6 @@ tu_enumerate_devices(struct vk_instance *vk_instance)
/* kgsl version check? */
if (TU_DEBUG(STARTUP))
mesa_logi("Found compatible device '%s'.", path);
device->instance = instance;
device->master_fd = -1;
device->local_fd = fd;