Skip to content

Commit

Permalink
drm/vmwgfx: Implement DRIVER_GEM
Browse files Browse the repository at this point in the history
This is initial change adding support for DRIVER_GEM to vmwgfx. vmwgfx
was written before GEM and has always used TTM. Over the years the
TTM buffers started inherting from GEM objects but vmwgfx never
implemented GEM making it quite awkward. We were directly setting
variables in GEM objects to not make DRM crash.

This change brings vmwgfx inline with other DRM drivers and allows us
to use a lot of DRM helpers which have depended on drivers with GEM
support.

Due to historical reasons vmwgfx splits the idea of a buffer and surface
which makes it a littly tricky since either one can be used in most
of our ioctl's which take user space handles. For now our BO's are
GEM objects and our surfaces are opaque objects which are backed by
GEM objects. In the future I'd like to combine those into a single
BO but we don't want to break any of our existing ioctl's so it will
take time to do it in a non-destructive way.

Signed-off-by: Zack Rusin <[email protected]>
Reviewed-by: Martin Krastev <[email protected]>
Link: https://patchwork.freedesktop.org/patch/msgid/[email protected]
  • Loading branch information
zackr committed Dec 9, 2021
1 parent 8ad0c3f commit 8afa13a
Show file tree
Hide file tree
Showing 25 changed files with 588 additions and 745 deletions.
1 change: 1 addition & 0 deletions drivers/gpu/drm/vmwgfx/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ config DRM_VMWGFX
depends on DRM && PCI && MMU
depends on X86 || ARM64
select DRM_TTM
select DRM_TTM_HELPER
select MAPPING_DIRTY_HELPERS
# Only needed for the transitional use of drm_crtc_init - can be removed
# again once vmwgfx sets up the primary plane itself.
Expand Down
3 changes: 2 additions & 1 deletion drivers/gpu/drm/vmwgfx/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ vmwgfx-y := vmwgfx_execbuf.o vmwgfx_gmr.o vmwgfx_hashtab.o vmwgfx_kms.o vmwgfx_d
vmwgfx_cotable.o vmwgfx_so.o vmwgfx_binding.o vmwgfx_msg.o \
vmwgfx_simple_resource.o vmwgfx_va.o vmwgfx_blit.o \
vmwgfx_validation.o vmwgfx_page_dirty.o vmwgfx_streamoutput.o \
vmwgfx_devcaps.o ttm_object.o vmwgfx_system_manager.o
vmwgfx_devcaps.o ttm_object.o vmwgfx_system_manager.o \
vmwgfx_gem.o

vmwgfx-$(CONFIG_DRM_FBDEV_EMULATION) += vmwgfx_fb.o
vmwgfx-$(CONFIG_TRANSPARENT_HUGEPAGE) += vmwgfx_thp.o
Expand Down
114 changes: 28 additions & 86 deletions drivers/gpu/drm/vmwgfx/ttm_object.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
#include <linux/atomic.h>
#include <linux/module.h>
#include "ttm_object.h"
#include "vmwgfx_drv.h"

MODULE_IMPORT_NS(DMA_BUF);

Expand All @@ -73,7 +74,7 @@ struct ttm_object_file {
struct ttm_object_device *tdev;
spinlock_t lock;
struct list_head ref_list;
struct vmwgfx_open_hash ref_hash[TTM_REF_NUM];
struct vmwgfx_open_hash ref_hash;
struct kref refcount;
};

