diff mbox

[RFC] drm: split up drm_ioctl to allow drivers to hook into "core" functions

Message ID 20171231181509.4429-1-imirkin@alum.mit.edu (mailing list archive)
State New, archived
Headers show

Commit Message

Ilia Mirkin Dec. 31, 2017, 6:15 p.m. UTC
Currently there's no way to allow a driver to reimplement any ioctls
from the drm core. This can be desirable to, e.g., override fixed format
selection logic, without turning to a midlayer-like solution.

Signed-off-by: Ilia Mirkin <imirkin@alum.mit.edu>
---

I want drm_mode_addfb to pick a different format for depth=30 than the
one it currently selects. Flipping it for all drivers would break a
bunch of existing ones, so this enables a driver to take control.

Alternatively I can stash something into drm_device which specifies the
preferred depth=30 fb format. However from my cursory observations of
dri-devel discussions, midlayering is seen as a problem and not a
solution.

 drivers/gpu/drm/drm_ioctl.c | 36 ++++++++++++++++++++++++------------
 include/drm/drm_ioctl.h     |  2 ++
 2 files changed, 26 insertions(+), 12 deletions(-)

Comments

Ilia Mirkin Dec. 31, 2017, 6:40 p.m. UTC | #1
On Sun, Dec 31, 2017 at 1:15 PM, Ilia Mirkin <imirkin@alum.mit.edu> wrote:
> Currently there's no way to allow a driver to reimplement any ioctls
> from the drm core. This can be desirable to, e.g., override fixed format
> selection logic, without turning to a midlayer-like solution.
>
> Signed-off-by: Ilia Mirkin <imirkin@alum.mit.edu>
> ---
>
> I want drm_mode_addfb to pick a different format for depth=30 than the
> one it currently selects. Flipping it for all drivers would break a
> bunch of existing ones, so this enables a driver to take control.
>
> Alternatively I can stash something into drm_device which specifies the
> preferred depth=30 fb format. However from my cursory observations of
> dri-devel discussions, midlayering is seen as a problem and not a
> solution.

Ugh, of course this is turning into a disaster as well.
drm_mode_addfb2 isn't exported, so I have to copy all the
functionality into nouveau, or move it to drm_kms_helper or whatever.
The flag in drm_device approach is sounding a lot more palatable. Let
me know what the best way to proceed is.

This is all to fix a regression, btw, since previous to nouveau
becoming atomic this all worked fine -- it just looked at the
30bpp'ness of the fb and assumed. Now it actually cares about specific
formats, and we run into all these problems.

