Loading drivers/gpu/drm/msm/msm_drv.c +126 −0 Original line number Diff line number Diff line Loading @@ -15,6 +15,27 @@ * You should have received a copy of the GNU General Public License along with * this program. If not, see <http://www.gnu.org/licenses/>. */ /* * Copyright (c) 2016 Intel Corporation * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that copyright * notice and this permission notice appear in supporting documentation, and * that the name of the copyright holders not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission. The copyright holders make no representations * about the suitability of this software for any purpose. It is provided "as * is" without express or implied warranty. * * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE * OF THIS SOFTWARE. */ #include <linux/of_address.h> #include <linux/kthread.h> Loading Loading @@ -1331,6 +1352,109 @@ static int msm_release(struct inode *inode, struct file *filp) return drm_release(inode, filp); } /** * msm_drv_framebuffer_remove - remove and unreference a framebuffer object * @fb: framebuffer to remove */ void msm_drv_framebuffer_remove(struct drm_framebuffer *fb) { struct drm_device *dev; if (!fb) return; dev = fb->dev; WARN_ON(!list_empty(&fb->filp_head)); drm_framebuffer_unreference(fb); } struct msm_drv_rmfb2_work { struct work_struct work; struct list_head fbs; }; static void msm_drv_rmfb2_work_fn(struct work_struct *w) { struct msm_drv_rmfb2_work *arg = container_of(w, typeof(*arg), work); while (!list_empty(&arg->fbs)) { struct drm_framebuffer *fb = list_first_entry(&arg->fbs, typeof(*fb), filp_head); list_del_init(&fb->filp_head); msm_drv_framebuffer_remove(fb); } } /** * msm_ioctl_rmfb2 - remove an FB from the configuration * @dev: drm device for the ioctl * @data: data pointer for the ioctl * @file_priv: drm file for the ioctl call * * Remove the FB specified by the user. * * Called by the user via ioctl. * * Returns: * Zero on success, negative errno on failure. */ int msm_ioctl_rmfb2(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_framebuffer *fb = NULL; struct drm_framebuffer *fbl = NULL; uint32_t *id = data; int found = 0; if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EINVAL; fb = drm_framebuffer_lookup(dev, *id); if (!fb) return -ENOENT; /* drop extra ref from traversing drm_framebuffer_lookup */ drm_framebuffer_unreference(fb); mutex_lock(&file_priv->fbs_lock); list_for_each_entry(fbl, &file_priv->fbs, filp_head) if (fb == fbl) found = 1; if (!found) { mutex_unlock(&file_priv->fbs_lock); return -ENOENT; } list_del_init(&fb->filp_head); mutex_unlock(&file_priv->fbs_lock); /* * we now own the reference that was stored in the fbs list * * drm_framebuffer_remove may fail with -EINTR on pending signals, * so run this in a separate stack as there's no way to correctly * handle this after the fb is already removed from the lookup table. */ if (drm_framebuffer_read_refcount(fb) > 1) { struct msm_drv_rmfb2_work arg; INIT_WORK_ONSTACK(&arg.work, msm_drv_rmfb2_work_fn); INIT_LIST_HEAD(&arg.fbs); list_add_tail(&fb->filp_head, &arg.fbs); schedule_work(&arg.work); flush_work(&arg.work); destroy_work_on_stack(&arg.work); } else drm_framebuffer_unreference(fb); return 0; } EXPORT_SYMBOL(msm_ioctl_rmfb2); static const struct drm_ioctl_desc msm_ioctls[] = { DRM_IOCTL_DEF_DRV(MSM_GET_PARAM, msm_ioctl_get_param, DRM_AUTH|DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(MSM_GEM_NEW, msm_ioctl_gem_new, DRM_AUTH|DRM_RENDER_ALLOW), Loading @@ -1345,6 +1469,8 @@ static const struct drm_ioctl_desc msm_ioctls[] = { DRM_UNLOCKED|DRM_CONTROL_ALLOW), DRM_IOCTL_DEF_DRV(MSM_DEREGISTER_EVENT, msm_ioctl_deregister_event, DRM_UNLOCKED|DRM_CONTROL_ALLOW), DRM_IOCTL_DEF_DRV(MSM_RMFB2, msm_ioctl_rmfb2, DRM_CONTROL_ALLOW|DRM_UNLOCKED), }; static const struct vm_operations_struct vm_ops = { Loading include/uapi/drm/msm_drm.h +3 −0 Original line number Diff line number Diff line Loading @@ -316,6 +316,7 @@ struct drm_msm_event_resp { #define DRM_SDE_WB_CONFIG 0x40 #define DRM_MSM_REGISTER_EVENT 0x41 #define DRM_MSM_DEREGISTER_EVENT 0x42 #define DRM_MSM_RMFB2 0x43 /* sde custom events */ #define DRM_EVENT_HISTOGRAM 0x80000000 Loading @@ -335,6 +336,8 @@ struct drm_msm_event_resp { DRM_MSM_REGISTER_EVENT), struct drm_msm_event_req) #define DRM_IOCTL_MSM_DEREGISTER_EVENT DRM_IOW((DRM_COMMAND_BASE + \ DRM_MSM_DEREGISTER_EVENT), struct drm_msm_event_req) #define DRM_IOCTL_MSM_RMFB2 DRM_IOW((DRM_COMMAND_BASE + \ DRM_MSM_RMFB2), unsigned int) #if defined(__cplusplus) } Loading Loading
drivers/gpu/drm/msm/msm_drv.c +126 −0 Original line number Diff line number Diff line Loading @@ -15,6 +15,27 @@ * You should have received a copy of the GNU General Public License along with * this program. If not, see <http://www.gnu.org/licenses/>. */ /* * Copyright (c) 2016 Intel Corporation * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that copyright * notice and this permission notice appear in supporting documentation, and * that the name of the copyright holders not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission. The copyright holders make no representations * about the suitability of this software for any purpose. It is provided "as * is" without express or implied warranty. * * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE * OF THIS SOFTWARE. */ #include <linux/of_address.h> #include <linux/kthread.h> Loading Loading @@ -1331,6 +1352,109 @@ static int msm_release(struct inode *inode, struct file *filp) return drm_release(inode, filp); } /** * msm_drv_framebuffer_remove - remove and unreference a framebuffer object * @fb: framebuffer to remove */ void msm_drv_framebuffer_remove(struct drm_framebuffer *fb) { struct drm_device *dev; if (!fb) return; dev = fb->dev; WARN_ON(!list_empty(&fb->filp_head)); drm_framebuffer_unreference(fb); } struct msm_drv_rmfb2_work { struct work_struct work; struct list_head fbs; }; static void msm_drv_rmfb2_work_fn(struct work_struct *w) { struct msm_drv_rmfb2_work *arg = container_of(w, typeof(*arg), work); while (!list_empty(&arg->fbs)) { struct drm_framebuffer *fb = list_first_entry(&arg->fbs, typeof(*fb), filp_head); list_del_init(&fb->filp_head); msm_drv_framebuffer_remove(fb); } } /** * msm_ioctl_rmfb2 - remove an FB from the configuration * @dev: drm device for the ioctl * @data: data pointer for the ioctl * @file_priv: drm file for the ioctl call * * Remove the FB specified by the user. * * Called by the user via ioctl. * * Returns: * Zero on success, negative errno on failure. */ int msm_ioctl_rmfb2(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_framebuffer *fb = NULL; struct drm_framebuffer *fbl = NULL; uint32_t *id = data; int found = 0; if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EINVAL; fb = drm_framebuffer_lookup(dev, *id); if (!fb) return -ENOENT; /* drop extra ref from traversing drm_framebuffer_lookup */ drm_framebuffer_unreference(fb); mutex_lock(&file_priv->fbs_lock); list_for_each_entry(fbl, &file_priv->fbs, filp_head) if (fb == fbl) found = 1; if (!found) { mutex_unlock(&file_priv->fbs_lock); return -ENOENT; } list_del_init(&fb->filp_head); mutex_unlock(&file_priv->fbs_lock); /* * we now own the reference that was stored in the fbs list * * drm_framebuffer_remove may fail with -EINTR on pending signals, * so run this in a separate stack as there's no way to correctly * handle this after the fb is already removed from the lookup table. */ if (drm_framebuffer_read_refcount(fb) > 1) { struct msm_drv_rmfb2_work arg; INIT_WORK_ONSTACK(&arg.work, msm_drv_rmfb2_work_fn); INIT_LIST_HEAD(&arg.fbs); list_add_tail(&fb->filp_head, &arg.fbs); schedule_work(&arg.work); flush_work(&arg.work); destroy_work_on_stack(&arg.work); } else drm_framebuffer_unreference(fb); return 0; } EXPORT_SYMBOL(msm_ioctl_rmfb2); static const struct drm_ioctl_desc msm_ioctls[] = { DRM_IOCTL_DEF_DRV(MSM_GET_PARAM, msm_ioctl_get_param, DRM_AUTH|DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(MSM_GEM_NEW, msm_ioctl_gem_new, DRM_AUTH|DRM_RENDER_ALLOW), Loading @@ -1345,6 +1469,8 @@ static const struct drm_ioctl_desc msm_ioctls[] = { DRM_UNLOCKED|DRM_CONTROL_ALLOW), DRM_IOCTL_DEF_DRV(MSM_DEREGISTER_EVENT, msm_ioctl_deregister_event, DRM_UNLOCKED|DRM_CONTROL_ALLOW), DRM_IOCTL_DEF_DRV(MSM_RMFB2, msm_ioctl_rmfb2, DRM_CONTROL_ALLOW|DRM_UNLOCKED), }; static const struct vm_operations_struct vm_ops = { Loading
include/uapi/drm/msm_drm.h +3 −0 Original line number Diff line number Diff line Loading @@ -316,6 +316,7 @@ struct drm_msm_event_resp { #define DRM_SDE_WB_CONFIG 0x40 #define DRM_MSM_REGISTER_EVENT 0x41 #define DRM_MSM_DEREGISTER_EVENT 0x42 #define DRM_MSM_RMFB2 0x43 /* sde custom events */ #define DRM_EVENT_HISTOGRAM 0x80000000 Loading @@ -335,6 +336,8 @@ struct drm_msm_event_resp { DRM_MSM_REGISTER_EVENT), struct drm_msm_event_req) #define DRM_IOCTL_MSM_DEREGISTER_EVENT DRM_IOW((DRM_COMMAND_BASE + \ DRM_MSM_DEREGISTER_EVENT), struct drm_msm_event_req) #define DRM_IOCTL_MSM_RMFB2 DRM_IOW((DRM_COMMAND_BASE + \ DRM_MSM_RMFB2), unsigned int) #if defined(__cplusplus) } Loading