Expand Down Expand Up @@ -124,7 +125,6 @@ struct ttm_ref_object {
struct vmwgfx_hash_item hash;
struct list_head head;
struct kref kref;
enum ttm_ref_type ref_type;
struct ttm_base_object *obj;
struct ttm_object_file *tfile;
};
Expand Down Expand Up @@ -160,17 +160,14 @@ int ttm_base_object_init(struct ttm_object_file *tfile,
struct ttm_base_object *base,
bool shareable,
enum ttm_object_type object_type,
void (*refcount_release) (struct ttm_base_object **),
void (*ref_obj_release) (struct ttm_base_object *,
enum ttm_ref_type ref_type))
void (*refcount_release) (struct ttm_base_object **))
{
struct ttm_object_device *tdev = tfile->tdev;
int ret;

base->shareable = shareable;
base->tfile = ttm_object_file_ref(tfile);
base->refcount_release = refcount_release;
base->ref_obj_release = ref_obj_release;
base->object_type = object_type;
kref_init(&base->refcount);
idr_preload(GFP_KERNEL);
Expand All @@ -182,7 +179,7 @@ int ttm_base_object_init(struct ttm_object_file *tfile,
return ret;

base->handle = ret;
ret = ttm_ref_object_add(tfile, base, TTM_REF_USAGE, NULL, false);
ret = ttm_ref_object_add(tfile, base, NULL, false);
if (unlikely(ret != 0))
goto out_err1;

Expand Down Expand Up @@ -246,7 +243,7 @@ struct ttm_base_object *
ttm_base_object_noref_lookup(struct ttm_object_file *tfile, uint32_t key)
{
struct vmwgfx_hash_item *hash;
struct vmwgfx_open_hash *ht = &tfile->ref_hash[TTM_REF_USAGE];
struct vmwgfx_open_hash *ht = &tfile->ref_hash;
int ret;

rcu_read_lock();
Expand All @@ -266,7 +263,7 @@ struct ttm_base_object *ttm_base_object_lookup(struct ttm_object_file *tfile,
{
struct ttm_base_object *base = NULL;
struct vmwgfx_hash_item *hash;
struct vmwgfx_open_hash *ht = &tfile->ref_hash[TTM_REF_USAGE];
struct vmwgfx_open_hash *ht = &tfile->ref_hash;
int ret;

rcu_read_lock();
Expand Down Expand Up @@ -297,57 +294,12 @@ ttm_base_object_lookup_for_ref(struct ttm_object_device *tdev, uint32_t key)
return base;
}

/**
* ttm_ref_object_exists - Check whether a caller has a valid ref object
* (has opened) a base object.
*
* @tfile: Pointer to a struct ttm_object_file identifying the caller.
* @base: Pointer to a struct base object.
*
* Checks wether the caller identified by @tfile has put a valid USAGE
* reference object on the base object identified by @base.
*/
bool ttm_ref_object_exists(struct ttm_object_file *tfile,
struct ttm_base_object *base)
{
struct vmwgfx_open_hash *ht = &tfile->ref_hash[TTM_REF_USAGE];
struct vmwgfx_hash_item *hash;
struct ttm_ref_object *ref;

rcu_read_lock();
if (unlikely(vmwgfx_ht_find_item_rcu(ht, base->handle, &hash) != 0))
goto out_false;

/*
* Verify that the ref object is really pointing to our base object.
* Our base object could actually be dead, and the ref object pointing
* to another base object with the same handle.
*/
ref = drm_hash_entry(hash, struct ttm_ref_object, hash);
if (unlikely(base != ref->obj))
goto out_false;

/*
* Verify that the ref->obj pointer was actually valid!
*/
rmb();
if (unlikely(kref_read(&ref->kref) == 0))
goto out_false;

rcu_read_unlock();
return true;

out_false:
rcu_read_unlock();
return false;
}

int ttm_ref_object_add(struct ttm_object_file *tfile,
struct ttm_base_object *base,
enum ttm_ref_type ref_type, bool *existed,
bool *existed,
bool require_existed)
{
struct vmwgfx_open_hash *ht = &tfile->ref_hash[ref_type];
struct vmwgfx_open_hash *ht = &tfile->ref_hash;
struct ttm_ref_object *ref;
struct vmwgfx_hash_item *hash;
int ret = -EINVAL;
Expand Down Expand Up @@ -382,7 +334,6 @@ int ttm_ref_object_add(struct ttm_object_file *tfile,
ref->hash.key = base->handle;
ref->obj = base;
ref->tfile = tfile;
ref->ref_type = ref_type;
kref_init(&ref->kref);

spin_lock(&tfile->lock);
Expand Down Expand Up @@ -411,27 +362,23 @@ ttm_ref_object_release(struct kref *kref)
{
struct ttm_ref_object *ref =
container_of(kref, struct ttm_ref_object, kref);
struct ttm_base_object *base = ref->obj;
struct ttm_object_file *tfile = ref->tfile;
struct vmwgfx_open_hash *ht;

ht = &tfile->ref_hash[ref->ref_type];
ht = &tfile->ref_hash;
(void)vmwgfx_ht_remove_item_rcu(ht, &ref->hash);
list_del(&ref->head);
spin_unlock(&tfile->lock);

if (ref->ref_type != TTM_REF_USAGE && base->ref_obj_release)
base->ref_obj_release(base, ref->ref_type);

ttm_base_object_unref(&ref->obj);
kfree_rcu(ref, rcu_head);
spin_lock(&tfile->lock);
}

int ttm_ref_object_base_unref(struct ttm_object_file *tfile,
unsigned long key, enum ttm_ref_type ref_type)
unsigned long key)
{
struct vmwgfx_open_hash *ht = &tfile->ref_hash[ref_type];
struct vmwgfx_open_hash *ht = &tfile->ref_hash;
struct ttm_ref_object *ref;
struct vmwgfx_hash_item *hash;
int ret;
Expand All @@ -452,7 +399,6 @@ void ttm_object_file_release(struct ttm_object_file **p_tfile)
{
struct ttm_ref_object *ref;
struct list_head *list;
unsigned int i;
struct ttm_object_file *tfile = *p_tfile;

*p_tfile = NULL;
Expand All @@ -470,8 +416,7 @@ void ttm_object_file_release(struct ttm_object_file **p_tfile)
}

spin_unlock(&tfile->lock);
for (i = 0; i < TTM_REF_NUM; ++i)
vmwgfx_ht_remove(&tfile->ref_hash[i]);
vmwgfx_ht_remove(&tfile->ref_hash);

ttm_object_file_unref(&tfile);
}
Expand All @@ -480,8 +425,6 @@ struct ttm_object_file *ttm_object_file_init(struct ttm_object_device *tdev,
unsigned int hash_order)
{
struct ttm_object_file *tfile = kmalloc(sizeof(*tfile), GFP_KERNEL);
unsigned int i;
unsigned int j = 0;
int ret;

if (unlikely(tfile == NULL))
Expand All @@ -492,18 +435,13 @@ struct ttm_object_file *ttm_object_file_init(struct ttm_object_device *tdev,
kref_init(&tfile->refcount);
INIT_LIST_HEAD(&tfile->ref_list);

for (i = 0; i < TTM_REF_NUM; ++i) {
ret = vmwgfx_ht_create(&tfile->ref_hash[i], hash_order);
if (ret) {
j = i;
goto out_err;
}
}
ret = vmwgfx_ht_create(&tfile->ref_hash, hash_order);
if (ret)
goto out_err;

return tfile;
out_err:
for (i = 0; i < j; ++i)
vmwgfx_ht_remove(&tfile->ref_hash[i]);
vmwgfx_ht_remove(&tfile->ref_hash);

kfree(tfile);

Expand All @@ -526,7 +464,15 @@ ttm_object_device_init(unsigned int hash_order,
if (ret != 0)
goto out_no_object_hash;

idr_init_base(&tdev->idr, 1);
/*
* Our base is at VMWGFX_NUM_MOB + 1 because we want to create
* a seperate namespace for GEM handles (which are
* 1..VMWGFX_NUM_MOB) and the surface handles. Some ioctl's
* can take either handle as an argument so we want to
* easily be able to tell whether the handle refers to a
* GEM buffer or a surface.
*/
idr_init_base(&tdev->idr, VMWGFX_NUM_MOB + 1);
tdev->ops = *ops;
tdev->dmabuf_release = tdev->ops.release;
tdev->ops.release = ttm_prime_dmabuf_release;
Expand Down Expand Up @@ -647,7 +593,7 @@ int ttm_prime_fd_to_handle(struct ttm_object_file *tfile,
prime = (struct ttm_prime_object *) dma_buf->priv;
base = &prime->base;
*handle = base->handle;
ret = ttm_ref_object_add(tfile, base, TTM_REF_USAGE, NULL, false);
ret = ttm_ref_object_add(tfile, base, NULL, false);

dma_buf_put(dma_buf);

Expand Down Expand Up @@ -741,17 +687,14 @@ int ttm_prime_handle_to_fd(struct ttm_object_file *tfile,
* @shareable: See ttm_base_object_init
* @type: See ttm_base_object_init
* @refcount_release: See ttm_base_object_init
* @ref_obj_release: See ttm_base_object_init
*
* Initializes an object which is compatible with the drm_prime model
* for data sharing between processes and devices.
*/
int ttm_prime_object_init(struct ttm_object_file *tfile, size_t size,
struct ttm_prime_object *prime, bool shareable,
enum ttm_object_type type,
void (*refcount_release) (struct ttm_base_object **),
void (*ref_obj_release) (struct ttm_base_object *,
enum ttm_ref_type ref_type))
void (*refcount_release) (struct ttm_base_object **))
{
mutex_init(&prime->mutex);
prime->size = PAGE_ALIGN(size);
Expand All @@ -760,6 +703,5 @@ int ttm_prime_object_init(struct ttm_object_file *tfile, size_t size,
prime->refcount_release = refcount_release;
return ttm_base_object_init(tfile, &prime->base, shareable,
ttm_prime_type,
ttm_prime_refcount_release,
ref_obj_release);
ttm_prime_refcount_release);
}
44 changes: 4 additions & 40 deletions drivers/gpu/drm/vmwgfx/ttm_object.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,28 +44,6 @@

#include "vmwgfx_hashtab.h"

/**
* enum ttm_ref_type
*
* Describes what type of reference a ref object holds.
*
* TTM_REF_USAGE is a simple refcount on a base object.
*
* TTM_REF_SYNCCPU_READ is a SYNCCPU_READ reference on a
* buffer object.
*
* TTM_REF_SYNCCPU_WRITE is a SYNCCPU_WRITE reference on a
* buffer object.
*
*/

enum ttm_ref_type {
TTM_REF_USAGE,
TTM_REF_SYNCCPU_READ,
TTM_REF_SYNCCPU_WRITE,
TTM_REF_NUM
};

/**
* enum ttm_object_type
*
Expand All @@ -76,7 +54,6 @@ enum ttm_ref_type {

enum ttm_object_type {
ttm_fence_type,
ttm_buffer_type,
ttm_lock_type,
ttm_prime_type,
ttm_driver_type0 = 256,
Expand Down Expand Up @@ -127,8 +104,6 @@ struct ttm_base_object {
struct ttm_object_file *tfile;
struct kref refcount;
void (*refcount_release) (struct ttm_base_object **base);
void (*ref_obj_release) (struct ttm_base_object *base,
enum ttm_ref_type ref_type);
u32 handle;
enum ttm_object_type object_type;
u32 shareable;
Expand Down Expand Up @@ -177,11 +152,7 @@ extern int ttm_base_object_init(struct ttm_object_file *tfile,
bool shareable,
enum ttm_object_type type,
void (*refcount_release) (struct ttm_base_object
**),
void (*ref_obj_release) (struct ttm_base_object
*,
enum ttm_ref_type
ref_type));
**));

/**
* ttm_base_object_lookup
Expand Down Expand Up @@ -245,12 +216,9 @@ extern void ttm_base_object_unref(struct ttm_base_object **p_base);
*/
extern int ttm_ref_object_add(struct ttm_object_file *tfile,
struct ttm_base_object *base,
enum ttm_ref_type ref_type, bool *existed,
bool *existed,
bool require_existed);

extern bool ttm_ref_object_exists(struct ttm_object_file *tfile,
struct ttm_base_object *base);

/**
* ttm_ref_object_base_unref
*
Expand All @@ -263,8 +231,7 @@ extern bool ttm_ref_object_exists(struct ttm_object_file *tfile,
* will be unreferenced.
*/
extern int ttm_ref_object_base_unref(struct ttm_object_file *tfile,
unsigned long key,
enum ttm_ref_type ref_type);
unsigned long key);

/**
* ttm_object_file_init - initialize a struct ttm_object file
Expand Down Expand Up @@ -328,10 +295,7 @@ extern int ttm_prime_object_init(struct ttm_object_file *tfile,
bool shareable,
enum ttm_object_type type,
void (*refcount_release)
(struct ttm_base_object **),
void (*ref_obj_release)
(struct ttm_base_object *,
enum ttm_ref_type ref_type));
(struct ttm_base_object **));

static inline enum ttm_object_type
ttm_base_object_type(struct ttm_base_object *base)
Expand Down
Loading

0 comments on commit 8afa13a

Please sign in to comment.