>
>  drivers/gpu/drm/drm_ioctl.c | 36 ++++++++++++++++++++++++------------
>  include/drm/drm_ioctl.h     |  2 ++
>  2 files changed, 26 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c
> index 4aafe4802099..698d69c6db0a 100644
> --- a/drivers/gpu/drm/drm_ioctl.c
> +++ b/drivers/gpu/drm/drm_ioctl.c
> @@ -767,12 +767,7 @@ long drm_ioctl(struct file *filp,
>         struct drm_file *file_priv = filp->private_data;
>         struct drm_device *dev;
>         const struct drm_ioctl_desc *ioctl = NULL;
> -       drm_ioctl_t *func;
>         unsigned int nr = DRM_IOCTL_NR(cmd);
> -       int retcode = -EINVAL;
> -       char stack_kdata[128];
> -       char *kdata = NULL;
> -       unsigned int in_size, out_size, drv_size, ksize;
>         bool is_driver_ioctl;
>
>         dev = file_priv->minor->dev;
> @@ -784,16 +779,33 @@ long drm_ioctl(struct file *filp,
>
>         if (is_driver_ioctl) {
>                 /* driver ioctl */
> -               if (nr - DRM_COMMAND_BASE >= dev->driver->num_ioctls)
> -                       goto err_i1;
> -               ioctl = &dev->driver->ioctls[nr - DRM_COMMAND_BASE];
> +               if (nr - DRM_COMMAND_BASE < dev->driver->num_ioctls)
> +                       ioctl = &dev->driver->ioctls[nr - DRM_COMMAND_BASE];
>         } else {
>                 /* core ioctl */
> -               if (nr >= DRM_CORE_IOCTL_COUNT)
> -                       goto err_i1;
> -               ioctl = &drm_ioctls[nr];
> +               if (nr < DRM_CORE_IOCTL_COUNT)
> +                       ioctl = &drm_ioctls[nr];
>         }
>
> +       return __drm_ioctl(filp, cmd, arg, ioctl);
> +}
> +EXPORT_SYMBOL(drm_ioctl);
> +
> +long __drm_ioctl(struct file *filp,
> +                unsigned int cmd, unsigned long arg,
> +                const struct drm_ioctl_desc *ioctl)
> +{
> +       struct drm_file *file_priv = filp->private_data;
> +       drm_ioctl_t *func;
> +       unsigned int nr = DRM_IOCTL_NR(cmd);
> +       int retcode = -EINVAL;
> +       char stack_kdata[128];
> +       char *kdata = NULL;
> +       unsigned int in_size, out_size, drv_size, ksize;
> +
> +       if (!ioctl)
> +               goto err_i1;
> +
>         drv_size = _IOC_SIZE(ioctl->cmd);
>         out_size = in_size = _IOC_SIZE(cmd);
>         if ((cmd & ioctl->cmd & IOC_IN) == 0)
> @@ -851,7 +863,7 @@ long drm_ioctl(struct file *filp,
>                 DRM_DEBUG("ret = %d\n", retcode);
>         return retcode;
>  }
> -EXPORT_SYMBOL(drm_ioctl);
> +EXPORT_SYMBOL(__drm_ioctl);
>
>  /**
>   * drm_ioctl_flags - Check for core ioctl and return ioctl permission flags
> diff --git a/include/drm/drm_ioctl.h b/include/drm/drm_ioctl.h
> index add42809642a..e08f8ea66f2a 100644
> --- a/include/drm/drm_ioctl.h
> +++ b/include/drm/drm_ioctl.h
> @@ -172,6 +172,8 @@ struct drm_ioctl_desc {
>
>  int drm_ioctl_permit(u32 flags, struct drm_file *file_priv);
>  long drm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
> +long __drm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg,
> +                const struct drm_ioctl_desc *ioctl);
>  long drm_ioctl_kernel(struct file *, drm_ioctl_t, void *, u32);
>  #ifdef CONFIG_COMPAT
>  long drm_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
> --
> 2.13.6
>
Daniel Vetter Jan. 9, 2018, 9:04 a.m. UTC | #2
On Sun, Dec 31, 2017 at 01:40:46PM -0500, Ilia Mirkin wrote:
> On Sun, Dec 31, 2017 at 1:15 PM, Ilia Mirkin <imirkin@alum.mit.edu> wrote:
> > Currently there's no way to allow a driver to reimplement any ioctls
> > from the drm core. This can be desirable to, e.g., override fixed format
> > selection logic, without turning to a midlayer-like solution.
> >
> > Signed-off-by: Ilia Mirkin <imirkin@alum.mit.edu>
> > ---
> >
> > I want drm_mode_addfb to pick a different format for depth=30 than the
> > one it currently selects. Flipping it for all drivers would break a
> > bunch of existing ones, so this enables a driver to take control.
> >
> > Alternatively I can stash something into drm_device which specifies the
> > preferred depth=30 fb format. However from my cursory observations of
> > dri-devel discussions, midlayering is seen as a problem and not a
> > solution.
> 
> Ugh, of course this is turning into a disaster as well.
> drm_mode_addfb2 isn't exported, so I have to copy all the
> functionality into nouveau, or move it to drm_kms_helper or whatever.
> The flag in drm_device approach is sounding a lot more palatable. Let
> me know what the best way to proceed is.
> 
> This is all to fix a regression, btw, since previous to nouveau
> becoming atomic this all worked fine -- it just looked at the
> 30bpp'ness of the fb and assumed. Now it actually cares about specific
> formats, and we run into all these problems.

Can you just submit the hack to the core addfb code so we know what
exactly goes wrong? Overwriting core ioctls is imo not cool at all :-)
-Daniel


> 
> >
> >  drivers/gpu/drm/drm_ioctl.c | 36 ++++++++++++++++++++++++------------
> >  include/drm/drm_ioctl.h     |  2 ++
> >  2 files changed, 26 insertions(+), 12 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c
> > index 4aafe4802099..698d69c6db0a 100644
> > --- a/drivers/gpu/drm/drm_ioctl.c
> > +++ b/drivers/gpu/drm/drm_ioctl.c
> > @@ -767,12 +767,7 @@ long drm_ioctl(struct file *filp,
> >         struct drm_file *file_priv = filp->private_data;
> >         struct drm_device *dev;
> >         const struct drm_ioctl_desc *ioctl = NULL;
> > -       drm_ioctl_t *func;
> >         unsigned int nr = DRM_IOCTL_NR(cmd);
> > -       int retcode = -EINVAL;
> > -       char stack_kdata[128];
> > -       char *kdata = NULL;
> > -       unsigned int in_size, out_size, drv_size, ksize;
> >         bool is_driver_ioctl;
> >
> >         dev = file_priv->minor->dev;
> > @@ -784,16 +779,33 @@ long drm_ioctl(struct file *filp,
> >
> >         if (is_driver_ioctl) {
> >                 /* driver ioctl */
> > -               if (nr - DRM_COMMAND_BASE >= dev->driver->num_ioctls)
> > -                       goto err_i1;
> > -               ioctl = &dev->driver->ioctls[nr - DRM_COMMAND_BASE];
> > +               if (nr - DRM_COMMAND_BASE < dev->driver->num_ioctls)
> > +                       ioctl = &dev->driver->ioctls[nr - DRM_COMMAND_BASE];
> >         } else {
> >                 /* core ioctl */
> > -               if (nr >= DRM_CORE_IOCTL_COUNT)
> > -                       goto err_i1;
> > -               ioctl = &drm_ioctls[nr];
> > +               if (nr < DRM_CORE_IOCTL_COUNT)
> > +                       ioctl = &drm_ioctls[nr];
> >         }
> >
> > +       return __drm_ioctl(filp, cmd, arg, ioctl);
> > +}
> > +EXPORT_SYMBOL(drm_ioctl);
> > +
> > +long __drm_ioctl(struct file *filp,
> > +                unsigned int cmd, unsigned long arg,
> > +                const struct drm_ioctl_desc *ioctl)
> > +{
> > +       struct drm_file *file_priv = filp->private_data;
> > +       drm_ioctl_t *func;
> > +       unsigned int nr = DRM_IOCTL_NR(cmd);
> > +       int retcode = -EINVAL;
> > +       char stack_kdata[128];
> > +       char *kdata = NULL;
> > +       unsigned int in_size, out_size, drv_size, ksize;
> > +
> > +       if (!ioctl)
> > +               goto err_i1;
> > +
> >         drv_size = _IOC_SIZE(ioctl->cmd);
> >         out_size = in_size = _IOC_SIZE(cmd);
> >         if ((cmd & ioctl->cmd & IOC_IN) == 0)
> > @@ -851,7 +863,7 @@ long drm_ioctl(struct file *filp,
> >                 DRM_DEBUG("ret = %d\n", retcode);
> >         return retcode;
> >  }
> > -EXPORT_SYMBOL(drm_ioctl);
> > +EXPORT_SYMBOL(__drm_ioctl);
> >
> >  /**
> >   * drm_ioctl_flags - Check for core ioctl and return ioctl permission flags
> > diff --git a/include/drm/drm_ioctl.h b/include/drm/drm_ioctl.h
> > index add42809642a..e08f8ea66f2a 100644
> > --- a/include/drm/drm_ioctl.h
> > +++ b/include/drm/drm_ioctl.h
> > @@ -172,6 +172,8 @@ struct drm_ioctl_desc {
> >
> >  int drm_ioctl_permit(u32 flags, struct drm_file *file_priv);
> >  long drm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
> > +long __drm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg,
> > +                const struct drm_ioctl_desc *ioctl);
> >  long drm_ioctl_kernel(struct file *, drm_ioctl_t, void *, u32);
> >  #ifdef CONFIG_COMPAT
> >  long drm_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
> > --
> > 2.13.6
> >
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel
diff mbox

Patch

diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c
index 4aafe4802099..698d69c6db0a 100644
--- a/drivers/gpu/drm/drm_ioctl.c
+++ b/drivers/gpu/drm/drm_ioctl.c
@@ -767,12 +767,7 @@  long drm_ioctl(struct file *filp,
 	struct drm_file *file_priv = filp->private_data;
 	struct drm_device *dev;
 	const struct drm_ioctl_desc *ioctl = NULL;
-	drm_ioctl_t *func;
 	unsigned int nr = DRM_IOCTL_NR(cmd);
-	int retcode = -EINVAL;
-	char stack_kdata[128];
-	char *kdata = NULL;
-	unsigned int in_size, out_size, drv_size, ksize;
 	bool is_driver_ioctl;
 
 	dev = file_priv->minor->dev;
@@ -784,16 +779,33 @@  long drm_ioctl(struct file *filp,
 
 	if (is_driver_ioctl) {
 		/* driver ioctl */
-		if (nr - DRM_COMMAND_BASE >= dev->driver->num_ioctls)
-			goto err_i1;
-		ioctl = &dev->driver->ioctls[nr - DRM_COMMAND_BASE];
+		if (nr - DRM_COMMAND_BASE < dev->driver->num_ioctls)
+			ioctl = &dev->driver->ioctls[nr - DRM_COMMAND_BASE];
 	} else {
 		/* core ioctl */
-		if (nr >= DRM_CORE_IOCTL_COUNT)
-			goto err_i1;
-		ioctl = &drm_ioctls[nr];
+		if (nr < DRM_CORE_IOCTL_COUNT)
+			ioctl = &drm_ioctls[nr];
 	}
 
