blob: 434d2f71e3ab4a96a7aab029dff5934ca50d3bf6 [file] [log] [blame]
/*
* Copyright 2024 Advanced Micro Devices, Inc.
*
* SPDX-License-Identifier: MIT
*/
#ifndef AMDGPU_VIRTIO_PRIVATE_H
#define AMDGPU_VIRTIO_PRIVATE_H
#include "drm-uapi/amdgpu_drm.h"
#include "drm-uapi/virtgpu_drm.h"
#include "util/hash_table.h"
#include "util/simple_mtx.h"
#include "amd_family.h"
#include "virtio/vdrm/vdrm.h"
#include "virtio/virtio-gpu/drm_hw.h"
#include "amdgpu_virtio_proto.h"
#include "amdgpu_virtio.h"
struct amdvgpu_host_blob;
struct amdvgpu_host_blob_allocator;
/* Host context seqno handling.
* seqno are monotonically increasing integer, so we don't need
* to actually submit to know the value. This allows to not
* wait for the submission to go to the host (= no need to wait
* in the guest) and to know the seqno (= so we can take advantage
* of user fence).
*/
struct amdvgpu_context {
uint32_t refcount;
uint32_t host_context_id;
uint64_t ring_next_seqno[];
};
struct amdvgpu_device {
struct vdrm_device * vdev;
/* List of existing devices */
int refcount;
struct amdvgpu_device *next;
int fd;
/* Table mapping kms handles to amdvgpu_bo instances.
* Used to maintain a 1-to-1 mapping between the 2.
*/
simple_mtx_t handle_to_vbo_mutex;
struct hash_table *handle_to_vbo;
/* Submission through virtio-gpu are ring based.
* Ring 0 is used for CPU jobs, then N rings are allocated: 1
* per IP type per instance (so if the GPU has 1 gfx queue and 2
* queues -> ring0 + 3 hw rings = 4 rings total).
*/
uint32_t num_virtio_rings;
uint32_t virtio_ring_mapping[AMD_NUM_IP_TYPES];
struct drm_amdgpu_info_device dev_info;
/* Blob id are per drm_file identifiers of host blobs.
* Use a monotically increased integer to assign the blob id.
*/
uint32_t next_blob_id;
/* GPU VA management (allocation / release). */
amdgpu_va_manager_handle va_mgr;
/* Debug option to make some protocol commands synchronous.
* If bit N is set, then the specific command will be sync.
*/
int64_t sync_cmd;
/* virtio-gpu uses a single context per drm_file and expects that
* any 2 jobs submitted to the same {context, ring} will execute in
* order.
* amdgpu on the other hand allows for multiple context per drm_file,
* so we either have to open multiple virtio-gpu drm_file to be able to
* have 1 virtio-gpu context per amdgpu-context or use a single amdgpu
* context.
* Using multiple drm_file might cause BO sharing issues so for now limit
* ourselves to a single amdgpu context. Each amdgpu_ctx object can schedule
* parallel work on 1 gfx, 2 sdma, 4 compute, 1 of each vcn queue.
*/
simple_mtx_t contexts_mutex;
struct hash_table contexts;
bool allow_multiple_amdgpu_ctx;
};
/* Refcounting helpers. Returns true when dst reaches 0. */
static inline bool update_references(int *dst, int *src)
{
if (dst != src) {
/* bump src first */
if (src) {
assert(p_atomic_read(src) > 0);
p_atomic_inc(src);
}
if (dst) {
return p_atomic_dec_zero(dst);
}
}
return false;
}
#define virtio_ioctl(fd, name, args) ({ \
int ret = drmIoctl((fd), DRM_IOCTL_ ## name, (args)); \
ret; \
})
struct amdvgpu_host_blob_creation_params {
struct drm_virtgpu_resource_create_blob args;
struct amdgpu_ccmd_gem_new_req req;
};
struct amdvgpu_bo {
struct amdvgpu_device *dev;
/* Importing the same kms handle must return the same
* amdvgpu_pointer, so we need a refcount.
*/
int refcount;
/* The size of the BO (might be smaller that the host
* bo' size).
*/
unsigned size;
/* The host blob backing this bo. */
struct amdvgpu_host_blob *host_blob;
};
uint32_t amdvgpu_get_resource_id(amdvgpu_bo_handle bo);
/* There are 2 return-code:
* - the virtio one, returned by vdrm_send_req
* - the host one, which only makes sense for sync
* requests.
*/
static inline
int vdrm_send_req_wrapper(amdvgpu_device_handle dev,
struct vdrm_ccmd_req *req,
struct amdgpu_ccmd_rsp *rsp,
bool sync) {
if (dev->sync_cmd & (1u << req->cmd))
sync = true;
int r = vdrm_send_req(dev->vdev, req, sync);
if (r)
return r;
if (sync)
return rsp->ret;
return 0;
}
#endif /* AMDGPU_VIRTIO_PRIVATE_H */