diff options
49 files changed, 407 insertions, 283 deletions
diff --git a/Documentation/gpu/drm-internals.rst b/Documentation/gpu/drm-internals.rst index 4f7176576feb..490d655cda20 100644 --- a/Documentation/gpu/drm-internals.rst +++ b/Documentation/gpu/drm-internals.rst @@ -280,8 +280,8 @@ private data in the open method should free it here. The lastclose method should restore CRTC and plane properties to default value, so that a subsequent open of the device will not inherit state from the previous user. It can also be used to execute delayed power -switching state changes, e.g. in conjunction with the vga_switcheroo -infrastructure (see ?). Beyond that KMS drivers should not do any +switching state changes, e.g. in conjunction with the :ref:`vga_switcheroo` +infrastructure. Beyond that KMS drivers should not do any further cleanup. Only legacy UMS drivers might need to clean up device state so that the vga console or an independent fbdev driver could take over. diff --git a/Documentation/gpu/vga-switcheroo.rst b/Documentation/gpu/vga-switcheroo.rst index 327d930a2229..cbbdb994f1dd 100644 --- a/Documentation/gpu/vga-switcheroo.rst +++ b/Documentation/gpu/vga-switcheroo.rst @@ -1,3 +1,5 @@ +.. _vga_switcheroo: + ============== VGA Switcheroo ============== @@ -94,9 +96,3 @@ Public functions .. kernel-doc:: include/linux/apple-gmux.h :internal: - -.. WARNING: DOCPROC directive not supported: !Cdrivers/gpu/vga/vga_switcheroo.c - -.. WARNING: DOCPROC directive not supported: !Cinclude/linux/vga_switcheroo.h - -.. WARNING: DOCPROC directive not supported: !Cdrivers/platform/x86/apple-gmux.c diff --git a/MAINTAINERS b/MAINTAINERS index 0c22fe584283..5351c4be3aa2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3779,6 +3779,17 @@ F: include/linux/*fence.h F: Documentation/dma-buf-sharing.txt T: git git://git.linaro.org/people/sumitsemwal/linux-dma-buf.git +SYNC FILE FRAMEWORK +M: Sumit Semwal <sumit.semwal@linaro.org> +R: Gustavo Padovan <gustavo@padovan.org> +S: Maintained +L: linux-media@vger.kernel.org +L: dri-devel@lists.freedesktop.org +F: drivers/dma-buf/sync_file.c +F: include/linux/sync_file.h +F: Documentation/sync_file.txt +T: git git://git.linaro.org/people/sumitsemwal/linux-dma-buf.git + DMA GENERIC OFFLOAD ENGINE SUBSYSTEM M: Vinod Koul <vinod.koul@intel.com> L: dmaengine@vger.kernel.org diff --git a/drivers/dma-buf/Kconfig b/drivers/dma-buf/Kconfig index 9824bc4addf8..25bcfa0b474f 100644 --- a/drivers/dma-buf/Kconfig +++ b/drivers/dma-buf/Kconfig @@ -1,11 +1,20 @@ menu "DMABUF options" config SYNC_FILE - bool "sync_file support for fences" + bool "Explicit Synchronization Framework" default n select ANON_INODES select DMA_SHARED_BUFFER ---help--- - This option enables the fence framework synchronization to export - sync_files to userspace that can represent one or more fences. + The Sync File Framework adds explicit syncronization via + userspace. It enables send/receive 'struct fence' objects to/from + userspace via Sync File fds for synchronization between drivers via + userspace components. It has been ported from Android. + + The first and main user for this is graphics in which a fence is + associated with a buffer. When a job is submitted to the GPU a fence + is attached to the buffer and is transferred via userspace, using Sync + Files fds, to the DRM driver for example. More details at + Documentation/sync_file.txt. + endmenu diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 9c9f28c1ce84..614fb026436d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -1712,6 +1712,7 @@ void amdgpu_device_fini(struct amdgpu_device *adev) amdgpu_bo_evict_vram(adev); amdgpu_ib_pool_fini(adev); amdgpu_fence_driver_fini(adev); + drm_crtc_force_disable_all(adev->ddev); amdgpu_fbdev_fini(adev); r = amdgpu_fini(adev); kfree(adev->ip_block_status); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c index b464aaa1da3e..a8efbb54423f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c @@ -60,7 +60,10 @@ int amdgpu_driver_unload_kms(struct drm_device *dev) if (adev->rmmio == NULL) goto done_free; - pm_runtime_get_sync(dev->dev); + if (amdgpu_device_is_px(dev)) { + pm_runtime_get_sync(dev->dev); + pm_runtime_forbid(dev->dev); + } amdgpu_amdkfd_device_fini(adev); @@ -135,9 +138,12 @@ int amdgpu_driver_load_kms(struct drm_device *dev, unsigned long flags) } out: - if (r) + if (r) { + /* balance pm_runtime_get_sync in amdgpu_driver_unload_kms */ + if (adev->rmmio && amdgpu_device_is_px(dev)) + pm_runtime_put_noidle(dev->dev); amdgpu_driver_unload_kms(dev); - + } return r; } diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index 34405e4a5d36..2f58e9e2a59c 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -410,7 +410,7 @@ static void armada_drm_crtc_irq(struct armada_crtc *dcrtc, u32 stat) DRM_ERROR("graphics underflow on crtc %u\n", dcrtc->num); if (stat & VSYNC_IRQ) - drm_handle_vblank(dcrtc->crtc.dev, dcrtc->num); + drm_crtc_handle_vblank(&dcrtc->crtc); spin_lock(&dcrtc->irq_lock); ovl_plane = dcrtc->plane; diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c index 613f6c99b76a..a978381ef95b 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c @@ -383,7 +383,7 @@ static void atmel_hlcdc_crtc_finish_page_flip(struct atmel_hlcdc_crtc *crtc) void atmel_hlcdc_crtc_irq(struct drm_crtc *c) { - drm_handle_vblank(c->dev, 0); + drm_crtc_handle_vblank(c); atmel_hlcdc_crtc_finish_page_flip(drm_crtc_to_atmel_hlcdc_crtc(c)); } diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 3cee084e9d28..9359be4a0ca9 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -1589,6 +1589,72 @@ void drm_atomic_clean_old_fb(struct drm_device *dev, } EXPORT_SYMBOL(drm_atomic_clean_old_fb); +int drm_atomic_remove_fb(struct drm_framebuffer *fb) +{ + struct drm_modeset_acquire_ctx ctx; + struct drm_device *dev = fb->dev; + struct drm_atomic_state *state; + struct drm_plane *plane; + int ret = 0; + unsigned plane_mask; + + state = drm_atomic_state_alloc(dev); + if (!state) + return -ENOMEM; + + drm_modeset_acquire_init(&ctx, 0); + state->acquire_ctx = &ctx; + +retry: + plane_mask = 0; + ret = drm_modeset_lock_all_ctx(dev, &ctx); + if (ret) + goto unlock; + + drm_for_each_plane(plane, dev) { + struct drm_plane_state *plane_state; + + if (plane->state->fb != fb) + continue; + + plane_state = drm_atomic_get_plane_state(state, plane); + if (IS_ERR(plane_state)) { + ret = PTR_ERR(plane_state); + goto unlock; + } + + drm_atomic_set_fb_for_plane(plane_state, NULL); + ret = drm_atomic_set_crtc_for_plane(plane_state, NULL); + if (ret) + goto unlock; + + plane_mask |= BIT(drm_plane_index(plane)); + + plane->old_fb = plane->fb; + plane->fb = NULL; + } + + if (plane_mask) + ret = drm_atomic_commit(state); + +unlock: + if (plane_mask) + drm_atomic_clean_old_fb(dev, plane_mask, ret); + + if (ret == -EDEADLK) { + drm_modeset_backoff(&ctx); + goto retry; + } + + if (ret || !plane_mask) + drm_atomic_state_free(state); + + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); + + return ret; +} + int drm_mode_atomic_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { diff --git a/drivers/gpu/drm/drm_cache.c b/drivers/gpu/drm/drm_cache.c index 059f7c39c582..a7916e5f8864 100644 --- a/drivers/gpu/drm/drm_cache.c +++ b/drivers/gpu/drm/drm_cache.c @@ -136,6 +136,7 @@ drm_clflush_virt_range(void *addr, unsigned long length) mb(); for (; addr < end; addr += size) clflushopt(addr); + clflushopt(end - 1); /* force serialisation */ mb(); return; } diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index fd93e9c79d28..9d3f80efc9cc 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -396,6 +396,51 @@ void drm_mode_object_reference(struct drm_mode_object *obj) } EXPORT_SYMBOL(drm_mode_object_reference); +/** + * drm_crtc_force_disable - Forcibly turn off a CRTC + * @crtc: CRTC to turn off + * + * Returns: + * Zero on success, error code on failure. + */ +int drm_crtc_force_disable(struct drm_crtc *crtc) +{ + struct drm_mode_set set = { + .crtc = crtc, + }; + + return drm_mode_set_config_internal(&set); +} +EXPORT_SYMBOL(drm_crtc_force_disable); + +/** + * drm_crtc_force_disable_all - Forcibly turn off all enabled CRTCs + * @dev: DRM device whose CRTCs to turn off + * + * Drivers may want to call this on unload to ensure that all displays are + * unlit and the GPU is in a consistent, low power state. Takes modeset locks. + * + * Returns: + * Zero on success, error code on failure. + */ +int drm_crtc_force_disable_all(struct drm_device *dev) +{ + struct drm_crtc *crtc; + int ret = 0; + + drm_modeset_lock_all(dev); + drm_for_each_crtc(crtc, dev) + if (crtc->enabled) { + ret = drm_crtc_force_disable(crtc); + if (ret) + goto out; + } +out: + drm_modeset_unlock_all(dev); + return ret; +} +EXPORT_SYMBOL(drm_crtc_force_disable_all); + static void drm_framebuffer_free(struct kref *kref) { struct drm_framebuffer *fb = @@ -544,8 +589,6 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb) struct drm_device *dev; struct drm_crtc *crtc; struct drm_plane *plane; - struct drm_mode_set set; - int ret; if (!fb) return; @@ -570,16 +613,17 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb) * in this manner. */ if (drm_framebuffer_read_refcount(fb) > 1) { + if (dev->mode_config.funcs->atomic_commit) { + drm_atomic_remove_fb(fb); + goto out; + } + drm_modeset_lock_all(dev); /* remove from any CRTC */ drm_for_each_crtc(crtc, dev) { if (crtc->primary->fb == fb) { /* should turn off the crtc */ - memset(&set, 0, sizeof(struct drm_mode_set)); - set.crtc = crtc; - set.fb = NULL; - ret = drm_mode_set_config_internal(&set); - if (ret) + if (drm_crtc_force_disable(crtc)) DRM_ERROR("failed to reset crtc %p when fb was deleted\n", crtc); } } @@ -591,6 +635,7 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb) drm_modeset_unlock_all(dev); } +out: drm_framebuffer_unreference(fb); } EXPORT_SYMBOL(drm_framebuffer_remove); @@ -1068,23 +1113,7 @@ void drm_connector_unregister(struct drm_connector *connector) } EXPORT_SYMBOL(drm_connector_unregister); -/** - * drm_connector_register_all - register all connectors - * @dev: drm device - * - * This function registers all connectors in sysfs and other places so that - * userspace can start to access them. drm_connector_register_all() is called - * automatically from drm_dev_register() to complete the device registration, - * if they don't call drm_connector_register() on each connector individually. - * - * When a device is unplugged and should be removed from userspace access, - * call drm_connector_unregister_all(), which is the inverse of this - * function. - * - * Returns: - * Zero on success, error code on failure. - */ -int drm_connector_register_all(struct drm_device *dev) +static int drm_connector_register_all(struct drm_device *dev) { struct drm_connector *connector; int ret; @@ -1106,7 +1135,6 @@ err: drm_connector_unregister_all(dev); return ret; } -EXPORT_SYMBOL(drm_connector_register_all); /** * drm_connector_unregister_all - unregister connector userspace interfaces diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h index 47a500b90fd7..b248e2238a05 100644 --- a/drivers/gpu/drm/drm_crtc_internal.h +++ b/drivers/gpu/drm/drm_crtc_internal.h @@ -125,6 +125,7 @@ int drm_atomic_get_property(struct drm_mode_object *obj, struct drm_property *property, uint64_t *val); int drm_mode_atomic_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); +int drm_atomic_remove_fb(struct drm_framebuffer *fb); int drm_modeset_register_all(struct drm_device *dev); void drm_modeset_unregister_all(struct drm_device *dev); diff --git a/drivers/gpu/drm/drm_dp_aux_dev.c b/drivers/gpu/drm/drm_dp_aux_dev.c index 3334baacf43d..734f86a345f6 100644 --- a/drivers/gpu/drm/drm_dp_aux_dev.c +++ b/drivers/gpu/drm/drm_dp_aux_dev.c @@ -355,8 +355,7 @@ int drm_dp_aux_dev_init(void) drm_dp_aux_dev_class = class_create(THIS_MODULE, "drm_dp_aux_dev"); if (IS_ERR(drm_dp_aux_dev_class)) { - res = PTR_ERR(drm_dp_aux_dev_class); - goto out; + return PTR_ERR(drm_dp_aux_dev_class); } drm_dp_aux_dev_class->dev_groups = drm_dp_aux_groups; diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index aead9ffcbe29..be27ed36f56e 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -362,9 +362,7 @@ EXPORT_SYMBOL(drm_put_dev); void drm_unplug_dev(struct drm_device *dev) { /* for a USB device */ - drm_minor_unregister(dev, DRM_MINOR_LEGACY); - drm_minor_unregister(dev, DRM_MINOR_RENDER); - drm_minor_unregister(dev, DRM_MINOR_CONTROL); + drm_dev_unregister(dev); mutex_lock(&drm_global_mutex); diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index 1f84ff5f1bf8..33af4a5ddca1 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -648,7 +648,7 @@ long drm_ioctl(struct file *filp, int retcode = -EINVAL; char stack_kdata[128]; char *kdata = NULL; - unsigned int usize, asize, drv_size; + unsigned int in_size, out_size, drv_size, ksize; bool is_driver_ioctl; dev = file_priv->minor->dev; @@ -671,9 +671,12 @@ long drm_ioctl(struct file *filp, } drv_size = _IOC_SIZE(ioctl->cmd); - usize = _IOC_SIZE(cmd); - asize = max(usize, drv_size); - cmd = ioctl->cmd; + out_size = in_size = _IOC_SIZE(cmd); + if ((cmd & ioctl->cmd & IOC_IN) == 0) + in_size = 0; + if ((cmd & ioctl->cmd & IOC_OUT) == 0) + out_size = 0; + ksize = max(max(in_size, out_size), drv_size); DRM_DEBUG("pid=%d, dev=0x%lx, auth=%d, %s\n", task_pid_nr(current), @@ -693,30 +696,24 @@ long drm_ioctl(struct file *filp, if (unlikely(retcode)) goto err_i1; - if (cmd & (IOC_IN | IOC_OUT)) { - if (asize <= sizeof(stack_kdata)) { - kdata = stack_kdata; - } else { - kdata = kmalloc(asize, GFP_KERNEL); - if (!kdata) { - retcode = -ENOMEM; - goto err_i1; - } + if (ksize <= sizeof(stack_kdata)) { + kdata = stack_kdata; + } else { + kdata = kmalloc(ksize, GFP_KERNEL); + if (!kdata) { + retcode = -ENOMEM; + goto err_i1; } - if (asize > usize) - memset(kdata + usize, 0, asize - usize); } - if (cmd & IOC_IN) { - if (copy_from_user(kdata, (void __user *)arg, - usize) != 0) { - retcode = -EFAULT; - goto err_i1; - } - } else if (cmd & IOC_OUT) { - memset(kdata, 0, usize); + if (copy_from_user(kdata, (void __user *)arg, in_size) != 0) { + retcode = -EFAULT; + goto err_i1; } + if (ksize > in_size) + memset(kdata + in_size, 0, ksize - in_size); + /* Enforce sane locking for kms driver ioctls. Core ioctls are * too messy still. */ if ((drm_core_check_feature(dev, DRIVER_MODESET) && is_driver_ioctl) || @@ -728,11 +725,8 @@ long drm_ioctl(struct file *filp, mutex_unlock(&drm_global_mutex); } - if (cmd & IOC_OUT) { - if (copy_to_user((void __user *)arg, kdata, - usize) != 0) - retcode = -EFAULT; - } + if (copy_to_user((void __user *)arg, kdata, out_size) != 0) + retcode = -EFAULT; err_i1: if (!ioctl) @@ -759,7 +753,7 @@ EXPORT_SYMBOL(drm_ioctl); * shouldn't be used by any drivers. * * Returns: - * True if the @nr corresponds to a DRM core ioctl numer, false otherwise. + * True if the @nr corresponds to a DRM core ioctl number, false otherwise. */ bool drm_ioctl_flags(unsigned int nr, unsigned int *flags) { diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 8ca3d2bf2bda..35c86acede38 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -532,7 +532,7 @@ int drm_irq_uninstall(struct drm_device *dev) /* * Wake up any waiters so they don't hang. This is just to paper over - * isssues for UMS drivers which aren't in full control of their + * issues for UMS drivers which aren't in full control of their * vblank/irq handling. KMS drivers must ensure that vblanks are all * disabled when uninstalling the irq handler. */ @@ -594,7 +594,7 @@ int drm_control(struct drm_device *dev, void *data, return 0; if (drm_core_check_feature(dev, DRIVER_MODESET)) return 0; - /* UMS was only ever support on pci devices. */ + /* UMS was only ever supported on pci devices. */ if (WARN_ON(!dev->pdev)) return -EINVAL; @@ -945,8 +945,8 @@ EXPORT_SYMBOL(drm_crtc_vblank_count); * * This is the legacy version of drm_crtc_vblank_count_and_time(). */ -u32 drm_vblank_count_and_time(struct drm_device *dev, unsigned int pipe, - struct timeval *vblanktime) +static u32 drm_vblank_count_and_time(struct drm_device *dev, unsigned int pipe, + struct timeval *vblanktime) { struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; u32 vblank_count; @@ -963,7 +963,6 @@ u32 drm_vblank_count_and_time(struct drm_device *dev, unsigned int pipe, return vblank_count; } -EXPORT_SYMBOL(drm_vblank_count_and_time); /** * drm_crtc_vblank_count_and_time - retrieve "cooked" vblank counter value @@ -975,8 +974,6 @@ EXPORT_SYMBOL(drm_vblank_count_and_time); * vblank events since the system was booted, including lost events due to * modesetting activity. Returns corresponding system timestamp of the time * of the vblank interval that corresponds to the current vblank counter value. - * - * This is the native KMS version of drm_vblank_count_and_time(). */ u32 drm_crtc_vblank_count_and_time(struct drm_crtc *crtc, struct timeval *vblanktime) @@ -1588,12 +1585,6 @@ static int drm_queue_vblank_event(struct drm_device *dev, unsigned int pipe, seq = drm_vblank_count_and_time(dev, pipe, &now); - if ((vblwait->request.type & _DRM_VBLANK_NEXTONMISS) && - (seq - vblwait->request.sequence) <= (1 << 23)) { - vblwait->request.sequence = seq + 1; - vblwait->reply.sequence = vblwait->request.sequence; - } - DRM_DEBUG("event on vblank count %d, current %d, crtc %u\n", vblwait->request.sequence, seq, pipe); @@ -1690,6 +1681,11 @@ int drm_wait_vblank(struct drm_device *dev, void *data, goto done; } + if ((flags & _DRM_VBLANK_NEXTONMISS) && + (seq - vblwait->request.sequence) <= (1 << 23)) { + vblwait->request.sequence = seq + 1; + } + if (flags & _DRM_VBLANK_EVENT) { /* must hold on to the vblank ref until the event fires * drm_vblank_put will be called asynchronously @@ -1697,11 +1693,6 @@ int drm_wait_vblank(struct drm_device *dev, void *data, return drm_queue_vblank_event(dev, pipe, vblwait, file_priv); } - if ((flags & _DRM_VBLANK_NEXTONMISS) && - (seq - vblwait->request.sequence) <= (1<<23)) { - vblwait->request.sequence = seq + 1; - } - DRM_DEBUG("waiting on vblank count %d, crtc %u\n", vblwait->request.sequence, pipe); vblank->last_wait = vblwait->request.sequence; diff --git a/drivers/gpu/drm/drm_memory.c b/drivers/gpu/drm/drm_memory.c index 87a8cb73366f..fc0ebd273ef8 100644 --- a/drivers/gpu/drm/drm_memory.c +++ b/drivers/gpu/drm/drm_memory.c @@ -44,7 +44,7 @@ # include <asm/agp.h> #else # ifdef __powerpc__ -# define PAGE_AGP __pgprot(_PAGE_KERNEL | _PAGE_NO_CACHE) +# define PAGE_AGP pgprot_noncached_wc(PAGE_KERNEL) # else # define PAGE_AGP PAGE_KERNEL # endif diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index 49311fc61d5d..af0d471ee246 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -999,17 +999,17 @@ int mipi_dsi_dcs_set_tear_on(struct mipi_dsi_device *dsi, EXPORT_SYMBOL(mipi_dsi_dcs_set_tear_on); /** - * mipi_dsi_set_tear_scanline() - turn on the display module's Tearing Effect - * output signal on the TE signal line when display module reaches line N - * defined by STS[n:0]. + * mipi_dsi_dcs_set_tear_scanline() - set the scanline to use as trigger for + * the Tearing Effect output signal of the display module * @dsi: DSI peripheral device - * @param: STS[10:0] + * @scanline: scanline to use as trigger + * * Return: 0 on success or a negative error code on failure */ -int mipi_dsi_set_tear_scanline(struct mipi_dsi_device *dsi, u16 param) +int mipi_dsi_dcs_set_tear_scanline(struct mipi_dsi_device *dsi, u16 scanline) { - u8 payload[3] = { MIPI_DCS_SET_TEAR_SCANLINE, param >> 8, - param & 0xff }; + u8 payload[3] = { MIPI_DCS_SET_TEAR_SCANLINE, scanline >> 8, + scanline & 0xff }; ssize_t err; err = mipi_dsi_generic_write(dsi, payload, sizeof(payload)); @@ -1018,7 +1018,7 @@ int mipi_dsi_set_tear_scanline(struct mipi_dsi_device *dsi, u16 param) return 0; } -EXPORT_SYMBOL(mipi_dsi_set_tear_scanline); +EXPORT_SYMBOL(mipi_dsi_dcs_set_tear_scanline); /** * mipi_dsi_dcs_set_pixel_format() - sets the pixel format for the RGB image diff --git a/drivers/gpu/drm/drm_scatter.c b/drivers/gpu/drm/drm_scatter.c index 4f0f3b36d537..bf70431073f6 100644 --- a/drivers/gpu/drm/drm_scatter.c +++ b/drivers/gpu/drm/drm_scatter.c @@ -41,7 +41,7 @@ static inline void *drm_vmalloc_dma(unsigned long size) { #if defined(__powerpc__) && defined(CONFIG_NOT_COHERENT_CACHE) - return __vmalloc(size, GFP_KERNEL, PAGE_KERNEL | _PAGE_NO_CACHE); + return __vmalloc(size, GFP_KERNEL, pgprot_noncached_wc(PAGE_KERNEL)); #else return vmalloc_32(size); #endif diff --git a/drivers/gpu/drm/drm_vm.c b/drivers/gpu/drm/drm_vm.c index 43ff44a2b8e7..caa4e4ca616d 100644 --- a/drivers/gpu/drm/drm_vm.c +++ b/drivers/gpu/drm/drm_vm.c @@ -80,7 +80,7 @@ static pgprot_t drm_dma_prot(uint32_t map_type, struct vm_area_struct *vma) pgprot_t tmp = vm_get_page_prot(vma->vm_flags); #if defined(__powerpc__) && defined(CONFIG_NOT_COHERENT_CACHE) - tmp |= _PAGE_NO_CACHE; + tmp = pgprot_noncached_wc(tmp); #endif return tmp; } @@ -593,7 +593,7 @@ static int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma) * pages and mappings in fault() */ #if defined(__powerpc__) - pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE; + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); #endif vma->vm_ops = &drm_vm_ops; break; diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig index d814b3048ee5..1c7e14cf2781 100644 --- a/drivers/gpu/drm/exynos/Kconfig +++ b/drivers/gpu/drm/exynos/Kconfig @@ -2,10 +2,6 @@ config DRM_EXYNOS tristate "DRM Support for Samsung SoC EXYNOS Series" depends on OF && DRM && (ARCH_S3C64XX || ARCH_EXYNOS || ARCH_MULTIPLATFORM) select DRM_KMS_HELPER - select DRM_KMS_FB_HELPER - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT select VIDEOMODE_HELPERS help Choose this option if you have a Samsung SoC EXYNOS chipset. diff --git a/drivers/gpu/drm/i2c/ch7006_drv.c b/drivers/gpu/drm/i2c/ch7006_drv.c index 0594c45f7164..e9e8ae2ec06b 100644 --- a/drivers/gpu/drm/i2c/ch7006_drv.c +++ b/drivers/gpu/drm/i2c/ch7006_drv.c @@ -361,13 +361,8 @@ static int ch7006_encoder_set_property(struct drm_encoder *encoder, /* Disable the crtc to ensure a full modeset is * performed whenever it's turned on again. */ - if (crtc) { - struct drm_mode_set modeset = { - .crtc = crtc, - }; - - drm_mode_set_config_internal(&modeset); - } + if (crtc) + drm_crtc_force_disable(crtc); } return 0; diff --git a/drivers/gpu/drm/mediatek/mtk_mipi_tx.c b/drivers/gpu/drm/mediatek/mtk_mipi_tx.c index cf8f38d39e10..1c366f8cb2d0 100644 --- a/drivers/gpu/drm/mediatek/mtk_mipi_tx.c +++ b/drivers/gpu/drm/mediatek/mtk_mipi_tx.c @@ -431,7 +431,7 @@ static int mtk_mipi_tx_probe(struct platform_device *pdev) phy_set_drvdata(phy, mipi_tx); phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); - if (IS_ERR(phy)) { + if (IS_ERR(phy_provider)) { ret = PTR_ERR(phy_provider); return ret; } diff --git a/drivers/gpu/drm/nouveau/dispnv04/disp.c b/drivers/gpu/drm/nouveau/dispnv04/disp.c index aea81a547e85..34c0f2f67548 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv04/disp.c @@ -125,18 +125,8 @@ nv04_display_destroy(struct drm_device *dev) struct nv04_display *disp = nv04_display(dev); struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_encoder *encoder; - struct drm_crtc *crtc; struct nouveau_crtc *nv_crtc; - /* Turn every CRTC off. */ - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - struct drm_mode_set modeset = { - .crtc = crtc, - }; - - drm_mode_set_config_internal(&modeset); - } - /* Restore state */ list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.base.head) encoder->enc_restore(&encoder->base.base); diff --git a/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c b/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c index a665b78b2af5..434d1e29f279 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c +++ b/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c @@ -749,13 +749,8 @@ static int nv17_tv_set_property(struct drm_encoder *encoder, /* Disable the crtc to ensure a full modeset is * performed whenever it's turned on again. */ - if (crtc) { - struct drm_mode_set modeset = { - .crtc = crtc, - }; - - drm_mode_set_config_internal(&modeset); - } + if (crtc) + drm_crtc_force_disable(crtc); } return 0; diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index 844bd9951456..afbf557b23d4 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -47,7 +47,7 @@ nouveau_display_vblank_handler(struct nvif_notify *notify) { struct nouveau_crtc *nv_crtc = container_of(notify, typeof(*nv_crtc), vblank); - drm_handle_vblank(nv_crtc->base.dev, nv_crtc->index); + drm_crtc_handle_vblank(&nv_crtc->base); return NVIF_NOTIFY_KEEP; } @@ -556,6 +556,7 @@ nouveau_display_destroy(struct drm_device *dev) nouveau_display_vblank_fini(dev); drm_kms_helper_poll_fini(dev); + drm_crtc_force_disable_all(dev); drm_mode_config_cleanup(dev); if (disp->dtor) diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 6dd396f56884..66c1280c0f1f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -505,7 +505,11 @@ nouveau_drm_unload(struct drm_device *dev) { struct nouveau_drm *drm = nouveau_drm(dev); - pm_runtime_get_sync(dev->dev); + if (nouveau_runtime_pm != 0) { + pm_runtime_get_sync(dev->dev); + pm_runtime_forbid(dev->dev); + } + nouveau_fbcon_fini(dev); nouveau_accel_fini(drm); nouveau_hwmon_fini(dev); diff --git a/drivers/gpu/drm/qxl/qxl_cmd.c b/drivers/gpu/drm/qxl/qxl_cmd.c index b5d4b41361bd..04270f5d110c 100644 --- a/drivers/gpu/drm/qxl/qxl_cmd.c +++ b/drivers/gpu/drm/qxl/qxl_cmd.c @@ -203,7 +203,7 @@ qxl_push_cursor_ring_release(struct qxl_device *qdev, struct qxl_release *releas bool qxl_queue_garbage_collect(struct qxl_device *qdev, bool flush) { if (!qxl_check_idle(qdev->release_ring)) { - queue_work(qdev->gc_queue, &qdev->gc_work); + schedule_work(&qdev->gc_work); if (flush) flush_work(&qdev->gc_work); return true; diff --git a/drivers/gpu/drm/qxl/qxl_draw.c b/drivers/gpu/drm/qxl/qxl_draw.c index 56e1d633875e..ffe885395145 100644 --- a/drivers/gpu/drm/qxl/qxl_draw.c +++ b/drivers/gpu/drm/qxl/qxl_draw.c @@ -37,7 +37,6 @@ static int alloc_clips(struct qxl_device *qdev, * the qxl_clip_rects. This is *not* the same as the memory allocated * on the device, it is offset to qxl_clip_rects.chunk.data */ static struct qxl_rect *drawable_set_clipping(struct qxl_device *qdev, - struct qxl_drawable *drawable, unsigned num_clips, struct qxl_bo *clips_bo) { @@ -136,6 +135,8 @@ static int qxl_palette_create_1bit(struct qxl_bo *palette_bo, * correctly globaly, since that would require * tracking all of our palettes. */ ret = qxl_bo_kmap(palette_bo, (void **)&pal); + if (ret) + return ret; pal->num_ents = 2; pal->unique = unique++; if (visual == FB_VISUAL_TRUECOLOR || visual == FB_VISUAL_DIRECTCOLOR) { @@ -349,7 +350,7 @@ void qxl_draw_dirty_fb(struct qxl_device *qdev, if (ret) goto out_release_backoff; - rects = drawable_set_clipping(qdev, drawable, num_clips, clips_bo); + rects = drawable_set_clipping(qdev, num_clips, clips_bo); if (!rects) goto out_release_backoff; diff --git a/drivers/gpu/drm/qxl/qxl_drv.h b/drivers/gpu/drm/qxl/qxl_drv.h index 3ad6604b34ce..8e633caa4078 100644 --- a/drivers/gpu/drm/qxl/qxl_drv.h +++ b/drivers/gpu/drm/qxl/qxl_drv.h @@ -321,7 +321,6 @@ struct qxl_device { struct qxl_bo *current_release_bo[3]; int current_release_bo_offset[3]; - struct workqueue_struct *gc_queue; struct work_struct gc_work; struct drm_property *hotplug_mode_update_property; diff --git a/drivers/gpu/drm/qxl/qxl_kms.c b/drivers/gpu/drm/qxl/qxl_kms.c index 2319800b7add..e642242728c0 100644 --- a/drivers/gpu/drm/qxl/qxl_kms.c +++ b/drivers/gpu/drm/qxl/qxl_kms.c @@ -258,7 +258,6 @@ static int qxl_device_init(struct qxl_device *qdev, (unsigned long)qdev->surfaceram_size); - qdev->gc_queue = create_singlethread_workqueue("qxl_gc"); INIT_WORK(&qdev->gc_work, qxl_gc_work); return 0; @@ -270,10 +269,7 @@ static void qxl_device_fini(struct qxl_device *qdev) qxl_bo_unref(&qdev->current_release_bo[0]); if (qdev->current_release_bo[1]) qxl_bo_unref(&qdev->current_release_bo[1]); - flush_workqueue(qdev->gc_queue); - destroy_workqueue(qdev->gc_queue); - qdev->gc_queue = NULL; - + flush_work(&qdev->gc_work); qxl_ring_free(qdev->command_ring); qxl_ring_free(qdev->cursor_ring); qxl_ring_free(qdev->release_ring); @@ -310,10 +306,6 @@ int qxl_driver_load(struct drm_device *dev, unsigned long flags) struct qxl_device *qdev; int r; - /* require kms */ - if (!drm_core_check_feature(dev, DRIVER_MODESET)) - return -ENODEV; - qdev = kzalloc(sizeof(struct qxl_device), GFP_KERNEL); if (qdev == NULL) return -ENOMEM; diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 21c44b2293bc..a00dd2f74527 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -30,6 +30,7 @@ #include <drm/drmP.h> #include <drm/drm_crtc_helper.h> #include <drm/radeon_drm.h> +#include <linux/pm_runtime.h> #include <linux/vgaarb.h> #include <linux/vga_switcheroo.h> #include <linux/efi.h> @@ -1526,6 +1527,9 @@ int radeon_device_init(struct radeon_device *rdev, return 0; failed: + /* balance pm_runtime_get_sync() in radeon_driver_unload_kms() */ + if (radeon_is_px(ddev)) + pm_runtime_put_noidle(ddev->dev); if (runtime) vga_switcheroo_fini_domain_pm_ops(rdev->dev); return r; diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 3965d1916b9c..5f1cd695c965 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -1711,6 +1711,7 @@ void radeon_modeset_fini(struct radeon_device *rdev) radeon_afmt_fini(rdev); drm_kms_helper_poll_fini(rdev->ddev); radeon_hpd_fini(rdev); + drm_crtc_force_disable_all(rdev->ddev); drm_mode_config_cleanup(rdev->ddev); rdev->mode_info.mode_config_initialized = false; } diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c index 414953c46a38..835563c1f0ed 100644 --- a/drivers/gpu/drm/radeon/radeon_kms.c +++ b/drivers/gpu/drm/radeon/radeon_kms.c @@ -63,7 +63,10 @@ int radeon_driver_unload_kms(struct drm_device *dev) if (rdev->rmmio == NULL) goto done_free; - pm_runtime_get_sync(dev->dev); + if (radeon_is_px(dev)) { + pm_runtime_get_sync(dev->dev); + pm_runtime_forbid(dev->dev); + } radeon_kfd_device_fini(rdev); diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c index 0d8bdda736f9..e39fcef2e033 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c @@ -552,7 +552,7 @@ static irqreturn_t rcar_du_crtc_irq(int irq, void *arg) rcar_du_crtc_write(rcrtc, DSRCR, status & DSRCR_MASK); if (status & DSSR_FRM) { - drm_handle_vblank(rcrtc->crtc.dev, rcrtc->index); + drm_crtc_handle_vblank(&rcrtc->crtc); rcar_du_crtc_finish_page_flip(rcrtc); ret = IRQ_HANDLED; } diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c index d665fb04d264..f0bd1ee8b128 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c @@ -433,6 +433,7 @@ static int rockchip_drm_platform_probe(struct platform_device *pdev) is_support_iommu = false; } + of_node_put(iommu); component_match_add(dev, &match, compare_of, port->parent); of_node_put(port); } diff --git a/drivers/gpu/drm/sti/sti_compositor.c b/drivers/gpu/drm/sti/sti_compositor.c index 794148ff0e57..bd74732ea09b 100644 --- a/drivers/gpu/drm/sti/sti_compositor.c +++ b/drivers/gpu/drm/sti/sti_compositor.c @@ -267,10 +267,12 @@ static int sti_compositor_probe(struct platform_device *pdev) vtg_np = of_parse_phandle(pdev->dev.of_node, "st,vtg", 0); if (vtg_np) compo->vtg_main = of_vtg_find(vtg_np); + of_node_put(vtg_np); vtg_np = of_parse_phandle(pdev->dev.of_node, "st,vtg", 1); if (vtg_np) compo->vtg_aux = of_vtg_find(vtg_np); + of_node_put(vtg_np); platform_set_drvdata(pdev, compo); diff --git a/drivers/gpu/drm/sti/sti_dvo.c b/drivers/gpu/drm/sti/sti_dvo.c index ec3108074350..00881eb4536e 100644 --- a/drivers/gpu/drm/sti/sti_dvo.c +++ b/drivers/gpu/drm/sti/sti_dvo.c @@ -580,6 +580,7 @@ static int sti_dvo_probe(struct platform_device *pdev) dvo->panel_node = of_parse_phandle(np, "sti,panel", 0); if (!dvo->panel_node) DRM_ERROR("No panel associated to the dvo output\n"); + of_node_put(dvo->panel_node); platform_set_drvdata(pdev, dvo); diff --git a/drivers/gpu/drm/sti/sti_hqvdp.c b/drivers/gpu/drm/sti/sti_hqvdp.c index 33d2f42550cc..b03232247966 100644 --- a/drivers/gpu/drm/sti/sti_hqvdp.c +++ b/drivers/gpu/drm/sti/sti_hqvdp.c @@ -1363,6 +1363,7 @@ static int sti_hqvdp_probe(struct platform_device *pdev) vtg_np = of_parse_phandle(pdev->dev.of_node, "st,vtg", 0); if (vtg_np) hqvdp->vtg = of_vtg_find(vtg_np); + of_node_put(vtg_np); platform_set_drvdata(pdev, hqvdp); diff --git a/drivers/gpu/drm/sti/sti_vtg.c b/drivers/gpu/drm/sti/sti_vtg.c index 957ce712ea44..0bdc385eec17 100644 --- a/drivers/gpu/drm/sti/sti_vtg.c +++ b/drivers/gpu/drm/sti/sti_vtg.c @@ -432,6 +432,7 @@ static int vtg_probe(struct platform_device *pdev) np = of_parse_phandle(pdev->dev.of_node, "st,slave", 0); if (np) { vtg->slave = of_vtg_find(np); + of_node_put(np); if (!vtg->slave) return -EPROBE_DEFER; diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c index 79027b1c64d3..107c8bd04f6d 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c @@ -697,7 +697,7 @@ irqreturn_t tilcdc_crtc_irq(struct drm_crtc *crtc) spin_unlock_irqrestore(&tilcdc_crtc->irq_lock, flags); - drm_handle_vblank(dev, 0); + drm_crtc_handle_vblank(crtc); if (!skip_event) { struct drm_pending_vblank_event *event; diff --git a/drivers/gpu/drm/udl/udl_drv.c b/drivers/gpu/drm/udl/udl_drv.c index c20408940cd0..17d34e0edbdd 100644 --- a/drivers/gpu/drm/udl/udl_drv.c +++ b/drivers/gpu/drm/udl/udl_drv.c @@ -94,7 +94,6 @@ static void udl_usb_disconnect(struct usb_interface *interface) struct drm_device *dev = usb_get_intfdata(interface); drm_kms_helper_poll_disable(dev); - drm_connector_unregister_all(dev); udl_fbdev_unplug(dev); udl_drop_usb(dev); drm_unplug_dev(dev); diff --git a/drivers/gpu/drm/vgem/vgem_drv.c b/drivers/gpu/drm/vgem/vgem_drv.c index 35ea5d02a827..29c2aab3c1a7 100644 --- a/drivers/gpu/drm/vgem/vgem_drv.c +++ b/drivers/gpu/drm/vgem/vgem_drv.c @@ -42,81 +42,38 @@ #define DRIVER_MAJOR 1 #define DRIVER_MINOR 0 -void vgem_gem_put_pages(struct drm_vgem_gem_object *obj) -{ - drm_gem_put_pages(&obj->base, obj->pages, false, false); - obj->pages = NULL; -} - static void vgem_gem_free_object(struct drm_gem_object *obj) { struct drm_vgem_gem_object *vgem_obj = to_vgem_bo(obj); - drm_gem_free_mmap_offset(obj); - - if (vgem_obj->use_dma_buf && obj->dma_buf) { - dma_buf_put(obj->dma_buf); - obj->dma_buf = NULL; - } - drm_gem_object_release(obj); - - if (vgem_obj->pages) - vgem_gem_put_pages(vgem_obj); - - vgem_obj->pages = NULL; - kfree(vgem_obj); } -int vgem_gem_get_pages(struct drm_vgem_gem_object *obj) -{ - struct page **pages; - - if (obj->pages || obj->use_dma_buf) - return 0; - - pages = drm_gem_get_pages(&obj->base); - if (IS_ERR(pages)) { - return PTR_ERR(pages); - } - - obj->pages = pages; - - return 0; -} - static int vgem_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { struct drm_vgem_gem_object *obj = vma->vm_private_data; - loff_t num_pages; - pgoff_t page_offset; - int ret; - /* We don't use vmf->pgoff since that has the fake offset */ - page_offset = ((unsigned long)vmf->virtual_address - vma->vm_start) >> - PAGE_SHIFT; - - num_pages = DIV_ROUND_UP(obj->base.size, PAGE_SIZE); - - if (page_offset > num_pages) - return VM_FAULT_SIGBUS; - - ret = vm_insert_page(vma, (unsigned long)vmf->virtual_address, - obj->pages[page_offset]); - switch (ret) { - case 0: - return VM_FAULT_NOPAGE; - case -ENOMEM: - return VM_FAULT_OOM; - case -EBUSY: - return VM_FAULT_RETRY; - case -EFAULT: - case -EINVAL: - return VM_FAULT_SIGBUS; - default: - WARN_ON(1); - return VM_FAULT_SIGBUS; + unsigned long vaddr = (unsigned long)vmf->virtual_address; + struct page *page; + + page = shmem_read_mapping_page(file_inode(obj->base.filp)->i_mapping, + (vaddr - vma->vm_start) >> PAGE_SHIFT); + if (!IS_ERR(page)) { + vmf->page = page; + return 0; + } else switch (PTR_ERR(page)) { + case -ENOSPC: + case -ENOMEM: + return VM_FAULT_OOM; + case -EBUSY: + return VM_FAULT_RETRY; + case -EFAULT: + case -EINVAL: + return VM_FAULT_SIGBUS; + default: + WARN_ON_ONCE(PTR_ERR(page)); + return VM_FAULT_SIGBUS; } } @@ -134,57 +91,43 @@ static struct drm_gem_object *vgem_gem_create(struct drm_device *dev, unsigned long size) { struct drm_vgem_gem_object *obj; - struct drm_gem_object *gem_object; - int err; - - size = roundup(size, PAGE_SIZE); + int ret; obj = kzalloc(sizeof(*obj), GFP_KERNEL); if (!obj) return ERR_PTR(-ENOMEM); - gem_object = &obj->base; - - err = drm_gem_object_init(dev, gem_object, size); - if (err) - goto out; - - err = vgem_gem_get_pages(obj); - if (err) - goto out; - - err = drm_gem_handle_create(file, gem_object, handle); - if (err) - goto handle_out; + ret = drm_gem_object_init(dev, &obj->base, roundup(size, PAGE_SIZE)); + if (ret) + goto err_free; - drm_gem_object_unreference_unlocked(gem_object); + ret = drm_gem_handle_create(file, &obj->base, handle); + drm_gem_object_unreference_unlocked(&obj->base); + if (ret) + goto err; - return gem_object; + return &obj->base; -handle_out: - drm_gem_object_release(gem_object); -out: +err_free: kfree(obj); - return ERR_PTR(err); +err: + return ERR_PTR(ret); } static int vgem_gem_dumb_create(struct drm_file *file, struct drm_device *dev, struct drm_mode_create_dumb *args) { struct drm_gem_object *gem_object; - uint64_t size; - uint64_t pitch = args->width * DIV_ROUND_UP(args->bpp, 8); + u64 pitch, size; + pitch = args->width * DIV_ROUND_UP(args->bpp, 8); size = args->height * pitch; if (size == 0) return -EINVAL; gem_object = vgem_gem_create(dev, file, &args->handle, size); - - if (IS_ERR(gem_object)) { - DRM_DEBUG_DRIVER("object creation failed\n"); + if (IS_ERR(gem_object)) return PTR_ERR(gem_object); - } args->size = gem_object->size; args->pitch = pitch; @@ -194,26 +137,26 @@ static int vgem_gem_dumb_create(struct drm_file *file, struct drm_device *dev, return 0; } -int vgem_gem_dumb_map(struct drm_file *file, struct drm_device *dev, - uint32_t handle, uint64_t *offset) +static int vgem_gem_dumb_map(struct drm_file *file, struct drm_device *dev, + uint32_t handle, uint64_t *offset) { - int ret = 0; struct drm_gem_object *obj; + int ret; obj = drm_gem_object_lookup(file, handle); if (!obj) return -ENOENT; + if (!obj->filp) { + ret = -EINVAL; + goto unref; + } + ret = drm_gem_create_mmap_offset(obj); if (ret) goto unref; - BUG_ON(!obj->filp); - - obj->filp->private_data = obj; - *offset = drm_vma_node_offset_addr(&obj->vma_node); - unref: drm_gem_object_unreference_unlocked(obj); @@ -223,24 +166,127 @@ unref: static struct drm_ioctl_desc vgem_ioctls[] = { }; +static int vgem_mmap(struct file *filp, struct vm_area_struct *vma) +{ + unsigned long flags = vma->vm_flags; + int ret; + + ret = drm_gem_mmap(filp, vma); + if (ret) + return ret; + + /* Keep the WC mmaping set by drm_gem_mmap() but our pages + * are ordinary and not special. + */ + vma->vm_flags = flags | VM_DONTEXPAND | VM_DONTDUMP; + return 0; +} + static const struct file_operations vgem_driver_fops = { .owner = THIS_MODULE, .open = drm_open, - .mmap = drm_gem_mmap, + .mmap = vgem_mmap, .poll = drm_poll, .read = drm_read, .unlocked_ioctl = drm_ioctl, .release = drm_release, }; +static int vgem_prime_pin(struct drm_gem_object *obj) +{ + long n_pages = obj->size >> PAGE_SHIFT; + struct page **pages; + + /* Flush the object from the CPU cache so that importers can rely + * on coherent indirect access via the exported dma-address. + */ + pages = drm_gem_get_pages(obj); + if (IS_ERR(pages)) + return PTR_ERR(pages); + + drm_clflush_pages(pages, n_pages); + drm_gem_put_pages(obj, pages, true, false); + + return 0; +} + +static struct sg_table *vgem_prime_get_sg_table(struct drm_gem_object *obj) +{ + struct sg_table *st; + struct page **pages; + + pages = drm_gem_get_pages(obj); + if (IS_ERR(pages)) + return ERR_CAST(pages); + + st = drm_prime_pages_to_sg(pages, obj->size >> PAGE_SHIFT); + drm_gem_put_pages(obj, pages, false, false); + + return st; +} + +static void *vgem_prime_vmap(struct drm_gem_object *obj) +{ + long n_pages = obj->size >> PAGE_SHIFT; + struct page **pages; + void *addr; + + pages = drm_gem_get_pages(obj); + if (IS_ERR(pages)) + return NULL; + + addr = vmap(pages, n_pages, 0, pgprot_writecombine(PAGE_KERNEL)); + drm_gem_put_pages(obj, pages, false, false); + + return addr; +} + +static void vgem_prime_vunmap(struct drm_gem_object *obj, void *vaddr) +{ + vunmap(vaddr); +} + +static int vgem_prime_mmap(struct drm_gem_object *obj, + struct vm_area_struct *vma) +{ + int ret; + + if (obj->size < vma->vm_end - vma->vm_start) + return -EINVAL; + + if (!obj->filp) + return -ENODEV; + + ret = obj->filp->f_op->mmap(obj->filp, vma); + if (ret) + return ret; + + fput(vma->vm_file); + vma->vm_file = get_file(obj->filp); + vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP; + vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags)); + + return 0; +} + static struct drm_driver vgem_driver = { - .driver_features = DRIVER_GEM, + .driver_features = DRIVER_GEM | DRIVER_PRIME, .gem_free_object_unlocked = vgem_gem_free_object, .gem_vm_ops = &vgem_gem_vm_ops, .ioctls = vgem_ioctls, .fops = &vgem_driver_fops, + .dumb_create = vgem_gem_dumb_create, .dumb_map_offset = vgem_gem_dumb_map, + + .prime_handle_to_fd = drm_gem_prime_handle_to_fd, + .gem_prime_pin = vgem_prime_pin, + .gem_prime_export = drm_gem_prime_export, + .gem_prime_get_sg_table = vgem_prime_get_sg_table, + .gem_prime_vmap = vgem_prime_vmap, + .gem_prime_vunmap = vgem_prime_vunmap, + .gem_prime_mmap = vgem_prime_mmap, + .name = DRIVER_NAME, .desc = DRIVER_DESC, .date = DRIVER_DATE, @@ -248,7 +294,7 @@ static struct drm_driver vgem_driver = { .minor = DRIVER_MINOR, }; -struct drm_device *vgem_device; +static struct drm_device *vgem_device; static int __init vgem_init(void) { @@ -261,7 +307,6 @@ static int __init vgem_init(void) } ret = drm_dev_register(vgem_device, 0); - if (ret) goto out_unref; diff --git a/drivers/gpu/drm/vgem/vgem_drv.h b/drivers/gpu/drm/vgem/vgem_drv.h index e9f92f7ee275..988cbaae7588 100644 --- a/drivers/gpu/drm/vgem/vgem_drv.h +++ b/drivers/gpu/drm/vgem/vgem_drv.h @@ -35,12 +35,6 @@ #define to_vgem_bo(x) container_of(x, struct drm_vgem_gem_object, base) struct drm_vgem_gem_object { struct drm_gem_object base; - struct page **pages; - bool use_dma_buf; }; -/* vgem_drv.c */ -extern void vgem_gem_put_pages(struct drm_vgem_gem_object *obj); -extern int vgem_gem_get_pages(struct drm_vgem_gem_object *obj); - #endif diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 60646644bef3..5d5c9515618d 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -1041,8 +1041,7 @@ static struct vmw_master *vmw_master_check(struct drm_device *dev, struct vmw_fpriv *vmw_fp = vmw_fpriv(file_priv); struct vmw_master *vmaster; - if (file_priv->minor->type != DRM_MINOR_LEGACY || - !(flags & DRM_AUTH)) + if (!drm_is_primary_client(file_priv) || !(flags & DRM_AUTH)) return NULL; ret = mutex_lock_interruptible(&dev->master_mutex); diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c index 2df216b39cc5..5f962bfcb43c 100644 --- a/drivers/gpu/vga/vga_switcheroo.c +++ b/drivers/gpu/vga/vga_switcheroo.c @@ -52,9 +52,9 @@ * * * muxed: Dual GPUs with a multiplexer chip to switch outputs between GPUs. * * muxless: Dual GPUs but only one of them is connected to outputs. - * The other one is merely used to offload rendering, its results - * are copied over PCIe into the framebuffer. On Linux this is - * supported with DRI PRIME. + * The other one is merely used to offload rendering, its results + * are copied over PCIe into the framebuffer. On Linux this is + * supported with DRI PRIME. * * Hybrid graphics started to appear in the late Naughties and were initially * all muxed. Newer laptops moved to a muxless architecture for cost reasons. @@ -560,21 +560,21 @@ EXPORT_SYMBOL(vga_switcheroo_unlock_ddc); * * OFF: Power off the device not in use. * * ON: Power on the device not in use. * * IGD: Switch to the integrated graphics device. - * Power on the integrated GPU if necessary, power off the discrete GPU. - * Prerequisite is that no user space processes (e.g. Xorg, alsactl) - * have opened device files of the GPUs or the audio client. If the - * switch fails, the user may invoke lsof(8) or fuser(1) on /dev/dri/ - * and /dev/snd/controlC1 to identify processes blocking the switch. + * Power on the integrated GPU if necessary, power off the discrete GPU. + * Prerequisite is that no user space processes (e.g. Xorg, alsactl) + * have opened device files of the GPUs or the audio client. If the + * switch fails, the user may invoke lsof(8) or fuser(1) on /dev/dri/ + * and /dev/snd/controlC1 to identify processes blocking the switch. * * DIS: Switch to the discrete graphics device. * * DIGD: Delayed switch to the integrated graphics device. - * This will perform the switch once the last user space process has - * closed the device files of the GPUs and the audio client. + * This will perform the switch once the last user space process has + * closed the device files of the GPUs and the audio client. * * DDIS: Delayed switch to the discrete graphics device. * * MIGD: Mux-only switch to the integrated graphics device. - * Does not remap console or change the power state of either gpu. - * If the integrated GPU is currently off, the screen will turn black. - * If it is on, the screen will show whatever happens to be in VRAM. - * Either way, the user has to blindly enter the command to switch back. + * Does not remap console or change the power state of either gpu. + * If the integrated GPU is currently off, the screen will turn black. + * If it is on, the screen will show whatever happens to be in VRAM. + * Either way, the user has to blindly enter the command to switch back. * * MDIS: Mux-only switch to the discrete graphics device. * * For GPUs whose power state is controlled by the driver's runtime pm, diff --git a/include/drm/drmP.h b/include/drm/drmP.h index cf918e3e6afb..c2fe2cffb809 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -942,8 +942,6 @@ extern int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *filp); extern u32 drm_vblank_count(struct drm_device *dev, unsigned int pipe); extern u32 drm_crtc_vblank_count(struct drm_crtc *crtc); -extern u32 drm_vblank_count_and_time(struct drm_device *dev, unsigned int pipe, - struct timeval *vblanktime); extern u32 drm_crtc_vblank_count_and_time(struct drm_crtc *crtc, struct timeval *vblanktime); extern void drm_crtc_send_vblank_event(struct drm_crtc *crtc, diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index f5469d3a46dd..9e6ab4a0c274 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -2588,7 +2588,6 @@ static inline unsigned drm_connector_index(struct drm_connector *connector) } /* helpers to {un}register all connectors from sysfs for device */ -extern int drm_connector_register_all(struct drm_device *dev); extern void drm_connector_unregister_all(struct drm_device *dev); extern __printf(5, 6) @@ -2654,6 +2653,8 @@ extern struct drm_plane * drm_plane_from_index(struct drm_device *dev, int idx); extern void drm_plane_force_disable(struct drm_plane *plane); extern void drm_crtc_get_hv_timing(const struct drm_display_mode *mode, int *hdisplay, int *vdisplay); +extern int drm_crtc_force_disable(struct drm_crtc *crtc); +extern int drm_crtc_force_disable_all(struct drm_device *dev); extern void drm_encoder_cleanup(struct drm_encoder *encoder); diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h index 72f5b15e0738..47ac92584d76 100644 --- a/include/drm/drm_mipi_dsi.h +++ b/include/drm/drm_mipi_dsi.h @@ -265,7 +265,7 @@ int mipi_dsi_dcs_set_column_address(struct mipi_dsi_device *dsi, u16 start, u16 end); int mipi_dsi_dcs_set_page_address(struct mipi_dsi_device *dsi, u16 start, u16 end); -int mipi_dsi_set_tear_scanline(struct mipi_dsi_device *dsi, u16 param); +int mipi_dsi_dcs_set_tear_scanline(struct mipi_dsi_device *dsi, u16 scanline); int mipi_dsi_dcs_set_tear_off(struct mipi_dsi_device *dsi); int mipi_dsi_dcs_set_tear_on(struct mipi_dsi_device *dsi, enum mipi_dsi_dcs_tear_mode mode); |