+	return __drm_ioctl(filp, cmd, arg, ioctl);
+}
+EXPORT_SYMBOL(drm_ioctl);
+
+long __drm_ioctl(struct file *filp,
+		 unsigned int cmd, unsigned long arg,
+		 const struct drm_ioctl_desc *ioctl)
+{
+	struct drm_file *file_priv = filp->private_data;
+	drm_ioctl_t *func;
+	unsigned int nr = DRM_IOCTL_NR(cmd);
+	int retcode = -EINVAL;
+	char stack_kdata[128];
+	char *kdata = NULL;
+	unsigned int in_size, out_size, drv_size, ksize;
+
+	if (!ioctl)
+		goto err_i1;
+
 	drv_size = _IOC_SIZE(ioctl->cmd);
 	out_size = in_size = _IOC_SIZE(cmd);
 	if ((cmd & ioctl->cmd & IOC_IN) == 0)
@@ -851,7 +863,7 @@  long drm_ioctl(struct file *filp,
 		DRM_DEBUG("ret = %d\n", retcode);
 	return retcode;
 }
-EXPORT_SYMBOL(drm_ioctl);
+EXPORT_SYMBOL(__drm_ioctl);
 
 /**
  * drm_ioctl_flags - Check for core ioctl and return ioctl permission flags
diff --git a/include/drm/drm_ioctl.h b/include/drm/drm_ioctl.h
index add42809642a..e08f8ea66f2a 100644
--- a/include/drm/drm_ioctl.h
+++ b/include/drm/drm_ioctl.h
@@ -172,6 +172,8 @@  struct drm_ioctl_desc {
 
 int drm_ioctl_permit(u32 flags, struct drm_file *file_priv);
 long drm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
+long __drm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg,
+		 const struct drm_ioctl_desc *ioctl);
 long drm_ioctl_kernel(struct file *, drm_ioctl_t, void *, u32);
 #ifdef CONFIG_COMPAT
 long drm_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);