drm: dumb scanout create/mmap for intel/radeon (v3)
This is just an idea that might or might not be a good idea, it basically adds two ioctls to create a dumb and map a dumb buffer suitable for scanout. The handle can be passed to the KMS ioctls to create a framebuffer. It looks to me like it would be useful in the following cases: a) in development drivers - we can always provide a shadowfb fallback. b) libkms users - we can clean up libkms a lot and avoid linking to libdrm_*. c) plymouth via libkms is a lot easier. Userspace bits would be just calls + mmaps. We could probably mark these handles somehow as not being suitable for acceleartion so as top stop people who are dumber than dumb. Signed-off-by: Dave Airlie <airlied@redhat.com>
This commit is contained in:
parent
1f692a14cb
commit
ff72145bad
15 changed files with 246 additions and 38 deletions
|
@ -2694,3 +2694,36 @@ void drm_mode_config_reset(struct drm_device *dev)
|
|||
connector->funcs->reset(connector);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_mode_config_reset);
|
||||
|
||||
int drm_mode_create_dumb_ioctl(struct drm_device *dev,
|
||||
void *data, struct drm_file *file_priv)
|
||||
{
|
||||
struct drm_mode_create_dumb *args = data;
|
||||
|
||||
if (!dev->driver->dumb_create)
|
||||
return -ENOSYS;
|
||||
return dev->driver->dumb_create(file_priv, dev, args);
|
||||
}
|
||||
|
||||
int drm_mode_mmap_dumb_ioctl(struct drm_device *dev,
|
||||
void *data, struct drm_file *file_priv)
|
||||
{
|
||||
struct drm_mode_map_dumb *args = data;
|
||||
|
||||
/* call driver ioctl to get mmap offset */
|
||||
if (!dev->driver->dumb_map_offset)
|
||||
return -ENOSYS;
|
||||
|
||||
return dev->driver->dumb_map_offset(file_priv, dev, args->handle, &args->offset);
|
||||
}
|
||||
|
||||
int drm_mode_destroy_dumb_ioctl(struct drm_device *dev,
|
||||
void *data, struct drm_file *file_priv)
|
||||
{
|
||||
struct drm_mode_destroy_dumb *args = data;
|
||||
|
||||
if (!dev->driver->dumb_destroy)
|
||||
return -ENOSYS;
|
||||
|
||||
return dev->driver->dumb_destroy(file_priv, dev, args->handle);
|
||||
}
|
||||
|
|
|
@ -150,7 +150,10 @@ static struct drm_ioctl_desc drm_ioctls[] = {
|
|||
DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MODE_PAGE_FLIP, drm_mode_page_flip_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MODE_DIRTYFB, drm_mode_dirtyfb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED)
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MODE_DIRTYFB, drm_mode_dirtyfb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MODE_CREATE_DUMB, drm_mode_create_dumb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MODE_MAP_DUMB, drm_mode_mmap_dumb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
|
||||
DRM_IOCTL_DEF(DRM_IOCTL_MODE_DESTROY_DUMB, drm_mode_destroy_dumb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED)
|
||||
};
|
||||
|
||||
#define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls )
|
||||
|
|
|
@ -181,7 +181,7 @@ EXPORT_SYMBOL(drm_gem_object_alloc);
|
|||
/**
|
||||
* Removes the mapping from handle to filp for this object.
|
||||
*/
|
||||
static int
|
||||
int
|
||||
drm_gem_handle_delete(struct drm_file *filp, u32 handle)
|
||||
{
|
||||
struct drm_device *dev;
|
||||
|
@ -214,6 +214,7 @@ drm_gem_handle_delete(struct drm_file *filp, u32 handle)
|
|||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_gem_handle_delete);
|
||||
|
||||
/**
|
||||
* Create a handle for this object. This adds a handle reference
|
||||
|
|
|
@ -700,6 +700,9 @@ static struct drm_driver driver = {
|
|||
.gem_init_object = i915_gem_init_object,
|
||||
.gem_free_object = i915_gem_free_object,
|
||||
.gem_vm_ops = &i915_gem_vm_ops,
|
||||
.dumb_create = i915_gem_dumb_create,
|
||||
.dumb_map_offset = i915_gem_mmap_gtt,
|
||||
.dumb_destroy = i915_gem_dumb_destroy,
|
||||
.ioctls = i915_ioctls,
|
||||
.fops = {
|
||||
.owner = THIS_MODULE,
|
||||
|
|
|
@ -1114,6 +1114,13 @@ void i915_gem_object_move_to_active(struct drm_i915_gem_object *obj,
|
|||
struct intel_ring_buffer *ring,
|
||||
u32 seqno);
|
||||
|
||||
int i915_gem_dumb_create(struct drm_file *file_priv,
|
||||
struct drm_device *dev,
|
||||
struct drm_mode_create_dumb *args);
|
||||
int i915_gem_mmap_gtt(struct drm_file *file_priv, struct drm_device *dev,
|
||||
uint32_t handle, uint64_t *offset);
|
||||
int i915_gem_dumb_destroy(struct drm_file *file_priv, struct drm_device *dev,
|
||||
uint32_t handle);
|
||||
/**
|
||||
* Returns true if seq1 is later than seq2.
|
||||
*/
|
||||
|
|
|
@ -193,22 +193,20 @@ i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new mm object and returns a handle to it.
|
||||
*/
|
||||
int
|
||||
i915_gem_create_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file)
|
||||
static int
|
||||
i915_gem_create(struct drm_file *file,
|
||||
struct drm_device *dev,
|
||||
uint64_t size,
|
||||
uint32_t *handle_p)
|
||||
{
|
||||
struct drm_i915_gem_create *args = data;
|
||||
struct drm_i915_gem_object *obj;
|
||||
int ret;
|
||||
u32 handle;
|
||||
|
||||
args->size = roundup(args->size, PAGE_SIZE);
|
||||
size = roundup(size, PAGE_SIZE);
|
||||
|
||||
/* Allocate the new object */
|
||||
obj = i915_gem_alloc_object(dev, args->size);
|
||||
obj = i915_gem_alloc_object(dev, size);
|
||||
if (obj == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -224,10 +222,41 @@ i915_gem_create_ioctl(struct drm_device *dev, void *data,
|
|||
drm_gem_object_unreference(&obj->base);
|
||||
trace_i915_gem_object_create(obj);
|
||||
|
||||
args->handle = handle;
|
||||
*handle_p = handle;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
i915_gem_dumb_create(struct drm_file *file,
|
||||
struct drm_device *dev,
|
||||
struct drm_mode_create_dumb *args)
|
||||
{
|
||||
/* have to work out size/pitch and return them */
|
||||
args->pitch = ALIGN(args->width & ((args->bpp + 1) / 8), 64);
|
||||
args->size = args->pitch * args->height;
|
||||
return i915_gem_create(file, dev,
|
||||
args->size, &args->handle);
|
||||
}
|
||||
|
||||
int i915_gem_dumb_destroy(struct drm_file *file,
|
||||
struct drm_device *dev,
|
||||
uint32_t handle)
|
||||
{
|
||||
return drm_gem_handle_delete(file, handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new mm object and returns a handle to it.
|
||||
*/
|
||||
int
|
||||
i915_gem_create_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file)
|
||||
{
|
||||
struct drm_i915_gem_create *args = data;
|
||||
return i915_gem_create(file, dev,
|
||||
args->size, &args->handle);
|
||||
}
|
||||
|
||||
static int i915_gem_object_needs_bit17_swizzle(struct drm_i915_gem_object *obj)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = obj->base.dev->dev_private;
|
||||
|
@ -1425,27 +1454,13 @@ i915_gem_get_unfenced_gtt_alignment(struct drm_i915_gem_object *obj)
|
|||
return tile_height * obj->stride * 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* i915_gem_mmap_gtt_ioctl - prepare an object for GTT mmap'ing
|
||||
* @dev: DRM device
|
||||
* @data: GTT mapping ioctl data
|
||||
* @file: GEM object info
|
||||
*
|
||||
* Simply returns the fake offset to userspace so it can mmap it.
|
||||
* The mmap call will end up in drm_gem_mmap(), which will set things
|
||||
* up so we can get faults in the handler above.
|
||||
*
|
||||
* The fault handler will take care of binding the object into the GTT
|
||||
* (since it may have been evicted to make room for something), allocating
|
||||
* a fence register, and mapping the appropriate aperture address into
|
||||
* userspace.
|
||||
*/
|
||||
int
|
||||
i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file)
|
||||
i915_gem_mmap_gtt(struct drm_file *file,
|
||||
struct drm_device *dev,
|
||||
uint32_t handle,
|
||||
uint64_t *offset)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct drm_i915_gem_mmap_gtt *args = data;
|
||||
struct drm_i915_gem_object *obj;
|
||||
int ret;
|
||||
|
||||
|
@ -1456,7 +1471,7 @@ i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
|
||||
obj = to_intel_bo(drm_gem_object_lookup(dev, file, handle));
|
||||
if (obj == NULL) {
|
||||
ret = -ENOENT;
|
||||
goto unlock;
|
||||
|
@ -1479,7 +1494,7 @@ i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data,
|
|||
goto out;
|
||||
}
|
||||
|
||||
args->offset = (u64)obj->base.map_list.hash.key << PAGE_SHIFT;
|
||||
*offset = (u64)obj->base.map_list.hash.key << PAGE_SHIFT;
|
||||
|
||||
out:
|
||||
drm_gem_object_unreference(&obj->base);
|
||||
|
@ -1488,6 +1503,34 @@ unlock:
|
|||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* i915_gem_mmap_gtt_ioctl - prepare an object for GTT mmap'ing
|
||||
* @dev: DRM device
|
||||
* @data: GTT mapping ioctl data
|
||||
* @file: GEM object info
|
||||
*
|
||||
* Simply returns the fake offset to userspace so it can mmap it.
|
||||
* The mmap call will end up in drm_gem_mmap(), which will set things
|
||||
* up so we can get faults in the handler above.
|
||||
*
|
||||
* The fault handler will take care of binding the object into the GTT
|
||||
* (since it may have been evicted to make room for something), allocating
|
||||
* a fence register, and mapping the appropriate aperture address into
|
||||
* userspace.
|
||||
*/
|
||||
int
|
||||
i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file)
|
||||
{
|
||||
struct drm_i915_gem_mmap_gtt *args = data;
|
||||
|
||||
if (!(dev->driver->driver_features & DRIVER_GEM))
|
||||
return -ENODEV;
|
||||
|
||||
return i915_gem_mmap_gtt(file, dev, args->handle, &args->offset);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj,
|
||||
gfp_t gfpmask)
|
||||
|
|
|
@ -288,6 +288,15 @@ int radeon_gem_object_pin(struct drm_gem_object *obj, uint32_t pin_domain,
|
|||
uint64_t *gpu_addr);
|
||||
void radeon_gem_object_unpin(struct drm_gem_object *obj);
|
||||
|
||||
int radeon_mode_dumb_create(struct drm_file *file_priv,
|
||||
struct drm_device *dev,
|
||||
struct drm_mode_create_dumb *args);
|
||||
int radeon_mode_dumb_mmap(struct drm_file *filp,
|
||||
struct drm_device *dev,
|
||||
uint32_t handle, uint64_t *offset_p);
|
||||
int radeon_mode_dumb_destroy(struct drm_file *file_priv,
|
||||
struct drm_device *dev,
|
||||
uint32_t handle);
|
||||
|
||||
/*
|
||||
* GART structures, functions & helpers
|
||||
|
|
|
@ -84,6 +84,16 @@ extern int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc,
|
|||
extern struct drm_ioctl_desc radeon_ioctls_kms[];
|
||||
extern int radeon_max_kms_ioctl;
|
||||
int radeon_mmap(struct file *filp, struct vm_area_struct *vma);
|
||||
int radeon_mode_dumb_mmap(struct drm_file *filp,
|
||||
struct drm_device *dev,
|
||||
uint32_t handle, uint64_t *offset_p);
|
||||
int radeon_mode_dumb_create(struct drm_file *file_priv,
|
||||
struct drm_device *dev,
|
||||
struct drm_mode_create_dumb *args);
|
||||
int radeon_mode_dumb_destroy(struct drm_file *file_priv,
|
||||
struct drm_device *dev,
|
||||
uint32_t handle);
|
||||
|
||||
#if defined(CONFIG_DEBUG_FS)
|
||||
int radeon_debugfs_init(struct drm_minor *minor);
|
||||
void radeon_debugfs_cleanup(struct drm_minor *minor);
|
||||
|
@ -322,6 +332,9 @@ static struct drm_driver kms_driver = {
|
|||
.gem_init_object = radeon_gem_object_init,
|
||||
.gem_free_object = radeon_gem_object_free,
|
||||
.dma_ioctl = radeon_dma_ioctl_kms,
|
||||
.dumb_create = radeon_mode_dumb_create,
|
||||
.dumb_map_offset = radeon_mode_dumb_mmap,
|
||||
.dumb_destroy = radeon_mode_dumb_destroy,
|
||||
.fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = drm_open,
|
||||
|
|
|
@ -64,7 +64,7 @@ static struct fb_ops radeonfb_ops = {
|
|||
};
|
||||
|
||||
|
||||
static int radeon_align_pitch(struct radeon_device *rdev, int width, int bpp, bool tiled)
|
||||
int radeon_align_pitch(struct radeon_device *rdev, int width, int bpp, bool tiled)
|
||||
{
|
||||
int aligned = width;
|
||||
int align_large = (ASIC_IS_AVIVO(rdev)) || tiled;
|
||||
|
|
|
@ -236,23 +236,31 @@ int radeon_gem_set_domain_ioctl(struct drm_device *dev, void *data,
|
|||
return r;
|
||||
}
|
||||
|
||||
int radeon_gem_mmap_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *filp)
|
||||
int radeon_mode_dumb_mmap(struct drm_file *filp,
|
||||
struct drm_device *dev,
|
||||
uint32_t handle, uint64_t *offset_p)
|
||||
{
|
||||
struct drm_radeon_gem_mmap *args = data;
|
||||
struct drm_gem_object *gobj;
|
||||
struct radeon_bo *robj;
|
||||
|
||||
gobj = drm_gem_object_lookup(dev, filp, args->handle);
|
||||
gobj = drm_gem_object_lookup(dev, filp, handle);
|
||||
if (gobj == NULL) {
|
||||
return -ENOENT;
|
||||
}
|
||||
robj = gobj->driver_private;
|
||||
args->addr_ptr = radeon_bo_mmap_offset(robj);
|
||||
*offset_p = radeon_bo_mmap_offset(robj);
|
||||
drm_gem_object_unreference_unlocked(gobj);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int radeon_gem_mmap_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *filp)
|
||||
{
|
||||
struct drm_radeon_gem_mmap *args = data;
|
||||
|
||||
return radeon_mode_dumb_mmap(filp, dev, args->handle, &args->addr_ptr);
|
||||
}
|
||||
|
||||
int radeon_gem_busy_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *filp)
|
||||
{
|
||||
|
@ -345,3 +353,38 @@ out:
|
|||
drm_gem_object_unreference_unlocked(gobj);
|
||||
return r;
|
||||
}
|
||||
|
||||
int radeon_mode_dumb_create(struct drm_file *file_priv,
|
||||
struct drm_device *dev,
|
||||
struct drm_mode_create_dumb *args)
|
||||
{
|
||||
struct radeon_device *rdev = dev->dev_private;
|
||||
struct drm_gem_object *gobj;
|
||||
int r;
|
||||
|
||||
args->pitch = radeon_align_pitch(rdev, args->width, args->bpp, 0) * ((args->bpp + 1) / 8);
|
||||
args->size = args->pitch * args->height;
|
||||
args->size = ALIGN(args->size, PAGE_SIZE);
|
||||
|
||||
r = radeon_gem_object_create(rdev, args->size, 0,
|
||||
RADEON_GEM_DOMAIN_VRAM,
|
||||
false, ttm_bo_type_device,
|
||||
&gobj);
|
||||
if (r)
|
||||
return -ENOMEM;
|
||||
|
||||
r = drm_gem_handle_create(file_priv, gobj, &args->handle);
|
||||
if (r) {
|
||||
drm_gem_object_unreference_unlocked(gobj);
|
||||
return r;
|
||||
}
|
||||
drm_gem_object_handle_unreference_unlocked(gobj);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int radeon_mode_dumb_destroy(struct drm_file *file_priv,
|
||||
struct drm_device *dev,
|
||||
uint32_t handle)
|
||||
{
|
||||
return drm_gem_handle_delete(file_priv, handle);
|
||||
}
|
||||
|
|
|
@ -675,4 +675,5 @@ void radeon_fb_output_poll_changed(struct radeon_device *rdev);
|
|||
|
||||
void radeon_crtc_handle_flip(struct radeon_device *rdev, int crtc_id);
|
||||
|
||||
int radeon_align_pitch(struct radeon_device *rdev, int width, int bpp, bool tiled);
|
||||
#endif
|
||||
|
|
|
@ -701,6 +701,10 @@ struct drm_gem_open {
|
|||
#define DRM_IOCTL_MODE_PAGE_FLIP DRM_IOWR(0xB0, struct drm_mode_crtc_page_flip)
|
||||
#define DRM_IOCTL_MODE_DIRTYFB DRM_IOWR(0xB1, struct drm_mode_fb_dirty_cmd)
|
||||
|
||||
#define DRM_IOCTL_MODE_CREATE_DUMB DRM_IOWR(0xB2, struct drm_mode_create_dumb)
|
||||
#define DRM_IOCTL_MODE_MAP_DUMB DRM_IOWR(0xB3, struct drm_mode_map_dumb)
|
||||
#define DRM_IOCTL_MODE_DESTROY_DUMB DRM_IOWR(0xB4, struct drm_mode_destroy_dumb)
|
||||
|
||||
/**
|
||||
* Device specific ioctls should only be in their respective headers
|
||||
* The device specific ioctl range is from 0x40 to 0x99.
|
||||
|
|
|
@ -880,6 +880,17 @@ struct drm_driver {
|
|||
/* vga arb irq handler */
|
||||
void (*vgaarb_irq)(struct drm_device *dev, bool state);
|
||||
|
||||
/* dumb alloc support */
|
||||
int (*dumb_create)(struct drm_file *file_priv,
|
||||
struct drm_device *dev,
|
||||
struct drm_mode_create_dumb *args);
|
||||
int (*dumb_map_offset)(struct drm_file *file_priv,
|
||||
struct drm_device *dev, uint32_t handle,
|
||||
uint64_t *offset);
|
||||
int (*dumb_destroy)(struct drm_file *file_priv,
|
||||
struct drm_device *dev,
|
||||
uint32_t handle);
|
||||
|
||||
/* Driver private ops for this object */
|
||||
struct vm_operations_struct *gem_vm_ops;
|
||||
|
||||
|
@ -1544,6 +1555,7 @@ drm_gem_object_unreference_unlocked(struct drm_gem_object *obj)
|
|||
int drm_gem_handle_create(struct drm_file *file_priv,
|
||||
struct drm_gem_object *obj,
|
||||
u32 *handlep);
|
||||
int drm_gem_handle_delete(struct drm_file *filp, u32 handle);
|
||||
|
||||
static inline void
|
||||
drm_gem_object_handle_reference(struct drm_gem_object *obj)
|
||||
|
|
|
@ -798,4 +798,11 @@ extern int drm_add_modes_noedid(struct drm_connector *connector,
|
|||
extern bool drm_edid_is_valid(struct edid *edid);
|
||||
struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev,
|
||||
int hsize, int vsize, int fresh);
|
||||
|
||||
extern int drm_mode_create_dumb_ioctl(struct drm_device *dev,
|
||||
void *data, struct drm_file *file_priv);
|
||||
extern int drm_mode_mmap_dumb_ioctl(struct drm_device *dev,
|
||||
void *data, struct drm_file *file_priv);
|
||||
extern int drm_mode_destroy_dumb_ioctl(struct drm_device *dev,
|
||||
void *data, struct drm_file *file_priv);
|
||||
#endif /* __DRM_CRTC_H__ */
|
||||
|
|
|
@ -344,4 +344,33 @@ struct drm_mode_crtc_page_flip {
|
|||
__u64 user_data;
|
||||
};
|
||||
|
||||
/* create a dumb scanout buffer */
|
||||
struct drm_mode_create_dumb {
|
||||
uint32_t height;
|
||||
uint32_t width;
|
||||
uint32_t bpp;
|
||||
uint32_t flags;
|
||||
/* handle, pitch, size will be returned */
|
||||
uint32_t handle;
|
||||
uint32_t pitch;
|
||||
uint64_t size;
|
||||
};
|
||||
|
||||
/* set up for mmap of a dumb scanout buffer */
|
||||
struct drm_mode_map_dumb {
|
||||
/** Handle for the object being mapped. */
|
||||
__u32 handle;
|
||||
__u32 pad;
|
||||
/**
|
||||
* Fake offset to use for subsequent mmap call
|
||||
*
|
||||
* This is a fixed-size type for 32/64 compatibility.
|
||||
*/
|
||||
__u64 offset;
|
||||
};
|
||||
|
||||
struct drm_mode_destroy_dumb {
|
||||
uint32_t handle;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue