mirror of https://gitlab.freedesktop.org/mesa/mesa
259 lines
6.4 KiB
C
259 lines
6.4 KiB
C
/*
|
|
* Copyright © 2016 Red Hat.
|
|
* Copyright © 2016 Bas Nieuwenhuizen
|
|
* SPDX-License-Identifier: MIT
|
|
*
|
|
* based in part on anv driver which is:
|
|
* 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"
|
|
|
|
|
|
VkResult
|
|
tu_bo_init_new_explicit_iova(struct tu_device *dev,
|
|
struct tu_bo **out_bo,
|
|
uint64_t size,
|
|
uint64_t client_iova,
|
|
enum tu_bo_alloc_flags flags, const char *name)
|
|
{
|
|
return dev->instance->knl->bo_init(dev, out_bo, size, client_iova, flags, name);
|
|
}
|
|
|
|
VkResult
|
|
tu_bo_init_dmabuf(struct tu_device *dev,
|
|
struct tu_bo **bo,
|
|
uint64_t size,
|
|
int fd)
|
|
{
|
|
return dev->instance->knl->bo_init_dmabuf(dev, bo, size, fd);
|
|
}
|
|
|
|
int
|
|
tu_bo_export_dmabuf(struct tu_device *dev, struct tu_bo *bo)
|
|
{
|
|
return dev->instance->knl->bo_export_dmabuf(dev, bo);
|
|
}
|
|
|
|
void
|
|
tu_bo_finish(struct tu_device *dev, struct tu_bo *bo)
|
|
{
|
|
dev->instance->knl->bo_finish(dev, bo);
|
|
}
|
|
|
|
VkResult
|
|
tu_bo_map(struct tu_device *dev, struct tu_bo *bo)
|
|
{
|
|
return dev->instance->knl->bo_map(dev, bo);
|
|
}
|
|
|
|
void tu_bo_allow_dump(struct tu_device *dev, struct tu_bo *bo)
|
|
{
|
|
dev->instance->knl->bo_allow_dump(dev, bo);
|
|
}
|
|
|
|
int
|
|
tu_device_get_gpu_timestamp(struct tu_device *dev,
|
|
uint64_t *ts)
|
|
{
|
|
return dev->instance->knl->device_get_gpu_timestamp(dev, ts);
|
|
}
|
|
|
|
int
|
|
tu_device_get_suspend_count(struct tu_device *dev,
|
|
uint64_t *suspend_count)
|
|
{
|
|
return dev->instance->knl->device_get_suspend_count(dev, suspend_count);
|
|
}
|
|
|
|
VkResult
|
|
tu_device_wait_u_trace(struct tu_device *dev, struct tu_u_trace_syncobj *syncobj)
|
|
{
|
|
return dev->instance->knl->device_wait_u_trace(dev, syncobj);
|
|
}
|
|
|
|
VkResult
|
|
tu_device_check_status(struct vk_device *vk_device)
|
|
{
|
|
struct tu_device *dev = container_of(vk_device, struct tu_device, vk);
|
|
return dev->instance->knl->device_check_status(dev);
|
|
}
|
|
|
|
int
|
|
tu_drm_submitqueue_new(const struct tu_device *dev,
|
|
int priority,
|
|
uint32_t *queue_id)
|
|
{
|
|
return dev->instance->knl->submitqueue_new(dev, priority, queue_id);
|
|
}
|
|
|
|
void
|
|
tu_drm_submitqueue_close(const struct tu_device *dev, uint32_t queue_id)
|
|
{
|
|
dev->instance->knl->submitqueue_close(dev, queue_id);
|
|
}
|
|
|
|
VkResult
|
|
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_HAS_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];
|
|
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;
|
|
|
|
VkResult result = VK_ERROR_INCOMPATIBLE_DRIVER;
|
|
if (strcmp(version->name, "msm") == 0) {
|
|
#ifdef TU_HAS_MSM
|
|
result = tu_knl_drm_msm_load(instance, fd, version, &device);
|
|
#endif
|
|
} 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
|
|
}
|