From 656fa22f9ceabbae74ea4628dd02d297aa07104b Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 11 May 2017 11:31:23 -0700 Subject: drm/vc4: Switch DSI to the panel-bridge layer, and support bridges. The newer version of the RPi panel driver is going to be a combination of a bridge and a panel, but we should also support panels without a bridge, so the panel-bridge layer lets us do that cleanly. v2: Drop "dev" argument. Signed-off-by: Eric Anholt Acked-by: Daniel Vetter Reviewed-by: Boris Brezillon Signed-off-by: Archit Taneja Link: http://patchwork.freedesktop.org/patch/msgid/20170511183128.25085-2-eric@anholt.net --- drivers/gpu/drm/vc4/Kconfig | 2 +- drivers/gpu/drm/vc4/vc4_dsi.c | 154 ++++++------------------------------------ 2 files changed, 21 insertions(+), 135 deletions(-) (limited to 'drivers/gpu/drm/vc4') diff --git a/drivers/gpu/drm/vc4/Kconfig b/drivers/gpu/drm/vc4/Kconfig index b16aefe4a8d3..4361bdcfd28a 100644 --- a/drivers/gpu/drm/vc4/Kconfig +++ b/drivers/gpu/drm/vc4/Kconfig @@ -7,7 +7,7 @@ config DRM_VC4 select DRM_KMS_HELPER select DRM_KMS_CMA_HELPER select DRM_GEM_CMA_HELPER - select DRM_PANEL + select DRM_PANEL_BRIDGE select SND_PCM select SND_PCM_ELD select SND_SOC_GENERIC_DMAENGINE_PCM diff --git a/drivers/gpu/drm/vc4/vc4_dsi.c b/drivers/gpu/drm/vc4/vc4_dsi.c index 0ef41df3915f..5e8b81eaa168 100644 --- a/drivers/gpu/drm/vc4/vc4_dsi.c +++ b/drivers/gpu/drm/vc4/vc4_dsi.c @@ -503,8 +503,8 @@ struct vc4_dsi { struct mipi_dsi_host dsi_host; struct drm_encoder *encoder; - struct drm_connector *connector; - struct drm_panel *panel; + struct drm_bridge *bridge; + bool is_panel_bridge; void __iomem *regs; @@ -605,18 +605,6 @@ to_vc4_dsi_encoder(struct drm_encoder *encoder) return container_of(encoder, struct vc4_dsi_encoder, base.base); } -/* VC4 DSI connector KMS struct */ -struct vc4_dsi_connector { - struct drm_connector base; - struct vc4_dsi *dsi; -}; - -static inline struct vc4_dsi_connector * -to_vc4_dsi_connector(struct drm_connector *connector) -{ - return container_of(connector, struct vc4_dsi_connector, base); -} - #define DSI_REG(reg) { reg, #reg } static const struct { u32 reg; @@ -724,79 +712,6 @@ int vc4_dsi_debugfs_regs(struct seq_file *m, void *unused) } #endif -static enum drm_connector_status -vc4_dsi_connector_detect(struct drm_connector *connector, bool force) -{ - struct vc4_dsi_connector *vc4_connector = - to_vc4_dsi_connector(connector); - struct vc4_dsi *dsi = vc4_connector->dsi; - - if (dsi->panel) - return connector_status_connected; - else - return connector_status_disconnected; -} - -static void vc4_dsi_connector_destroy(struct drm_connector *connector) -{ - drm_connector_unregister(connector); - drm_connector_cleanup(connector); -} - -static int vc4_dsi_connector_get_modes(struct drm_connector *connector) -{ - struct vc4_dsi_connector *vc4_connector = - to_vc4_dsi_connector(connector); - struct vc4_dsi *dsi = vc4_connector->dsi; - - if (dsi->panel) - return drm_panel_get_modes(dsi->panel); - - return 0; -} - -static const struct drm_connector_funcs vc4_dsi_connector_funcs = { - .dpms = drm_atomic_helper_connector_dpms, - .detect = vc4_dsi_connector_detect, - .fill_modes = drm_helper_probe_single_connector_modes, - .destroy = vc4_dsi_connector_destroy, - .reset = drm_atomic_helper_connector_reset, - .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, - .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, -}; - -static const struct drm_connector_helper_funcs vc4_dsi_connector_helper_funcs = { - .get_modes = vc4_dsi_connector_get_modes, -}; - -static struct drm_connector *vc4_dsi_connector_init(struct drm_device *dev, - struct vc4_dsi *dsi) -{ - struct drm_connector *connector; - struct vc4_dsi_connector *dsi_connector; - - dsi_connector = devm_kzalloc(dev->dev, sizeof(*dsi_connector), - GFP_KERNEL); - if (!dsi_connector) - return ERR_PTR(-ENOMEM); - - connector = &dsi_connector->base; - - dsi_connector->dsi = dsi; - - drm_connector_init(dev, connector, &vc4_dsi_connector_funcs, - DRM_MODE_CONNECTOR_DSI); - drm_connector_helper_add(connector, &vc4_dsi_connector_helper_funcs); - - connector->polled = 0; - connector->interlace_allowed = 0; - connector->doublescan_allowed = 0; - - drm_mode_connector_attach_encoder(connector, dsi->encoder); - - return connector; -} - static void vc4_dsi_encoder_destroy(struct drm_encoder *encoder) { drm_encoder_cleanup(encoder); @@ -894,12 +809,8 @@ static void vc4_dsi_encoder_disable(struct drm_encoder *encoder) struct vc4_dsi *dsi = vc4_encoder->dsi; struct device *dev = &dsi->pdev->dev; - drm_panel_disable(dsi->panel); - vc4_dsi_ulps(dsi, true); - drm_panel_unprepare(dsi->panel); - clk_disable_unprepare(dsi->pll_phy_clock); clk_disable_unprepare(dsi->escape_clock); clk_disable_unprepare(dsi->pixel_clock); @@ -984,12 +895,6 @@ static void vc4_dsi_encoder_enable(struct drm_encoder *encoder) return; } - ret = drm_panel_prepare(dsi->panel); - if (ret) { - DRM_ERROR("Panel failed to prepare\n"); - return; - } - if (debug_dump_regs) { DRM_INFO("DSI regs before:\n"); vc4_dsi_dump_regs(dsi); @@ -1211,13 +1116,6 @@ static void vc4_dsi_encoder_enable(struct drm_encoder *encoder) DRM_INFO("DSI regs after:\n"); vc4_dsi_dump_regs(dsi); } - - ret = drm_panel_enable(dsi->panel); - if (ret) { - DRM_ERROR("Panel failed to enable\n"); - drm_panel_unprepare(dsi->panel); - return; - } } static ssize_t vc4_dsi_host_transfer(struct mipi_dsi_host *host, @@ -1415,17 +1313,22 @@ static int vc4_dsi_host_attach(struct mipi_dsi_host *host, return 0; } - dsi->panel = of_drm_find_panel(device->dev.of_node); - if (!dsi->panel) - return 0; - - ret = drm_panel_attach(dsi->panel, dsi->connector); - if (ret != 0) - return ret; + dsi->bridge = of_drm_find_bridge(device->dev.of_node); + if (!dsi->bridge) { + struct drm_panel *panel = + of_drm_find_panel(device->dev.of_node); - drm_helper_hpd_irq_event(dsi->connector->dev); + dsi->bridge = drm_panel_bridge_add(panel, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(dsi->bridge)) { + ret = PTR_ERR(dsi->bridge); + dsi->bridge = NULL; + return ret; + } + dsi->is_panel_bridge = true; + } - return 0; + return drm_bridge_attach(dsi->encoder, dsi->bridge, NULL); } static int vc4_dsi_host_detach(struct mipi_dsi_host *host, @@ -1433,15 +1336,9 @@ static int vc4_dsi_host_detach(struct mipi_dsi_host *host, { struct vc4_dsi *dsi = host_to_dsi(host); - if (dsi->panel) { - int ret = drm_panel_detach(dsi->panel); - - if (ret) - return ret; - - dsi->panel = NULL; - - drm_helper_hpd_irq_event(dsi->connector->dev); + if (dsi->is_panel_bridge) { + drm_panel_bridge_remove(dsi->bridge); + dsi->bridge = NULL; } return 0; @@ -1708,12 +1605,6 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data) DRM_MODE_ENCODER_DSI, NULL); drm_encoder_helper_add(dsi->encoder, &vc4_dsi_encoder_helper_funcs); - dsi->connector = vc4_dsi_connector_init(drm, dsi); - if (IS_ERR(dsi->connector)) { - ret = PTR_ERR(dsi->connector); - goto err_destroy_encoder; - } - dsi->dsi_host.ops = &vc4_dsi_host_ops; dsi->dsi_host.dev = dev; @@ -1724,11 +1615,6 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data) pm_runtime_enable(dev); return 0; - -err_destroy_encoder: - vc4_dsi_encoder_destroy(dsi->encoder); - - return ret; } static void vc4_dsi_unbind(struct device *dev, struct device *master, @@ -1740,7 +1626,7 @@ static void vc4_dsi_unbind(struct device *dev, struct device *master, pm_runtime_disable(dev); - vc4_dsi_connector_destroy(dsi->connector); + drm_bridge_remove(dsi->bridge); vc4_dsi_encoder_destroy(dsi->encoder); mipi_dsi_host_unregister(&dsi->dsi_host); -- cgit v1.2.3 From 7b1298e05310f1fe58401f40e5426a558ec5d3ac Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 11 May 2017 11:31:24 -0700 Subject: drm/vc4: Switch DPI to using the panel-bridge helper. Another 100 lines of boilerplate gone, while allowing for bridges to be connected in the display chain. Reviewed-by: Boris Brezillon Signed-off-by: Eric Anholt Signed-off-by: Archit Taneja Link: http://patchwork.freedesktop.org/patch/msgid/20170511183128.25085-3-eric@anholt.net --- drivers/gpu/drm/vc4/vc4_dpi.c | 164 ++++++++---------------------------------- 1 file changed, 30 insertions(+), 134 deletions(-) (limited to 'drivers/gpu/drm/vc4') diff --git a/drivers/gpu/drm/vc4/vc4_dpi.c b/drivers/gpu/drm/vc4/vc4_dpi.c index 39d68080873c..2e0fe46aeb2e 100644 --- a/drivers/gpu/drm/vc4/vc4_dpi.c +++ b/drivers/gpu/drm/vc4/vc4_dpi.c @@ -23,8 +23,10 @@ */ #include +#include #include #include +#include #include #include #include @@ -95,7 +97,8 @@ struct vc4_dpi { struct drm_encoder *encoder; struct drm_connector *connector; - struct drm_panel *panel; + struct drm_bridge *bridge; + bool is_panel_bridge; void __iomem *regs; @@ -118,24 +121,6 @@ to_vc4_dpi_encoder(struct drm_encoder *encoder) return container_of(encoder, struct vc4_dpi_encoder, base.base); } -/* VC4 DPI connector KMS struct */ -struct vc4_dpi_connector { - struct drm_connector base; - struct vc4_dpi *dpi; - - /* Since the connector is attached to just the one encoder, - * this is the reference to it so we can do the best_encoder() - * hook. - */ - struct drm_encoder *encoder; -}; - -static inline struct vc4_dpi_connector * -to_vc4_dpi_connector(struct drm_connector *connector) -{ - return container_of(connector, struct vc4_dpi_connector, base); -} - #define DPI_REG(reg) { reg, #reg } static const struct { u32 reg; @@ -167,80 +152,6 @@ int vc4_dpi_debugfs_regs(struct seq_file *m, void *unused) } #endif -static enum drm_connector_status -vc4_dpi_connector_detect(struct drm_connector *connector, bool force) -{ - struct vc4_dpi_connector *vc4_connector = - to_vc4_dpi_connector(connector); - struct vc4_dpi *dpi = vc4_connector->dpi; - - if (dpi->panel) - return connector_status_connected; - else - return connector_status_disconnected; -} - -static void vc4_dpi_connector_destroy(struct drm_connector *connector) -{ - drm_connector_unregister(connector); - drm_connector_cleanup(connector); -} - -static int vc4_dpi_connector_get_modes(struct drm_connector *connector) -{ - struct vc4_dpi_connector *vc4_connector = - to_vc4_dpi_connector(connector); - struct vc4_dpi *dpi = vc4_connector->dpi; - - if (dpi->panel) - return drm_panel_get_modes(dpi->panel); - - return 0; -} - -static const struct drm_connector_funcs vc4_dpi_connector_funcs = { - .dpms = drm_atomic_helper_connector_dpms, - .detect = vc4_dpi_connector_detect, - .fill_modes = drm_helper_probe_single_connector_modes, - .destroy = vc4_dpi_connector_destroy, - .reset = drm_atomic_helper_connector_reset, - .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, - .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, -}; - -static const struct drm_connector_helper_funcs vc4_dpi_connector_helper_funcs = { - .get_modes = vc4_dpi_connector_get_modes, -}; - -static struct drm_connector *vc4_dpi_connector_init(struct drm_device *dev, - struct vc4_dpi *dpi) -{ - struct drm_connector *connector = NULL; - struct vc4_dpi_connector *dpi_connector; - - dpi_connector = devm_kzalloc(dev->dev, sizeof(*dpi_connector), - GFP_KERNEL); - if (!dpi_connector) - return ERR_PTR(-ENOMEM); - - connector = &dpi_connector->base; - - dpi_connector->encoder = dpi->encoder; - dpi_connector->dpi = dpi; - - drm_connector_init(dev, connector, &vc4_dpi_connector_funcs, - DRM_MODE_CONNECTOR_DPI); - drm_connector_helper_add(connector, &vc4_dpi_connector_helper_funcs); - - connector->polled = 0; - connector->interlace_allowed = 0; - connector->doublescan_allowed = 0; - - drm_mode_connector_attach_encoder(connector, dpi->encoder); - - return connector; -} - static const struct drm_encoder_funcs vc4_dpi_encoder_funcs = { .destroy = drm_encoder_cleanup, }; @@ -250,11 +161,7 @@ static void vc4_dpi_encoder_disable(struct drm_encoder *encoder) struct vc4_dpi_encoder *vc4_encoder = to_vc4_dpi_encoder(encoder); struct vc4_dpi *dpi = vc4_encoder->dpi; - drm_panel_disable(dpi->panel); - clk_disable_unprepare(dpi->pixel_clock); - - drm_panel_unprepare(dpi->panel); } static void vc4_dpi_encoder_enable(struct drm_encoder *encoder) @@ -265,12 +172,6 @@ static void vc4_dpi_encoder_enable(struct drm_encoder *encoder) u32 dpi_c = DPI_ENABLE | DPI_OUTPUT_ENABLE_MODE; int ret; - ret = drm_panel_prepare(dpi->panel); - if (ret) { - DRM_ERROR("Panel failed to prepare\n"); - return; - } - if (dpi->connector->display_info.num_bus_formats) { u32 bus_format = dpi->connector->display_info.bus_formats[0]; @@ -321,13 +222,6 @@ static void vc4_dpi_encoder_enable(struct drm_encoder *encoder) ret = clk_prepare_enable(dpi->pixel_clock); if (ret) DRM_ERROR("Failed to set clock rate: %d\n", ret); - - ret = drm_panel_enable(dpi->panel); - if (ret) { - DRM_ERROR("Panel failed to enable\n"); - drm_panel_unprepare(dpi->panel); - return; - } } static bool vc4_dpi_encoder_mode_fixup(struct drm_encoder *encoder, @@ -351,24 +245,34 @@ static const struct of_device_id vc4_dpi_dt_match[] = { {} }; -/* Walks the OF graph to find the panel node and then asks DRM to look - * up the panel. +/* Sets up the next link in the display chain, whether it's a panel or + * a bridge. */ -static struct drm_panel *vc4_dpi_get_panel(struct device *dev) +static int vc4_dpi_init_bridge(struct vc4_dpi *dpi) { - struct device_node *panel_node; - struct device_node *np = dev->of_node; + struct device *dev = &dpi->pdev->dev; struct drm_panel *panel; + int ret; - /* don't proceed if we have an endpoint but no panel_node tied to it */ - panel_node = of_graph_get_remote_node(np, 0, 0); - if (!panel_node) - return NULL; + ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0, + &panel, &dpi->bridge); + if (ret) { + /* If nothing was connected in the DT, that's not an + * error. + */ + if (ret == -ENODEV) + return 0; + else + return ret; + } - panel = of_drm_find_panel(panel_node); - of_node_put(panel_node); + if (panel) { + dpi->bridge = drm_panel_bridge_add(panel, + DRM_MODE_CONNECTOR_DPI); + dpi->is_panel_bridge = true; + } - return panel; + return drm_bridge_attach(dpi->encoder, dpi->bridge, NULL); } static int vc4_dpi_bind(struct device *dev, struct device *master, void *data) @@ -422,20 +326,13 @@ static int vc4_dpi_bind(struct device *dev, struct device *master, void *data) if (ret) DRM_ERROR("Failed to turn on core clock: %d\n", ret); - dpi->panel = vc4_dpi_get_panel(dev); - drm_encoder_init(drm, dpi->encoder, &vc4_dpi_encoder_funcs, DRM_MODE_ENCODER_DPI, NULL); drm_encoder_helper_add(dpi->encoder, &vc4_dpi_encoder_helper_funcs); - dpi->connector = vc4_dpi_connector_init(drm, dpi); - if (IS_ERR(dpi->connector)) { - ret = PTR_ERR(dpi->connector); + ret = vc4_dpi_init_bridge(dpi); + if (ret) goto err_destroy_encoder; - } - - if (dpi->panel) - drm_panel_attach(dpi->panel, dpi->connector); dev_set_drvdata(dev, dpi); @@ -456,10 +353,9 @@ static void vc4_dpi_unbind(struct device *dev, struct device *master, struct vc4_dev *vc4 = to_vc4_dev(drm); struct vc4_dpi *dpi = dev_get_drvdata(dev); - if (dpi->panel) - drm_panel_detach(dpi->panel); + if (dpi->is_panel_bridge) + drm_panel_bridge_remove(dpi->bridge); - vc4_dpi_connector_destroy(dpi->connector); drm_encoder_cleanup(dpi->encoder); clk_disable_unprepare(dpi->core_clock); -- cgit v1.2.3 From 24bb206f32cdaa76c59444b62be51708dc16fbe8 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 7 Jun 2017 21:05:57 +0200 Subject: drm/vc4/vc4_bo.c: always set bo->resv The bo->resv pointer could be NULL, leading to kernel oopses like the one below. This patch ensures that bo->resv is always set in vc4_create_object ensuring that it is never NULL. Thanks to Eric Anholt for pointing to the correct solution. [ 19.738487] Unable to handle kernel NULL pointer dereference at virtual address 00000000 [ 19.746805] pgd = ffff8000275fc000 [ 19.750319] [00000000] *pgd=0000000000000000 [ 19.754715] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 19.760369] Modules linked in: smsc95xx usbnet vc4 drm_kms_helper drm pwm_bcm2835 i2c_bcm2835 bcm2835_rng rng_core bcm2835_dma virt_dma [ 19.772767] CPU: 0 PID: 1297 Comm: Xorg Not tainted 4.12.0-rc1-rpi3 #58 [ 19.779476] Hardware name: Raspberry Pi 3 Model B (DT) [ 19.784688] task: ffff800028268000 task.stack: ffff800026c08000 [ 19.790705] PC is at ww_mutex_lock_interruptible+0x14/0xc0 [ 19.796329] LR is at vc4_submit_cl_ioctl+0x4fc/0x998 [vc4] ... [ 20.240855] [] ww_mutex_lock_interruptible+0x14/0xc0 [ 20.247528] [] vc4_submit_cl_ioctl+0x4fc/0x998 [vc4] [ 20.254372] [] drm_ioctl+0x180/0x438 [drm] [ 20.260120] [] do_vfs_ioctl+0xa4/0x7d0 [ 20.265510] [] SyS_ioctl+0x7c/0x98 [ 20.270550] [] el0_svc_naked+0x24/0x28 [ 20.275941] Code: d2800002 d5384103 910003fd f9800011 (c85ffc04) [ 20.282527] ---[ end trace 1f6bd640ff32ae12 ]--- Signed-off-by: Hans Verkuil Reviewed-by: Eric Anholt Link: http://patchwork.freedesktop.org/patch/msgid/14e68768-6c92-2d74-92fd-196dbc50d8f7@xs4all.nl --- drivers/gpu/drm/vc4/vc4_bo.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'drivers/gpu/drm/vc4') diff --git a/drivers/gpu/drm/vc4/vc4_bo.c b/drivers/gpu/drm/vc4/vc4_bo.c index 80b2f9e55c5c..590c0912afc1 100644 --- a/drivers/gpu/drm/vc4/vc4_bo.c +++ b/drivers/gpu/drm/vc4/vc4_bo.c @@ -91,8 +91,7 @@ static void vc4_bo_destroy(struct vc4_bo *bo) vc4->bo_stats.num_allocated--; vc4->bo_stats.size_allocated -= obj->size; - if (bo->resv == &bo->_resv) - reservation_object_fini(bo->resv); + reservation_object_fini(&bo->_resv); drm_gem_cma_free_object(obj); } @@ -212,6 +211,8 @@ struct drm_gem_object *vc4_create_object(struct drm_device *dev, size_t size) vc4->bo_stats.num_allocated++; vc4->bo_stats.size_allocated += size; mutex_unlock(&vc4->bo_lock); + bo->resv = &bo->_resv; + reservation_object_init(bo->resv); return &bo->base.base; } @@ -250,12 +251,7 @@ struct vc4_bo *vc4_bo_create(struct drm_device *dev, size_t unaligned_size, return ERR_PTR(-ENOMEM); } } - bo = to_vc4_bo(&cma_obj->base); - - bo->resv = &bo->_resv; - reservation_object_init(bo->resv); - - return bo; + return to_vc4_bo(&cma_obj->base); } int vc4_dumb_create(struct drm_file *file_priv, -- cgit v1.2.3 From d0b1d259a4b58b21a21ea82d7174bf7ea825e9cc Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Fri, 12 May 2017 14:38:03 +0200 Subject: drm/vc4: Fix resource leak in 'vc4_get_hang_state_ioctl()' in error handling path If one 'drm_gem_handle_create()' fails, we leak somes handles and some memory. In order to fix it: - move the 'free(bo_state)' at the end of the function so that it is also called in the eror handling path. This has the side effect to also try to free it if the first 'kcalloc' fails. This is harmless. - add a new label, err_delete_handle, in order to delete already allocated handles in error handling path - remove the now useless 'err' label The way the code is now written will also delete the handles if the 'copy_to_user()' call fails. Signed-off-by: Christophe JAILLET Reviewed-by: Eric Anholt Link: http://patchwork.freedesktop.org/patch/msgid/20170512123803.1886-1-christophe.jaillet@wanadoo.fr --- drivers/gpu/drm/vc4/vc4_gem.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'drivers/gpu/drm/vc4') diff --git a/drivers/gpu/drm/vc4/vc4_gem.c b/drivers/gpu/drm/vc4/vc4_gem.c index 9dc7646d49ed..d5b821ad06af 100644 --- a/drivers/gpu/drm/vc4/vc4_gem.c +++ b/drivers/gpu/drm/vc4/vc4_gem.c @@ -111,8 +111,8 @@ vc4_get_hang_state_ioctl(struct drm_device *dev, void *data, &handle); if (ret) { - state->bo_count = i - 1; - goto err; + state->bo_count = i; + goto err_delete_handle; } bo_state[i].handle = handle; bo_state[i].paddr = vc4_bo->base.paddr; @@ -124,13 +124,16 @@ vc4_get_hang_state_ioctl(struct drm_device *dev, void *data, state->bo_count * sizeof(*bo_state))) ret = -EFAULT; - kfree(bo_state); +err_delete_handle: + if (ret) { + for (i = 0; i < state->bo_count; i++) + drm_gem_handle_delete(file_priv, bo_state[i].handle); + } err_free: - vc4_free_hang_state(dev, kernel_state); + kfree(bo_state); -err: return ret; } -- cgit v1.2.3