diff options
Diffstat (limited to 'drivers/gpu')
28 files changed, 296 insertions, 206 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c index 2e9db0ebe678..7056925eb386 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c @@ -376,7 +376,7 @@ int amdgpu_fence_driver_start_ring(struct amdgpu_ring *ring, struct amdgpu_device *adev = ring->adev; uint64_t index; - if (ring != &adev->uvd.inst[ring->me].ring) { + if (ring->funcs->type != AMDGPU_RING_TYPE_UVD) { ring->fence_drv.cpu_addr = &adev->wb.wb[ring->fence_offs]; ring->fence_drv.gpu_addr = adev->wb.gpu_addr + (ring->fence_offs * 4); } else { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c index 3f2a5e73e69f..a66cd521a875 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c @@ -52,7 +52,7 @@ int amdgpu_vcn_sw_init(struct amdgpu_device *adev) unsigned long bo_size; const char *fw_name; const struct common_firmware_header *hdr; - unsigned version_major, version_minor, family_id; + unsigned char fw_check; int r; INIT_DELAYED_WORK(&adev->vcn.idle_work, amdgpu_vcn_idle_work_handler); @@ -83,12 +83,33 @@ int amdgpu_vcn_sw_init(struct amdgpu_device *adev) hdr = (const struct common_firmware_header *)adev->vcn.fw->data; adev->vcn.fw_version = le32_to_cpu(hdr->ucode_version); - family_id = le32_to_cpu(hdr->ucode_version) & 0xff; - version_major = (le32_to_cpu(hdr->ucode_version) >> 24) & 0xff; - version_minor = (le32_to_cpu(hdr->ucode_version) >> 8) & 0xff; - DRM_INFO("Found VCN firmware Version: %hu.%hu Family ID: %hu\n", - version_major, version_minor, family_id); + /* Bit 20-23, it is encode major and non-zero for new naming convention. + * This field is part of version minor and DRM_DISABLED_FLAG in old naming + * convention. Since the l:wq!atest version minor is 0x5B and DRM_DISABLED_FLAG + * is zero in old naming convention, this field is always zero so far. + * These four bits are used to tell which naming convention is present. + */ + fw_check = (le32_to_cpu(hdr->ucode_version) >> 20) & 0xf; + if (fw_check) { + unsigned int dec_ver, enc_major, enc_minor, vep, fw_rev; + + fw_rev = le32_to_cpu(hdr->ucode_version) & 0xfff; + enc_minor = (le32_to_cpu(hdr->ucode_version) >> 12) & 0xff; + enc_major = fw_check; + dec_ver = (le32_to_cpu(hdr->ucode_version) >> 24) & 0xf; + vep = (le32_to_cpu(hdr->ucode_version) >> 28) & 0xf; + DRM_INFO("Found VCN firmware Version ENC: %hu.%hu DEC: %hu VEP: %hu Revision: %hu\n", + enc_major, enc_minor, dec_ver, vep, fw_rev); + } else { + unsigned int version_major, version_minor, family_id; + + family_id = le32_to_cpu(hdr->ucode_version) & 0xff; + version_major = (le32_to_cpu(hdr->ucode_version) >> 24) & 0xff; + version_minor = (le32_to_cpu(hdr->ucode_version) >> 8) & 0xff; + DRM_INFO("Found VCN firmware Version: %hu.%hu Family ID: %hu\n", + version_major, version_minor, family_id); + } bo_size = AMDGPU_GPU_PAGE_ALIGN(le32_to_cpu(hdr->ucode_size_bytes) + 8) + AMDGPU_VCN_STACK_SIZE + AMDGPU_VCN_HEAP_SIZE diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index 819949418495..422d1a434db4 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -1577,7 +1577,9 @@ static int amdgpu_vm_bo_split_mapping(struct amdgpu_device *adev, uint64_t count; max_entries = min(max_entries, 16ull * 1024ull); - for (count = 1; count < max_entries; ++count) { + for (count = 1; + count < max_entries / (PAGE_SIZE / AMDGPU_GPU_PAGE_SIZE); + ++count) { uint64_t idx = pfn + count; if (pages_addr[idx] != @@ -1590,7 +1592,7 @@ static int amdgpu_vm_bo_split_mapping(struct amdgpu_device *adev, dma_addr = pages_addr; } else { addr = pages_addr[pfn]; - max_entries = count; + max_entries = count * (PAGE_SIZE / AMDGPU_GPU_PAGE_SIZE); } } else if (flags & AMDGPU_PTE_VALID) { @@ -1605,7 +1607,7 @@ static int amdgpu_vm_bo_split_mapping(struct amdgpu_device *adev, if (r) return r; - pfn += last - start + 1; + pfn += (last - start + 1) / (PAGE_SIZE / AMDGPU_GPU_PAGE_SIZE); if (nodes && nodes->size == pfn) { pfn = 0; ++nodes; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 655950102827..66bd3cc3e387 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -3927,10 +3927,11 @@ static void amdgpu_dm_do_flip(struct drm_crtc *crtc, if (acrtc->base.state->event) prepare_flip_isr(acrtc); + spin_unlock_irqrestore(&crtc->dev->event_lock, flags); + surface_updates->surface = dc_stream_get_status(acrtc_state->stream)->plane_states[0]; surface_updates->flip_addr = &addr; - dc_commit_updates_for_stream(adev->dm.dc, surface_updates, 1, @@ -3943,9 +3944,6 @@ static void amdgpu_dm_do_flip(struct drm_crtc *crtc, __func__, addr.address.grph.addr.high_part, addr.address.grph.addr.low_part); - - - spin_unlock_irqrestore(&crtc->dev->event_lock, flags); } /* @@ -4205,6 +4203,7 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) struct drm_connector *connector; struct drm_connector_state *old_con_state, *new_con_state; struct dm_crtc_state *dm_old_crtc_state, *dm_new_crtc_state; + int crtc_disable_count = 0; drm_atomic_helper_update_legacy_modeset_state(dev, state); @@ -4409,6 +4408,9 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc); bool modeset_needed; + if (old_crtc_state->active && !new_crtc_state->active) + crtc_disable_count++; + dm_new_crtc_state = to_dm_crtc_state(new_crtc_state); dm_old_crtc_state = to_dm_crtc_state(old_crtc_state); modeset_needed = modeset_required( @@ -4462,11 +4464,9 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) * so we can put the GPU into runtime suspend if we're not driving any * displays anymore */ + for (i = 0; i < crtc_disable_count; i++) + pm_runtime_put_autosuspend(dev->dev); pm_runtime_mark_last_busy(dev->dev); - for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { - if (old_crtc_state->active && !new_crtc_state->active) - pm_runtime_put_autosuspend(dev->dev); - } } diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c index 8d20faa198cf..0a788d76ed5f 100644 --- a/drivers/gpu/drm/arm/malidp_drv.c +++ b/drivers/gpu/drm/arm/malidp_drv.c @@ -278,7 +278,6 @@ static int malidp_init(struct drm_device *drm) static void malidp_fini(struct drm_device *drm) { - drm_atomic_helper_shutdown(drm); drm_mode_config_cleanup(drm); } @@ -646,6 +645,7 @@ vblank_fail: malidp_de_irq_fini(drm); drm->irq_enabled = false; irq_init_fail: + drm_atomic_helper_shutdown(drm); component_unbind_all(dev, drm); bind_fail: of_node_put(malidp->crtc.port); @@ -681,6 +681,7 @@ static void malidp_unbind(struct device *dev) malidp_se_irq_fini(drm); malidp_de_irq_fini(drm); drm->irq_enabled = false; + drm_atomic_helper_shutdown(drm); component_unbind_all(dev, drm); of_node_put(malidp->crtc.port); malidp->crtc.port = NULL; diff --git a/drivers/gpu/drm/arm/malidp_hw.c b/drivers/gpu/drm/arm/malidp_hw.c index d789b46dc817..069783e715f1 100644 --- a/drivers/gpu/drm/arm/malidp_hw.c +++ b/drivers/gpu/drm/arm/malidp_hw.c @@ -634,7 +634,8 @@ const struct malidp_hw malidp_device[MALIDP_MAX_DEVICES] = { .vsync_irq = MALIDP500_DE_IRQ_VSYNC, }, .se_irq_map = { - .irq_mask = MALIDP500_SE_IRQ_CONF_MODE, + .irq_mask = MALIDP500_SE_IRQ_CONF_MODE | + MALIDP500_SE_IRQ_GLOBAL, .vsync_irq = 0, }, .dc_irq_map = { diff --git a/drivers/gpu/drm/arm/malidp_planes.c b/drivers/gpu/drm/arm/malidp_planes.c index 7a44897c50fe..29409a65d864 100644 --- a/drivers/gpu/drm/arm/malidp_planes.c +++ b/drivers/gpu/drm/arm/malidp_planes.c @@ -23,6 +23,7 @@ /* Layer specific register offsets */ #define MALIDP_LAYER_FORMAT 0x000 +#define LAYER_FORMAT_MASK 0x3f #define MALIDP_LAYER_CONTROL 0x004 #define LAYER_ENABLE (1 << 0) #define LAYER_FLOWCFG_MASK 7 @@ -235,8 +236,8 @@ static int malidp_de_plane_check(struct drm_plane *plane, if (state->rotation & MALIDP_ROTATED_MASK) { int val; - val = mp->hwdev->hw->rotmem_required(mp->hwdev, state->crtc_h, - state->crtc_w, + val = mp->hwdev->hw->rotmem_required(mp->hwdev, state->crtc_w, + state->crtc_h, fb->format->format); if (val < 0) return val; @@ -337,7 +338,9 @@ static void malidp_de_plane_update(struct drm_plane *plane, dest_w = plane->state->crtc_w; dest_h = plane->state->crtc_h; - malidp_hw_write(mp->hwdev, ms->format, mp->layer->base); + val = malidp_hw_read(mp->hwdev, mp->layer->base); + val = (val & ~LAYER_FORMAT_MASK) | ms->format; + malidp_hw_write(mp->hwdev, val, mp->layer->base); for (i = 0; i < ms->n_planes; i++) { /* calculate the offset for the layer's plane registers */ diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 735f695cb889..f4751b383858 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2261,9 +2261,6 @@ static inline struct scatterlist *____sg_next(struct scatterlist *sg) **/ static inline struct scatterlist *__sg_next(struct scatterlist *sg) { -#ifdef CONFIG_DEBUG_SG - BUG_ON(sg->sg_magic != SG_MAGIC); -#endif return sg_is_last(sg) ? NULL : ____sg_next(sg); } diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c index 32b1a6cdecfc..d3443125e661 100644 --- a/drivers/gpu/drm/meson/meson_drv.c +++ b/drivers/gpu/drm/meson/meson_drv.c @@ -197,8 +197,10 @@ static int meson_drv_bind_master(struct device *dev, bool has_components) priv->io_base = regs; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hhi"); - if (!res) - return -EINVAL; + if (!res) { + ret = -EINVAL; + goto free_drm; + } /* Simply ioremap since it may be a shared register zone */ regs = devm_ioremap(dev, res->start, resource_size(res)); if (!regs) { @@ -215,8 +217,10 @@ static int meson_drv_bind_master(struct device *dev, bool has_components) } res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dmc"); - if (!res) - return -EINVAL; + if (!res) { + ret = -EINVAL; + goto free_drm; + } /* Simply ioremap since it may be a shared register zone */ regs = devm_ioremap(dev, res->start, resource_size(res)); if (!regs) { diff --git a/drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c b/drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c index 92fe125ce22e..f34c06bb5bd7 100644 --- a/drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c +++ b/drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c @@ -4,7 +4,7 @@ * Copyright (C) 2010 Nokia Corporation * * Original Driver Author: Imre Deak <imre.deak@nokia.com> - * Based on panel-generic.c by Tomi Valkeinen <tomi.valkeinen@nokia.com> + * Based on panel-generic.c by Tomi Valkeinen <tomi.valkeinen@ti.com> * Adapted to new DSS2 framework: Roger Quadros <roger.quadros@nokia.com> * * This program is free software; you can redistribute it and/or modify it diff --git a/drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c b/drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c index b5d8a00df811..a1f1dc18407a 100644 --- a/drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c +++ b/drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c @@ -2,7 +2,7 @@ * Toppoly TD028TTEC1 panel support * * Copyright (C) 2008 Nokia Corporation - * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> + * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> * * Neo 1973 code (jbt6k74.c): * Copyright (C) 2006-2007 by OpenMoko, Inc. diff --git a/drivers/gpu/drm/omapdrm/dss/core.c b/drivers/gpu/drm/omapdrm/dss/core.c index acef7ece5783..07d00a186f15 100644 --- a/drivers/gpu/drm/omapdrm/dss/core.c +++ b/drivers/gpu/drm/omapdrm/dss/core.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2009 Nokia Corporation - * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> + * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> * * Some code and ideas taken from drivers/video/omap/ driver * by Imre Deak. @@ -82,7 +82,7 @@ static void __exit omap_dss_exit(void) module_init(omap_dss_init); module_exit(omap_dss_exit); -MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@nokia.com>"); +MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>"); MODULE_DESCRIPTION("OMAP2/3 Display Subsystem"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/omapdrm/dss/dispc.c b/drivers/gpu/drm/omapdrm/dss/dispc.c index 7f3ac6b13b56..84f274c4a4cb 100644 --- a/drivers/gpu/drm/omapdrm/dss/dispc.c +++ b/drivers/gpu/drm/omapdrm/dss/dispc.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2009 Nokia Corporation - * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> + * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> * * Some code and ideas taken from drivers/video/omap/ driver * by Imre Deak. diff --git a/drivers/gpu/drm/omapdrm/dss/display.c b/drivers/gpu/drm/omapdrm/dss/display.c index 424143128cd4..9e7fcbd57e52 100644 --- a/drivers/gpu/drm/omapdrm/dss/display.c +++ b/drivers/gpu/drm/omapdrm/dss/display.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2009 Nokia Corporation - * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> + * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> * * Some code and ideas taken from drivers/video/omap/ driver * by Imre Deak. diff --git a/drivers/gpu/drm/omapdrm/dss/dpi.c b/drivers/gpu/drm/omapdrm/dss/dpi.c index 3d662e6805eb..9fcc50217133 100644 --- a/drivers/gpu/drm/omapdrm/dss/dpi.c +++ b/drivers/gpu/drm/omapdrm/dss/dpi.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2009 Nokia Corporation - * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> + * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> * * Some code and ideas taken from drivers/video/omap/ driver * by Imre Deak. diff --git a/drivers/gpu/drm/omapdrm/dss/dsi.c b/drivers/gpu/drm/omapdrm/dss/dsi.c index d4a680629825..74467b308721 100644 --- a/drivers/gpu/drm/omapdrm/dss/dsi.c +++ b/drivers/gpu/drm/omapdrm/dss/dsi.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2009 Nokia Corporation - * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> + * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published by diff --git a/drivers/gpu/drm/omapdrm/dss/dss.c b/drivers/gpu/drm/omapdrm/dss/dss.c index 0b908e9de792..cb80ddaa19d2 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss.c +++ b/drivers/gpu/drm/omapdrm/dss/dss.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2009 Nokia Corporation - * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> + * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> * * Some code and ideas taken from drivers/video/omap/ driver * by Imre Deak. diff --git a/drivers/gpu/drm/omapdrm/dss/dss.h b/drivers/gpu/drm/omapdrm/dss/dss.h index 847c78ade024..38302631b64b 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss.h +++ b/drivers/gpu/drm/omapdrm/dss/dss.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2009 Nokia Corporation - * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> + * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> * * Some code and ideas taken from drivers/video/omap/ driver * by Imre Deak. @@ -180,6 +180,9 @@ struct dss_pll_hw { /* DRA7 errata i886: use high N & M to avoid jitter */ bool errata_i886; + + /* DRA7 errata i932: retry pll lock on failure */ + bool errata_i932; }; struct dss_pll { diff --git a/drivers/gpu/drm/omapdrm/dss/pll.c b/drivers/gpu/drm/omapdrm/dss/pll.c index 078b0e8216c3..ff362b38bf0d 100644 --- a/drivers/gpu/drm/omapdrm/dss/pll.c +++ b/drivers/gpu/drm/omapdrm/dss/pll.c @@ -16,6 +16,7 @@ #define DSS_SUBSYS_NAME "PLL" +#include <linux/delay.h> #include <linux/clk.h> #include <linux/io.h> #include <linux/kernel.h> @@ -381,6 +382,22 @@ static int dss_wait_hsdiv_ack(struct dss_pll *pll, u32 hsdiv_ack_mask) return -ETIMEDOUT; } +static bool pll_is_locked(u32 stat) +{ + /* + * Required value for each bitfield listed below + * + * PLL_STATUS[6] = 0 PLL_BYPASS + * PLL_STATUS[5] = 0 PLL_HIGHJITTER + * + * PLL_STATUS[3] = 0 PLL_LOSSREF + * PLL_STATUS[2] = 0 PLL_RECAL + * PLL_STATUS[1] = 1 PLL_LOCK + * PLL_STATUS[0] = 1 PLL_CTRL_RESET_DONE + */ + return ((stat & 0x6f) == 0x3); +} + int dss_pll_write_config_type_a(struct dss_pll *pll, const struct dss_pll_clock_info *cinfo) { @@ -436,18 +453,54 @@ int dss_pll_write_config_type_a(struct dss_pll *pll, l = FLD_MOD(l, 0, 25, 25); /* M7_CLOCK_EN */ writel_relaxed(l, base + PLL_CONFIGURATION2); - writel_relaxed(1, base + PLL_GO); /* PLL_GO */ + if (hw->errata_i932) { + int cnt = 0; + u32 sleep_time; + const u32 max_lock_retries = 20; - if (wait_for_bit_change(base + PLL_GO, 0, 0) != 0) { - DSSERR("DSS DPLL GO bit not going down.\n"); - r = -EIO; - goto err; - } + /* + * Calculate wait time for PLL LOCK + * 1000 REFCLK cycles in us. + */ + sleep_time = DIV_ROUND_UP(1000*1000*1000, cinfo->fint); - if (wait_for_bit_change(base + PLL_STATUS, 1, 1) != 1) { - DSSERR("cannot lock DSS DPLL\n"); - r = -EIO; - goto err; + for (cnt = 0; cnt < max_lock_retries; cnt++) { + writel_relaxed(1, base + PLL_GO); /* PLL_GO */ + + /** + * read the register back to ensure the write is + * flushed + */ + readl_relaxed(base + PLL_GO); + + usleep_range(sleep_time, sleep_time + 5); + l = readl_relaxed(base + PLL_STATUS); + + if (pll_is_locked(l) && + !(readl_relaxed(base + PLL_GO) & 0x1)) + break; + + } + + if (cnt == max_lock_retries) { + DSSERR("cannot lock PLL\n"); + r = -EIO; + goto err; + } + } else { + writel_relaxed(1, base + PLL_GO); /* PLL_GO */ + + if (wait_for_bit_change(base + PLL_GO, 0, 0) != 0) { + DSSERR("DSS DPLL GO bit not going down.\n"); + r = -EIO; + goto err; + } + + if (wait_for_bit_change(base + PLL_STATUS, 1, 1) != 1) { + DSSERR("cannot lock DSS DPLL\n"); + r = -EIO; + goto err; + } } l = readl_relaxed(base + PLL_CONFIGURATION2); diff --git a/drivers/gpu/drm/omapdrm/dss/sdi.c b/drivers/gpu/drm/omapdrm/dss/sdi.c index 1e2c931f6acf..69c3b7a3d5c7 100644 --- a/drivers/gpu/drm/omapdrm/dss/sdi.c +++ b/drivers/gpu/drm/omapdrm/dss/sdi.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2009 Nokia Corporation - * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> + * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published by diff --git a/drivers/gpu/drm/omapdrm/dss/venc.c b/drivers/gpu/drm/omapdrm/dss/venc.c index 24d1ced210bd..ac01907dcc34 100644 --- a/drivers/gpu/drm/omapdrm/dss/venc.c +++ b/drivers/gpu/drm/omapdrm/dss/venc.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2009 Nokia Corporation - * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> + * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> * * VENC settings from TI's DSS driver * diff --git a/drivers/gpu/drm/omapdrm/dss/video-pll.c b/drivers/gpu/drm/omapdrm/dss/video-pll.c index 585ed94ccf17..cb46311f92c9 100644 --- a/drivers/gpu/drm/omapdrm/dss/video-pll.c +++ b/drivers/gpu/drm/omapdrm/dss/video-pll.c @@ -134,6 +134,7 @@ static const struct dss_pll_hw dss_dra7_video_pll_hw = { .has_refsel = true, .errata_i886 = true, + .errata_i932 = true, }; struct dss_pll *dss_video_pll_init(struct dss_device *dss, diff --git a/drivers/gpu/drm/omapdrm/omap_debugfs.c b/drivers/gpu/drm/omapdrm/omap_debugfs.c index b42e286616b0..91cf043f2b6b 100644 --- a/drivers/gpu/drm/omapdrm/omap_debugfs.c +++ b/drivers/gpu/drm/omapdrm/omap_debugfs.c @@ -30,16 +30,11 @@ static int gem_show(struct seq_file *m, void *arg) struct drm_info_node *node = (struct drm_info_node *) m->private; struct drm_device *dev = node->minor->dev; struct omap_drm_private *priv = dev->dev_private; - int ret; - - ret = mutex_lock_interruptible(&dev->struct_mutex); - if (ret) - return ret; seq_printf(m, "All Objects:\n"); + mutex_lock(&priv->list_lock); omap_gem_describe_objects(&priv->obj_list, m); - - mutex_unlock(&dev->struct_mutex); + mutex_unlock(&priv->list_lock); return 0; } diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index ef3b0e3571ec..5005ecc284d2 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c @@ -493,7 +493,7 @@ static struct drm_driver omap_drm_driver = { .prime_fd_to_handle = drm_gem_prime_fd_to_handle, .gem_prime_export = omap_gem_prime_export, .gem_prime_import = omap_gem_prime_import, - .gem_free_object = omap_gem_free_object, + .gem_free_object_unlocked = omap_gem_free_object, .gem_vm_ops = &omap_gem_vm_ops, .dumb_create = omap_gem_dumb_create, .dumb_map_offset = omap_gem_dumb_map_offset, @@ -540,7 +540,7 @@ static int omapdrm_init(struct omap_drm_private *priv, struct device *dev) priv->omaprev = soc ? (unsigned int)soc->data : 0; priv->wq = alloc_ordered_workqueue("omapdrm", 0); - spin_lock_init(&priv->list_lock); + mutex_init(&priv->list_lock); INIT_LIST_HEAD(&priv->obj_list); /* Allocate and initialize the DRM device. */ diff --git a/drivers/gpu/drm/omapdrm/omap_drv.h b/drivers/gpu/drm/omapdrm/omap_drv.h index 6eaee4df4559..f27c8e216adf 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.h +++ b/drivers/gpu/drm/omapdrm/omap_drv.h @@ -71,7 +71,7 @@ struct omap_drm_private { struct workqueue_struct *wq; /* lock for obj_list below */ - spinlock_t list_lock; + struct mutex list_lock; /* list of GEM objects: */ struct list_head obj_list; diff --git a/drivers/gpu/drm/omapdrm/omap_fbdev.c b/drivers/gpu/drm/omapdrm/omap_fbdev.c index 0f66c74a54b0..d958cc813a94 100644 --- a/drivers/gpu/drm/omapdrm/omap_fbdev.c +++ b/drivers/gpu/drm/omapdrm/omap_fbdev.c @@ -170,13 +170,11 @@ static int omap_fbdev_create(struct drm_fb_helper *helper, goto fail; } - mutex_lock(&dev->struct_mutex); - fbi = drm_fb_helper_alloc_fbi(helper); if (IS_ERR(fbi)) { dev_err(dev->dev, "failed to allocate fb info\n"); ret = PTR_ERR(fbi); - goto fail_unlock; + goto fail; } DBG("fbi=%p, dev=%p", fbi, dev); @@ -212,12 +210,8 @@ static int omap_fbdev_create(struct drm_fb_helper *helper, DBG("par=%p, %dx%d", fbi->par, fbi->var.xres, fbi->var.yres); DBG("allocated %dx%d fb", fbdev->fb->width, fbdev->fb->height); - mutex_unlock(&dev->struct_mutex); - return 0; -fail_unlock: - mutex_unlock(&dev->struct_mutex); fail: if (ret) { diff --git a/drivers/gpu/drm/omapdrm/omap_gem.c b/drivers/gpu/drm/omapdrm/omap_gem.c index 17a53d207978..4ba5d035c590 100644 --- a/drivers/gpu/drm/omapdrm/omap_gem.c +++ b/drivers/gpu/drm/omapdrm/omap_gem.c @@ -47,6 +47,9 @@ struct omap_gem_object { /** roll applied when mapping to DMM */ u32 roll; + /** protects dma_addr_cnt, block, pages, dma_addrs and vaddr */ + struct mutex lock; + /** * dma_addr contains the buffer DMA address. It is valid for * @@ -137,14 +140,12 @@ struct omap_drm_usergart { */ /** get mmap offset */ -static u64 mmap_offset(struct drm_gem_object *obj) +u64 omap_gem_mmap_offset(struct drm_gem_object *obj) { struct drm_device *dev = obj->dev; int ret; size_t size; - WARN_ON(!mutex_is_locked(&dev->struct_mutex)); - /* Make it mmapable */ size = omap_gem_mmap_size(obj); ret = drm_gem_create_mmap_offset_size(obj, size); @@ -156,7 +157,7 @@ static u64 mmap_offset(struct drm_gem_object *obj) return drm_vma_node_offset_addr(&obj->vma_node); } -static bool is_contiguous(struct omap_gem_object *omap_obj) +static bool omap_gem_is_contiguous(struct omap_gem_object *omap_obj) { if (omap_obj->flags & OMAP_BO_MEM_DMA_API) return true; @@ -171,14 +172,14 @@ static bool is_contiguous(struct omap_gem_object *omap_obj) * Eviction */ -static void evict_entry(struct drm_gem_object *obj, +static void omap_gem_evict_entry(struct drm_gem_object *obj, enum tiler_fmt fmt, struct omap_drm_usergart_entry *entry) { struct omap_gem_object *omap_obj = to_omap_bo(obj); struct omap_drm_private *priv = obj->dev->dev_private; int n = priv->usergart[fmt].height; size_t size = PAGE_SIZE * n; - loff_t off = mmap_offset(obj) + + loff_t off = omap_gem_mmap_offset(obj) + (entry->obj_pgoff << PAGE_SHIFT); const int m = DIV_ROUND_UP(omap_obj->width << fmt, PAGE_SIZE); @@ -199,7 +200,7 @@ static void evict_entry(struct drm_gem_object *obj, } /* Evict a buffer from usergart, if it is mapped there */ -static void evict(struct drm_gem_object *obj) +static void omap_gem_evict(struct drm_gem_object *obj) { struct omap_gem_object *omap_obj = to_omap_bo(obj); struct omap_drm_private *priv = obj->dev->dev_private; @@ -213,7 +214,7 @@ static void evict(struct drm_gem_object *obj) &priv->usergart[fmt].entry[i]; if (entry->obj == obj) - evict_entry(obj, fmt, entry); + omap_gem_evict_entry(obj, fmt, entry); } } } @@ -222,7 +223,10 @@ static void evict(struct drm_gem_object *obj) * Page Management */ -/** ensure backing pages are allocated */ +/* + * Ensure backing pages are allocated. Must be called with the omap_obj.lock + * held. + */ static int omap_gem_attach_pages(struct drm_gem_object *obj) { struct drm_device *dev = obj->dev; @@ -232,7 +236,14 @@ static int omap_gem_attach_pages(struct drm_gem_object *obj) int i, ret; dma_addr_t *addrs; - WARN_ON(omap_obj->pages); + lockdep_assert_held(&omap_obj->lock); + + /* + * If not using shmem (in which case backing pages don't need to be + * allocated) or if pages are already allocated we're done. + */ + if (!(omap_obj->flags & OMAP_BO_MEM_SHMEM) || omap_obj->pages) + return 0; pages = drm_gem_get_pages(obj); if (IS_ERR(pages)) { @@ -288,35 +299,15 @@ free_pages: return ret; } -/* acquire pages when needed (for example, for DMA where physically - * contiguous buffer is not required - */ -static int get_pages(struct drm_gem_object *obj, struct page ***pages) -{ - struct omap_gem_object *omap_obj = to_omap_bo(obj); - int ret = 0; - - if ((omap_obj->flags & OMAP_BO_MEM_SHMEM) && !omap_obj->pages) { - ret = omap_gem_attach_pages(obj); - if (ret) { - dev_err(obj->dev->dev, "could not attach pages\n"); - return ret; - } - } - - /* TODO: even phys-contig.. we should have a list of pages? */ - *pages = omap_obj->pages; - - return 0; -} - -/** release backing pages */ +/* Release backing pages. Must be called with the omap_obj.lock held. */ static void omap_gem_detach_pages(struct drm_gem_object *obj) { struct omap_gem_object *omap_obj = to_omap_bo(obj); unsigned int npages = obj->size >> PAGE_SHIFT; unsigned int i; + lockdep_assert_held(&omap_obj->lock); + for (i = 0; i < npages; i++) { if (omap_obj->dma_addrs[i]) dma_unmap_page(obj->dev->dev, omap_obj->dma_addrs[i], @@ -336,16 +327,6 @@ u32 omap_gem_flags(struct drm_gem_object *obj) return to_omap_bo(obj)->flags; } -u64 omap_gem_mmap_offset(struct drm_gem_object *obj) -{ - u64 offset; - - mutex_lock(&obj->dev->struct_mutex); - offset = mmap_offset(obj); - mutex_unlock(&obj->dev->struct_mutex); - return offset; -} - /** get mmap size */ size_t omap_gem_mmap_size(struct drm_gem_object *obj) { @@ -371,7 +352,7 @@ size_t omap_gem_mmap_size(struct drm_gem_object *obj) */ /* Normal handling for the case of faulting in non-tiled buffers */ -static int fault_1d(struct drm_gem_object *obj, +static vm_fault_t omap_gem_fault_1d(struct drm_gem_object *obj, struct vm_area_struct *vma, struct vm_fault *vmf) { struct omap_gem_object *omap_obj = to_omap_bo(obj); @@ -385,18 +366,19 @@ static int fault_1d(struct drm_gem_object *obj, omap_gem_cpu_sync_page(obj, pgoff); pfn = page_to_pfn(omap_obj->pages[pgoff]); } else { - BUG_ON(!is_contiguous(omap_obj)); + BUG_ON(!omap_gem_is_contiguous(omap_obj)); pfn = (omap_obj->dma_addr >> PAGE_SHIFT) + pgoff; } VERB("Inserting %p pfn %lx, pa %lx", (void *)vmf->address, pfn, pfn << PAGE_SHIFT); - return vm_insert_mixed(vma, vmf->address, __pfn_to_pfn_t(pfn, PFN_DEV)); + return vmf_insert_mixed(vma, vmf->address, + __pfn_to_pfn_t(pfn, PFN_DEV)); } /* Special handling for the case of faulting in 2d tiled buffers */ -static int fault_2d(struct drm_gem_object *obj, +static vm_fault_t omap_gem_fault_2d(struct drm_gem_object *obj, struct vm_area_struct *vma, struct vm_fault *vmf) { struct omap_gem_object *omap_obj = to_omap_bo(obj); @@ -407,7 +389,8 @@ static int fault_2d(struct drm_gem_object *obj, unsigned long pfn; pgoff_t pgoff, base_pgoff; unsigned long vaddr; - int i, ret, slots; + int i, err, slots; + vm_fault_t ret = VM_FAULT_NOPAGE; /* * Note the height of the slot is also equal to the number of pages @@ -443,7 +426,7 @@ static int fault_2d(struct drm_gem_object *obj, /* evict previous buffer using this usergart entry, if any: */ if (entry->obj) - evict_entry(entry->obj, fmt, entry); + omap_gem_evict_entry(entry->obj, fmt, entry); entry->obj = obj; entry->obj_pgoff = base_pgoff; @@ -473,9 +456,10 @@ static int fault_2d(struct drm_gem_object *obj, memset(pages + slots, 0, sizeof(struct page *) * (n - slots)); - ret = tiler_pin(entry->block, pages, ARRAY_SIZE(pages), 0, true); - if (ret) { - dev_err(obj->dev->dev, "failed to pin: %d\n", ret); + err = tiler_pin(entry->block, pages, ARRAY_SIZE(pages), 0, true); + if (err) { + ret = vmf_error(err); + dev_err(obj->dev->dev, "failed to pin: %d\n", err); return ret; } @@ -485,7 +469,10 @@ static int fault_2d(struct drm_gem_object *obj, pfn, pfn << PAGE_SHIFT); for (i = n; i > 0; i--) { - vm_insert_mixed(vma, vaddr, __pfn_to_pfn_t(pfn, PFN_DEV)); + ret = vmf_insert_mixed(vma, + vaddr, __pfn_to_pfn_t(pfn, PFN_DEV)); + if (ret & VM_FAULT_ERROR) + break; pfn += priv->usergart[fmt].stride_pfn; vaddr += PAGE_SIZE * m; } @@ -494,7 +481,7 @@ static int fault_2d(struct drm_gem_object *obj, priv->usergart[fmt].last = (priv->usergart[fmt].last + 1) % NUM_USERGART_ENTRIES; - return 0; + return ret; } /** @@ -509,24 +496,25 @@ static int fault_2d(struct drm_gem_object *obj, * vma->vm_private_data points to the GEM object that is backing this * mapping. */ -int omap_gem_fault(struct vm_fault *vmf) +vm_fault_t omap_gem_fault(struct vm_fault *vmf) { struct vm_area_struct *vma = vmf->vma; struct drm_gem_object *obj = vma->vm_private_data; struct omap_gem_object *omap_obj = to_omap_bo(obj); - struct drm_device *dev = obj->dev; - struct page **pages; - int ret; + int err; + vm_fault_t ret; /* Make sure we don't parallel update on a fault, nor move or remove * something from beneath our feet */ - mutex_lock(&dev->struct_mutex); + mutex_lock(&omap_obj->lock); /* if a shmem backed object, make sure we have pages attached now */ - ret = get_pages(obj, &pages); - if (ret) + err = omap_gem_attach_pages(obj); + if (err) { + ret = vmf_error(err); goto fail; + } /* where should we do corresponding put_pages().. we are mapping * the original page, rather than thru a GART, so we can't rely @@ -535,28 +523,14 @@ int omap_gem_fault(struct vm_fault *vmf) */ if (omap_obj->flags & OMAP_BO_TILED) - ret = fault_2d(obj, vma, vmf); + ret = omap_gem_fault_2d(obj, vma, vmf); else - ret = fault_1d(obj, vma, vmf); + ret = omap_gem_fault_1d(obj, vma, vmf); fail: - mutex_unlock(&dev->struct_mutex); - switch (ret) { - case 0: - case -ERESTARTSYS: - case -EINTR: - case -EBUSY: - /* - * EBUSY is ok: this just means that another thread - * already did the job. - */ - return VM_FAULT_NOPAGE; - case -ENOMEM: - return VM_FAULT_OOM; - default: - return VM_FAULT_SIGBUS; - } + mutex_unlock(&omap_obj->lock); + return ret; } /** We override mainly to fix up some of the vm mapping flags.. */ @@ -689,21 +663,22 @@ int omap_gem_roll(struct drm_gem_object *obj, u32 roll) omap_obj->roll = roll; - mutex_lock(&obj->dev->struct_mutex); + mutex_lock(&omap_obj->lock); /* if we aren't mapped yet, we don't need to do anything */ if (omap_obj->block) { - struct page **pages; - ret = get_pages(obj, &pages); + ret = omap_gem_attach_pages(obj); if (ret) goto fail; - ret = tiler_pin(omap_obj->block, pages, npages, roll, true); + + ret = tiler_pin(omap_obj->block, omap_obj->pages, npages, + roll, true); if (ret) dev_err(obj->dev->dev, "could not repin: %d\n", ret); } fail: - mutex_unlock(&obj->dev->struct_mutex); + mutex_unlock(&omap_obj->lock); return ret; } @@ -722,7 +697,7 @@ fail: * the omap_obj->dma_addrs[i] is set to the DMA address, and the page is * unmapped from the CPU. */ -static inline bool is_cached_coherent(struct drm_gem_object *obj) +static inline bool omap_gem_is_cached_coherent(struct drm_gem_object *obj) { struct omap_gem_object *omap_obj = to_omap_bo(obj); @@ -738,7 +713,7 @@ void omap_gem_cpu_sync_page(struct drm_gem_object *obj, int pgoff) struct drm_device *dev = obj->dev; struct omap_gem_object *omap_obj = to_omap_bo(obj); - if (is_cached_coherent(obj)) + if (omap_gem_is_cached_coherent(obj)) return; if (omap_obj->dma_addrs[pgoff]) { @@ -758,7 +733,7 @@ void omap_gem_dma_sync_buffer(struct drm_gem_object *obj, struct page **pages = omap_obj->pages; bool dirty = false; - if (is_cached_coherent(obj)) + if (omap_gem_is_cached_coherent(obj)) return; for (i = 0; i < npages; i++) { @@ -804,18 +779,17 @@ int omap_gem_pin(struct drm_gem_object *obj, dma_addr_t *dma_addr) struct omap_gem_object *omap_obj = to_omap_bo(obj); int ret = 0; - mutex_lock(&obj->dev->struct_mutex); + mutex_lock(&omap_obj->lock); - if (!is_contiguous(omap_obj) && priv->has_dmm) { + if (!omap_gem_is_contiguous(omap_obj) && priv->has_dmm) { if (omap_obj->dma_addr_cnt == 0) { - struct page **pages; u32 npages = obj->size >> PAGE_SHIFT; enum tiler_fmt fmt = gem2fmt(omap_obj->flags); struct tiler_block *block; BUG_ON(omap_obj->block); - ret = get_pages(obj, &pages); + ret = omap_gem_attach_pages(obj); if (ret) goto fail; @@ -835,7 +809,7 @@ int omap_gem_pin(struct drm_gem_object *obj, dma_addr_t *dma_addr) } /* TODO: enable async refill.. */ - ret = tiler_pin(block, pages, npages, + ret = tiler_pin(block, omap_obj->pages, npages, omap_obj->roll, true); if (ret) { tiler_release(block); @@ -853,7 +827,7 @@ int omap_gem_pin(struct drm_gem_object *obj, dma_addr_t *dma_addr) omap_obj->dma_addr_cnt++; *dma_addr = omap_obj->dma_addr; - } else if (is_contiguous(omap_obj)) { + } else if (omap_gem_is_contiguous(omap_obj)) { *dma_addr = omap_obj->dma_addr; } else { ret = -EINVAL; @@ -861,7 +835,7 @@ int omap_gem_pin(struct drm_gem_object *obj, dma_addr_t *dma_addr) } fail: - mutex_unlock(&obj->dev->struct_mutex); + mutex_unlock(&omap_obj->lock); return ret; } @@ -879,7 +853,8 @@ void omap_gem_unpin(struct drm_gem_object *obj) struct omap_gem_object *omap_obj = to_omap_bo(obj); int ret; - mutex_lock(&obj->dev->struct_mutex); + mutex_lock(&omap_obj->lock); + if (omap_obj->dma_addr_cnt > 0) { omap_obj->dma_addr_cnt--; if (omap_obj->dma_addr_cnt == 0) { @@ -898,7 +873,7 @@ void omap_gem_unpin(struct drm_gem_object *obj) } } - mutex_unlock(&obj->dev->struct_mutex); + mutex_unlock(&omap_obj->lock); } /* Get rotated scanout address (only valid if already pinned), at the @@ -911,13 +886,16 @@ int omap_gem_rotated_dma_addr(struct drm_gem_object *obj, u32 orient, struct omap_gem_object *omap_obj = to_omap_bo(obj); int ret = -EINVAL; - mutex_lock(&obj->dev->struct_mutex); + mutex_lock(&omap_obj->lock); + if ((omap_obj->dma_addr_cnt > 0) && omap_obj->block && (omap_obj->flags & OMAP_BO_TILED)) { *dma_addr = tiler_tsptr(omap_obj->block, orient, x, y); ret = 0; } - mutex_unlock(&obj->dev->struct_mutex); + + mutex_unlock(&omap_obj->lock); + return ret; } @@ -944,17 +922,27 @@ int omap_gem_tiled_stride(struct drm_gem_object *obj, u32 orient) int omap_gem_get_pages(struct drm_gem_object *obj, struct page ***pages, bool remap) { - int ret; - if (!remap) { - struct omap_gem_object *omap_obj = to_omap_bo(obj); - if (!omap_obj->pages) - return -ENOMEM; - *pages = omap_obj->pages; - return 0; + struct omap_gem_object *omap_obj = to_omap_bo(obj); + int ret = 0; + + mutex_lock(&omap_obj->lock); + + if (remap) { + ret = omap_gem_attach_pages(obj); + if (ret) + goto unlock; } - mutex_lock(&obj->dev->struct_mutex); - ret = get_pages(obj, pages); - mutex_unlock(&obj->dev->struct_mutex); + + if (!omap_obj->pages) { + ret = -ENOMEM; + goto unlock; + } + + *pages = omap_obj->pages; + +unlock: + mutex_unlock(&omap_obj->lock); + return ret; } @@ -969,23 +957,34 @@ int omap_gem_put_pages(struct drm_gem_object *obj) } #ifdef CONFIG_DRM_FBDEV_EMULATION -/* Get kernel virtual address for CPU access.. this more or less only - * exists for omap_fbdev. This should be called with struct_mutex - * held. +/* + * Get kernel virtual address for CPU access.. this more or less only + * exists for omap_fbdev. */ void *omap_gem_vaddr(struct drm_gem_object *obj) { struct omap_gem_object *omap_obj = to_omap_bo(obj); - WARN_ON(!mutex_is_locked(&obj->dev->struct_mutex)); + void *vaddr; + int ret; + + mutex_lock(&omap_obj->lock); + if (!omap_obj->vaddr) { - struct page **pages; - int ret = get_pages(obj, &pages); - if (ret) - return ERR_PTR(ret); - omap_obj->vaddr = vmap(pages, obj->size >> PAGE_SHIFT, + ret = omap_gem_attach_pages(obj); + if (ret) { + vaddr = ERR_PTR(ret); + goto unlock; + } + + omap_obj->vaddr = vmap(omap_obj->pages, obj->size >> PAGE_SHIFT, VM_MAP, pgprot_writecombine(PAGE_KERNEL)); } - return omap_obj->vaddr; + + vaddr = omap_obj->vaddr; + +unlock: + mutex_unlock(&omap_obj->lock); + return vaddr; } #endif @@ -1001,6 +1000,7 @@ int omap_gem_resume(struct drm_device *dev) struct omap_gem_object *omap_obj; int ret = 0; + mutex_lock(&priv->list_lock); list_for_each_entry(omap_obj, &priv->obj_list, mm_list) { if (omap_obj->block) { struct drm_gem_object *obj = &omap_obj->base; @@ -1012,12 +1012,14 @@ int omap_gem_resume(struct drm_device *dev) omap_obj->roll, true); if (ret) { dev_err(dev->dev, "could not repin: %d\n", ret); - return ret; + goto done; } } } - return 0; +done: + mutex_unlock(&priv->list_lock); + return ret; } #endif @@ -1033,6 +1035,8 @@ void omap_gem_describe(struct drm_gem_object *obj, struct seq_file *m) off = drm_vma_node_start(&obj->vma_node); + mutex_lock(&omap_obj->lock); + seq_printf(m, "%08x: %2d (%2d) %08llx %pad (%2d) %p %4d", omap_obj->flags, obj->name, kref_read(&obj->refcount), off, &omap_obj->dma_addr, omap_obj->dma_addr_cnt, @@ -1050,6 +1054,8 @@ void omap_gem_describe(struct drm_gem_object *obj, struct seq_file *m) seq_printf(m, " %zu", obj->size); } + mutex_unlock(&omap_obj->lock); + seq_printf(m, "\n"); } @@ -1081,17 +1087,21 @@ void omap_gem_free_object(struct drm_gem_object *obj) struct omap_drm_private *priv = dev->dev_private; struct omap_gem_object *omap_obj = to_omap_bo(obj); - evict(obj); - - WARN_ON(!mutex_is_locked(&dev->struct_mutex)); + omap_gem_evict(obj); - spin_lock(&priv->list_lock); + mutex_lock(&priv->list_lock); list_del(&omap_obj->mm_list); - spin_unlock(&priv->list_lock); + mutex_unlock(&priv->list_lock); - /* this means the object is still pinned.. which really should - * not happen. I think.. + /* + * We own the sole reference to the object at this point, but to keep + * lockdep happy, we must still take the omap_obj_lock to call + * omap_gem_detach_pages(). This should hardly make any difference as + * there can't be any lock contention. */ + mutex_lock(&omap_obj->lock); + + /* The object should not be pinned. */ WARN_ON(omap_obj->dma_addr_cnt > 0); if (omap_obj->pages) { @@ -1110,8 +1120,12 @@ void omap_gem_free_object(struct drm_gem_object *obj) drm_prime_gem_destroy(obj, omap_obj->sgt); } + mutex_unlock(&omap_obj->lock); + drm_gem_object_release(obj); + mutex_destroy(&omap_obj->lock); + kfree(omap_obj); } @@ -1167,6 +1181,7 @@ struct drm_gem_object *omap_gem_new(struct drm_device *dev, obj = &omap_obj->base; omap_obj->flags = flags; + mutex_init(&omap_obj->lock); if (flags & OMAP_BO_TILED) { /* @@ -1206,9 +1221,9 @@ struct drm_gem_object *omap_gem_new(struct drm_device *dev, goto err_release; } - spin_lock(&priv->list_lock); + mutex_lock(&priv->list_lock); list_add(&omap_obj->mm_list, &priv->obj_list); - spin_unlock(&priv->list_lock); + mutex_unlock(&priv->list_lock); return obj; @@ -1231,16 +1246,15 @@ struct drm_gem_object *omap_gem_new_dmabuf(struct drm_device *dev, size_t size, if (sgt->orig_nents != 1 && !priv->has_dmm) return ERR_PTR(-EINVAL); - mutex_lock(&dev->struct_mutex); - gsize.bytes = PAGE_ALIGN(size); obj = omap_gem_new(dev, gsize, OMAP_BO_MEM_DMABUF | OMAP_BO_WC); - if (!obj) { - obj = ERR_PTR(-ENOMEM); - goto done; - } + if (!obj) + return ERR_PTR(-ENOMEM); omap_obj = to_omap_bo(obj); + + mutex_lock(&omap_obj->lock); + omap_obj->sgt = sgt; if (sgt->orig_nents == 1) { @@ -1276,7 +1290,7 @@ struct drm_gem_object *omap_gem_new_dmabuf(struct drm_device *dev, size_t size, } done: - mutex_unlock(&dev->struct_mutex); + mutex_unlock(&omap_obj->lock); return obj; } diff --git a/drivers/gpu/drm/omapdrm/omap_gem.h b/drivers/gpu/drm/omapdrm/omap_gem.h index a78bde05193a..c1c45fbde155 100644 --- a/drivers/gpu/drm/omapdrm/omap_gem.h +++ b/drivers/gpu/drm/omapdrm/omap_gem.h @@ -21,6 +21,7 @@ #define __OMAPDRM_GEM_H__ #include <linux/types.h> +#include <linux/mm_types.h> enum dma_data_direction; @@ -80,7 +81,7 @@ struct dma_buf *omap_gem_prime_export(struct drm_device *dev, struct drm_gem_object *omap_gem_prime_import(struct drm_device *dev, struct dma_buf *buffer); -int omap_gem_fault(struct vm_fault *vmf); +vm_fault_t omap_gem_fault(struct vm_fault *vmf); int omap_gem_roll(struct drm_gem_object *obj, u32 roll); void omap_gem_cpu_sync_page(struct drm_gem_object *obj, int pgoff); void omap_gem_dma_sync_buffer(struct drm_gem_object *obj, |