aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/gud/gud_drv.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/gud/gud_drv.c')
-rw-r--r--drivers/gpu/drm/gud/gud_drv.c61
1 files changed, 41 insertions, 20 deletions
diff --git a/drivers/gpu/drm/gud/gud_drv.c b/drivers/gpu/drm/gud/gud_drv.c
index e8b672dc9832..eb4e08846da4 100644
--- a/drivers/gpu/drm/gud/gud_drv.c
+++ b/drivers/gpu/drm/gud/gud_drv.c
@@ -364,7 +364,6 @@ static void gud_debugfs_init(struct drm_minor *minor)
static const struct drm_simple_display_pipe_funcs gud_pipe_funcs = {
.check = gud_pipe_check,
.update = gud_pipe_update,
- .prepare_fb = drm_gem_simple_display_pipe_prepare_fb,
};
static const struct drm_mode_config_funcs gud_mode_config_funcs = {
@@ -394,14 +393,42 @@ static const struct drm_driver gud_drm_driver = {
.minor = 0,
};
-static void gud_free_buffers_and_mutex(struct drm_device *drm, void *unused)
+static int gud_alloc_bulk_buffer(struct gud_device *gdrm)
{
- struct gud_device *gdrm = to_gud_device(drm);
+ unsigned int i, num_pages;
+ struct page **pages;
+ void *ptr;
+ int ret;
+
+ gdrm->bulk_buf = vmalloc_32(gdrm->bulk_len);
+ if (!gdrm->bulk_buf)
+ return -ENOMEM;
+
+ num_pages = DIV_ROUND_UP(gdrm->bulk_len, PAGE_SIZE);
+ pages = kmalloc_array(num_pages, sizeof(struct page *), GFP_KERNEL);
+ if (!pages)
+ return -ENOMEM;
+
+ for (i = 0, ptr = gdrm->bulk_buf; i < num_pages; i++, ptr += PAGE_SIZE)
+ pages[i] = vmalloc_to_page(ptr);
+
+ ret = sg_alloc_table_from_pages(&gdrm->bulk_sgt, pages, num_pages,
+ 0, gdrm->bulk_len, GFP_KERNEL);
+ kfree(pages);
+
+ return ret;
+}
+
+static void gud_free_buffers_and_mutex(void *data)
+{
+ struct gud_device *gdrm = data;
vfree(gdrm->compress_buf);
- kfree(gdrm->bulk_buf);
+ gdrm->compress_buf = NULL;
+ sg_free_table(&gdrm->bulk_sgt);
+ vfree(gdrm->bulk_buf);
+ gdrm->bulk_buf = NULL;
mutex_destroy(&gdrm->ctrl_lock);
- mutex_destroy(&gdrm->damage_lock);
}
static int gud_probe(struct usb_interface *intf, const struct usb_device_id *id)
@@ -455,7 +482,7 @@ static int gud_probe(struct usb_interface *intf, const struct usb_device_id *id)
INIT_WORK(&gdrm->work, gud_flush_work);
gud_clear_damage(gdrm);
- ret = drmm_add_action_or_reset(drm, gud_free_buffers_and_mutex, NULL);
+ ret = devm_add_action(dev, gud_free_buffers_and_mutex, gdrm);
if (ret)
return ret;
@@ -536,24 +563,17 @@ static int gud_probe(struct usb_interface *intf, const struct usb_device_id *id)
if (desc.max_buffer_size)
max_buffer_size = le32_to_cpu(desc.max_buffer_size);
-retry:
- /*
- * Use plain kmalloc here since devm_kmalloc() places struct devres at the beginning
- * of the buffer it allocates. This wastes a lot of memory when allocating big buffers.
- * Asking for 2M would actually allocate 4M. This would also prevent getting the biggest
- * possible buffer potentially leading to split transfers.
- */
- gdrm->bulk_buf = kmalloc(max_buffer_size, GFP_KERNEL | __GFP_NOWARN);
- if (!gdrm->bulk_buf) {
- max_buffer_size = roundup_pow_of_two(max_buffer_size) / 2;
- if (max_buffer_size < SZ_512K)
- return -ENOMEM;
- goto retry;
- }
+ /* Prevent a misbehaving device from allocating loads of RAM. 4096x4096@XRGB8888 = 64 MB */
+ if (max_buffer_size > SZ_64M)
+ max_buffer_size = SZ_64M;
gdrm->bulk_pipe = usb_sndbulkpipe(interface_to_usbdev(intf), usb_endpoint_num(bulk_out));
gdrm->bulk_len = max_buffer_size;
+ ret = gud_alloc_bulk_buffer(gdrm);
+ if (ret)
+ return ret;
+
if (gdrm->compression & GUD_COMPRESSION_LZ4) {
gdrm->lz4_comp_mem = devm_kmalloc(dev, LZ4_MEM_COMPRESS, GFP_KERNEL);
if (!gdrm->lz4_comp_mem)
@@ -640,6 +660,7 @@ static int gud_resume(struct usb_interface *intf)
static const struct usb_device_id gud_id_table[] = {
{ USB_DEVICE_INTERFACE_CLASS(0x1d50, 0x614d, USB_CLASS_VENDOR_SPEC) },
+ { USB_DEVICE_INTERFACE_CLASS(0x16d0, 0x10a9, USB_CLASS_VENDOR_SPEC) },
{ }
};