From: Carsten Haitzler carsten.haitzler@arm.com
Vblank is a bit different because it produces events that then can copy bpointers/capabilities back to userspace via a read on the DRM device as opposed to the ioctl. The compat handler called the normal native/purecap one and this happened to work for compat but not for purecap. Make the shared "native" purecap handling work for both and share that infra properly to avoid copy and paste.
Signed-off-by: Carsten Haitzler Carsten.Haitzler@arm.com --- drivers/gpu/drm/drm_atomic_uapi.c | 3 +- drivers/gpu/drm/drm_internal.h | 4 +++ drivers/gpu/drm/drm_ioc32.c | 8 +++++- drivers/gpu/drm/drm_vblank.c | 46 +++++++++++++++++++++++-------- include/drm/drm_vblank.h | 23 ++++++++++++++++ include/uapi/drm/drm.h | 6 ++-- 6 files changed, 74 insertions(+), 16 deletions(-)
diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c index 3e4668a20157..08474a1ea90e 100644 --- a/drivers/gpu/drm/drm_atomic_uapi.c +++ b/drivers/gpu/drm/drm_atomic_uapi.c @@ -940,7 +940,8 @@ int drm_atomic_get_property(struct drm_mode_object *obj, */
static struct drm_pending_vblank_event *create_vblank_event( - struct drm_crtc *crtc, uint64_t user_data) + struct drm_crtc *crtc, + __kernel_uintptr_t user_data) { struct drm_pending_vblank_event *e = NULL;
diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h index 8462b657c375..2d588df41cb5 100644 --- a/drivers/gpu/drm/drm_internal.h +++ b/drivers/gpu/drm/drm_internal.h @@ -23,6 +23,7 @@
#include <linux/kthread.h>
+#include <drm/drm.h> #include <drm/drm_ioctl.h> #include <drm/drm_vblank.h>
@@ -113,6 +114,9 @@ void drm_vblank_cancel_pending_works(struct drm_vblank_crtc *vblank); void drm_handle_vblank_works(struct drm_vblank_crtc *vblank);
/* IOCTLS */ +int drm_wait_vblank_ioctl_internal(struct drm_device *dev, void *data, + struct drm_file *filp, + bool compat); int drm_wait_vblank_ioctl(struct drm_device *dev, void *data, struct drm_file *filp); int drm_legacy_modeset_ctl_ioctl(struct drm_device *dev, void *data, diff --git a/drivers/gpu/drm/drm_ioc32.c b/drivers/gpu/drm/drm_ioc32.c index 504c2fcd9c89..d6a8c7250dda 100644 --- a/drivers/gpu/drm/drm_ioc32.c +++ b/drivers/gpu/drm/drm_ioc32.c @@ -33,6 +33,7 @@
#include <drm/drm_file.h> #include <drm/drm_print.h> +#include <drm/drm_drv.h>
#include "drm_crtc_internal.h" #include "drm_internal.h" @@ -841,11 +842,16 @@ typedef union drm_wait_vblank32 { static int compat_drm_wait_vblank(struct file *file, unsigned int cmd, user_uintptr_t arg) { + struct drm_file *file_priv = file->private_data; + struct drm_device *dev = file_priv->minor->dev; drm_wait_vblank32_t __user *argp = (void __user *)arg; drm_wait_vblank32_t req32; union drm_wait_vblank req; int err;
+ if (drm_dev_is_unplugged(dev)) + return -ENODEV; + if (copy_from_user(&req32, argp, sizeof(req32))) return -EFAULT;
@@ -854,7 +860,7 @@ static int compat_drm_wait_vblank(struct file *file, unsigned int cmd, req.request.type = req32.request.type; req.request.sequence = req32.request.sequence; req.request.signal = req32.request.signal; - err = drm_ioctl_kernel(file, drm_wait_vblank_ioctl, &req, DRM_UNLOCKED); + err = drm_wait_vblank_ioctl_internal(dev, &req, file_priv, true);
req32.reply.type = req.reply.type; req32.reply.sequence = req.reply.sequence; diff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c index 877e2067534f..7e0d5c5daa5c 100644 --- a/drivers/gpu/drm/drm_vblank.c +++ b/drivers/gpu/drm/drm_vblank.c @@ -1031,14 +1031,20 @@ static void send_vblank_event(struct drm_device *dev, case DRM_EVENT_VBLANK: case DRM_EVENT_FLIP_COMPLETE: tv = ktime_to_timespec64(now); - e->event.vbl.sequence = seq; /* * e->event is a user space structure, with hardcoded unsigned * 32-bit seconds/microseconds. This is safe as we always use * monotonic timestamps since linux-4.15 */ - e->event.vbl.tv_sec = tv.tv_sec; - e->event.vbl.tv_usec = tv.tv_nsec / 1000; + if (e->compat) { + e->event.vbl32.sequence = seq; + e->event.vbl32.tv_sec = tv.tv_sec; + e->event.vbl32.tv_usec = tv.tv_nsec / 1000; + } else { + e->event.vbl.sequence = seq; + e->event.vbl.tv_sec = tv.tv_sec; + e->event.vbl.tv_usec = tv.tv_nsec / 1000; + } break; case DRM_EVENT_CRTC_SEQUENCE: if (seq) @@ -1659,10 +1665,13 @@ int drm_legacy_modeset_ctl_ioctl(struct drm_device *dev, void *data, static int drm_queue_vblank_event(struct drm_device *dev, unsigned int pipe, u64 req_seq, union drm_wait_vblank *vblwait, - struct drm_file *file_priv) + struct drm_file *file_priv, + bool compat + ) { struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; struct drm_pending_vblank_event *e; + struct drm_crtc *crtc = NULL; ktime_t now; u64 seq; int ret; @@ -1675,12 +1684,19 @@ static int drm_queue_vblank_event(struct drm_device *dev, unsigned int pipe,
e->pipe = pipe; e->event.base.type = DRM_EVENT_VBLANK; - e->event.base.length = sizeof(e->event.vbl); - e->event.vbl.user_data = vblwait->request.signal; - e->event.vbl.crtc_id = 0; - if (drm_core_check_feature(dev, DRIVER_MODESET)) { - struct drm_crtc *crtc = drm_crtc_from_index(dev, pipe); - + if (drm_core_check_feature(dev, DRIVER_MODESET)) + crtc = drm_crtc_from_index(dev, pipe); + e->compat = compat; + if (compat) { + e->event.base.length = sizeof(e->event.vbl32); + e->event.vbl32.user_data = vblwait->request.signal; + e->event.vbl32.crtc_id = 0; + if (crtc) + e->event.vbl32.crtc_id = crtc->base.id; + } else { + e->event.base.length = sizeof(e->event.vbl); + e->event.vbl.user_data = vblwait->request.signal; + e->event.vbl.crtc_id = 0; if (crtc) e->event.vbl.crtc_id = crtc->base.id; } @@ -1789,6 +1805,13 @@ static bool drm_wait_vblank_supported(struct drm_device *dev)
int drm_wait_vblank_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) +{ + return drm_wait_vblank_ioctl_internal(dev, data, file_priv, false); +} + +int drm_wait_vblank_ioctl_internal(struct drm_device *dev, void *data, + struct drm_file *file_priv, + bool compat) { struct drm_crtc *crtc; struct drm_vblank_crtc *vblank; @@ -1886,7 +1909,8 @@ int drm_wait_vblank_ioctl(struct drm_device *dev, void *data, /* must hold on to the vblank ref until the event fires * drm_vblank_put will be called asynchronously */ - return drm_queue_vblank_event(dev, pipe, req_seq, vblwait, file_priv); + return drm_queue_vblank_event(dev, pipe, req_seq, vblwait, + file_priv, compat); }
if (req_seq != seq) { diff --git a/include/drm/drm_vblank.h b/include/drm/drm_vblank.h index 7f3957943dd1..10eb070a70a1 100644 --- a/include/drm/drm_vblank.h +++ b/include/drm/drm_vblank.h @@ -36,6 +36,22 @@ struct drm_device; struct drm_crtc; struct drm_vblank_work;
+struct drm_event_vblank32 { + struct drm_event base; + __u64 user_data; + __u32 tv_sec; + __u32 tv_usec; + __u32 sequence; + __u32 crtc_id; /* 0 on older kernels that do not support this */ +}; + +struct drm_event_crtc_sequence32 { + struct drm_event base; + __u64 user_data; + __s64 time_ns; + __u64 sequence; +}; + /** * struct drm_pending_vblank_event - pending vblank event tracking */ @@ -52,6 +68,10 @@ struct drm_pending_vblank_event { * @sequence: frame event should be triggered at */ u64 sequence; + /** + * @compat: This is a compat32 event + */ + bool compat; /** * @event: Actual event which will be sent to userspace. */ @@ -75,6 +95,9 @@ struct drm_pending_vblank_event { * @event.seq: Event payload for the MODE_QUEUEU_SEQUENCE IOCTL. */ struct drm_event_crtc_sequence seq; + + struct drm_event_vblank32 vbl32; + struct drm_event_crtc_sequence32 seq32; } event; };
diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h index de723566c5ae..5347b76005ee 100644 --- a/include/uapi/drm/drm.h +++ b/include/uapi/drm/drm.h @@ -494,7 +494,7 @@ enum drm_vblank_seq_type { struct drm_wait_vblank_request { enum drm_vblank_seq_type type; unsigned int sequence; - unsigned long signal; + __kernel_uintptr_t signal; };
struct drm_wait_vblank_reply { @@ -971,7 +971,7 @@ struct drm_crtc_queue_sequence { __u32 crtc_id; __u32 flags; __u64 sequence; /* on input, target sequence. on output, actual sequence */ - __u64 user_data; /* user data passed to event */ + __u64 user_data; /* user data passed to event */ };
#if defined(__cplusplus) @@ -1277,7 +1277,7 @@ struct drm_event {
struct drm_event_vblank { struct drm_event base; - __u64 user_data; + uintptr_t user_data; __u32 tv_sec; __u32 tv_usec; __u32 sequence;