[PATCH 4/5] gpu: host1x: Provide a proper struct bus_type

Sean Paul seanpaul at chromium.org
Mon Jan 5 07:47:07 PST 2015


On Fri, Dec 19, 2014 at 10:24 AM, Thierry Reding
<thierry.reding at gmail.com> wrote:
> From: Thierry Reding <treding at nvidia.com>
>
> Previously the struct bus_type exported by the host1x infrastructure was
> only a very basic skeleton. Turn that implementation into a more full-
> fledged bus to support proper probe ordering and power management.
>
> Note that the bus infrastructure needs to be available before any of the
> drivers can be registered, so the bus needs to be registered before the
> host1x module. Otherwise drivers could be registered before the module
> is loaded and trigger a BUG_ON() in driver_register(). To ensure the bus
> infrastructure is always there, always build the code into the kernel
> when enabled and register it with a postcore initcall.
>
> Signed-off-by: Thierry Reding <treding at nvidia.com>


This is a nice improvement.

Reviewed-by: Sean Paul <seanpaul at chromium.org>


> ---
>  drivers/gpu/drm/tegra/drm.c |   4 +-
>  drivers/gpu/host1x/Makefile |   3 +-
>  drivers/gpu/host1x/bus.c    | 115 +++++++++++++++++++++++++++++++-------------
>  drivers/gpu/host1x/bus.h    |   3 --
>  drivers/gpu/host1x/dev.c    |   9 +---
>  include/linux/host1x.h      |  18 +++++--
>  6 files changed, 102 insertions(+), 50 deletions(-)
>
> diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c
> index e549afeece1f..272c2dca3536 100644
> --- a/drivers/gpu/drm/tegra/drm.c
> +++ b/drivers/gpu/drm/tegra/drm.c
> @@ -908,7 +908,9 @@ static const struct of_device_id host1x_drm_subdevs[] = {
>  };
>
>  static struct host1x_driver host1x_drm_driver = {
> -       .name = "drm",
> +       .driver = {
> +               .name = "drm",
> +       },
>         .probe = host1x_drm_probe,
>         .remove = host1x_drm_remove,
>         .subdevs = host1x_drm_subdevs,
> diff --git a/drivers/gpu/host1x/Makefile b/drivers/gpu/host1x/Makefile
> index c1189f004441..a3e667a1b6f5 100644
> --- a/drivers/gpu/host1x/Makefile
> +++ b/drivers/gpu/host1x/Makefile
> @@ -1,5 +1,4 @@
>  host1x-y = \
> -       bus.o \
>         syncpt.o \
>         dev.o \
>         intr.o \
> @@ -13,3 +12,5 @@ host1x-y = \
>         hw/host1x04.o
>
>  obj-$(CONFIG_TEGRA_HOST1X) += host1x.o
> +
> +obj-y += bus.o
> diff --git a/drivers/gpu/host1x/bus.c b/drivers/gpu/host1x/bus.c
> index 0b52f0ea8871..28630a5e9397 100644
> --- a/drivers/gpu/host1x/bus.c
> +++ b/drivers/gpu/host1x/bus.c
> @@ -72,13 +72,14 @@ static void host1x_subdev_del(struct host1x_subdev *subdev)
>  /**
>   * host1x_device_parse_dt() - scan device tree and add matching subdevices
>   */
> -static int host1x_device_parse_dt(struct host1x_device *device)
> +static int host1x_device_parse_dt(struct host1x_device *device,
> +                                 struct host1x_driver *driver)
>  {
>         struct device_node *np;
>         int err;
>
>         for_each_child_of_node(device->dev.parent->of_node, np) {
> -               if (of_match_node(device->driver->subdevs, np) &&
> +               if (of_match_node(driver->subdevs, np) &&
>                     of_device_is_available(np)) {
>                         err = host1x_subdev_add(device, np);
>                         if (err < 0)
> @@ -109,17 +110,12 @@ static void host1x_subdev_register(struct host1x_device *device,
>         mutex_unlock(&device->clients_lock);
>         mutex_unlock(&device->subdevs_lock);
>
> -       /*
> -        * When all subdevices have been registered, the composite device is
> -        * ready to be probed.
> -        */
>         if (list_empty(&device->subdevs)) {
> -               err = device->driver->probe(device);
> +               err = device_add(&device->dev);
>                 if (err < 0)
> -                       dev_err(&device->dev, "probe failed for %ps: %d\n",
> -                               device->driver, err);
> +                       dev_err(&device->dev, "failed to add: %d\n", err);
>                 else
> -                       device->bound = true;
> +                       device->registered = true;
>         }
>  }
>
> @@ -127,18 +123,16 @@ static void __host1x_subdev_unregister(struct host1x_device *device,
>                                        struct host1x_subdev *subdev)
>  {
>         struct host1x_client *client = subdev->client;
> -       int err;
>
>         /*
>          * If all subdevices have been activated, we're about to remove the
>          * first active subdevice, so unload the driver first.
>          */
> -       if (list_empty(&device->subdevs) && device->bound) {
> -               err = device->driver->remove(device);
> -               if (err < 0)
> -                       dev_err(&device->dev, "remove failed: %d\n", err);
> -
> -               device->bound = false;
> +       if (list_empty(&device->subdevs)) {
> +               if (device->registered) {
> +                       device->registered = false;
> +                       device_del(&device->dev);
> +               }
>         }
>
>         /*
> @@ -265,19 +259,65 @@ static int host1x_del_client(struct host1x *host1x,
>         return -ENODEV;
>  }
>
> +static int host1x_device_match(struct device *dev, struct device_driver *drv)
> +{
> +       return strcmp(dev_name(dev), drv->name) == 0;
> +}
> +
> +static int host1x_device_probe(struct device *dev)
> +{
> +       struct host1x_driver *driver = to_host1x_driver(dev->driver);
> +       struct host1x_device *device = to_host1x_device(dev);
> +
> +       if (driver->probe)
> +               return driver->probe(device);
> +
> +       return 0;
> +}
> +
> +static int host1x_device_remove(struct device *dev)
> +{
> +       struct host1x_driver *driver = to_host1x_driver(dev->driver);
> +       struct host1x_device *device = to_host1x_device(dev);
> +
> +       if (driver->remove)
> +               return driver->remove(device);
> +
> +       return 0;
> +}
> +
> +static void host1x_device_shutdown(struct device *dev)
> +{
> +       struct host1x_driver *driver = to_host1x_driver(dev->driver);
> +       struct host1x_device *device = to_host1x_device(dev);
> +
> +       if (driver->shutdown)
> +               driver->shutdown(device);
> +}
> +
> +static const struct dev_pm_ops host1x_device_pm_ops = {
> +       .suspend = pm_generic_suspend,
> +       .resume = pm_generic_resume,
> +       .freeze = pm_generic_freeze,
> +       .thaw = pm_generic_thaw,
> +       .poweroff = pm_generic_poweroff,
> +       .restore = pm_generic_restore,
> +};
> +
>  static struct bus_type host1x_bus_type = {
>         .name = "host1x",
> +       .match = host1x_device_match,
> +       .probe = host1x_device_probe,
> +       .remove = host1x_device_remove,
> +       .shutdown = host1x_device_shutdown,
> +       .pm = &host1x_device_pm_ops,
>  };
>
> -int host1x_bus_init(void)
> +static int host1x_bus_init(void)
>  {
>         return bus_register(&host1x_bus_type);
>  }
> -
> -void host1x_bus_exit(void)
> -{
> -       bus_unregister(&host1x_bus_type);
> -}
> +postcore_initcall(host1x_bus_init);
>
>  static void __host1x_device_del(struct host1x_device *device)
>  {
> @@ -347,6 +387,8 @@ static int host1x_device_add(struct host1x *host1x,
>         if (!device)
>                 return -ENOMEM;
>
> +       device_initialize(&device->dev);
> +
>         mutex_init(&device->subdevs_lock);
>         INIT_LIST_HEAD(&device->subdevs);
>         INIT_LIST_HEAD(&device->active);
> @@ -357,18 +399,14 @@ static int host1x_device_add(struct host1x *host1x,
>
>         device->dev.coherent_dma_mask = host1x->dev->coherent_dma_mask;
>         device->dev.dma_mask = &device->dev.coherent_dma_mask;
> +       dev_set_name(&device->dev, "%s", driver->driver.name);
>         device->dev.release = host1x_device_release;
> -       dev_set_name(&device->dev, "%s", driver->name);
>         device->dev.bus = &host1x_bus_type;
>         device->dev.parent = host1x->dev;
>
> -       err = device_register(&device->dev);
> -       if (err < 0)
> -               return err;
> -
> -       err = host1x_device_parse_dt(device);
> +       err = host1x_device_parse_dt(device, driver);
>         if (err < 0) {
> -               device_unregister(&device->dev);
> +               kfree(device);
>                 return err;
>         }
>
> @@ -399,7 +437,12 @@ static int host1x_device_add(struct host1x *host1x,
>  static void host1x_device_del(struct host1x *host1x,
>                               struct host1x_device *device)
>  {
> -       device_unregister(&device->dev);
> +       if (device->registered) {
> +               device->registered = false;
> +               device_del(&device->dev);
> +       }
> +
> +       put_device(&device->dev);
>  }
>
>  static void host1x_attach_driver(struct host1x *host1x,
> @@ -474,7 +517,8 @@ int host1x_unregister(struct host1x *host1x)
>         return 0;
>  }
>
> -int host1x_driver_register(struct host1x_driver *driver)
> +int host1x_driver_register_full(struct host1x_driver *driver,
> +                               struct module *owner)
>  {
>         struct host1x *host1x;
>
> @@ -491,9 +535,12 @@ int host1x_driver_register(struct host1x_driver *driver)
>
>         mutex_unlock(&devices_lock);
>
> -       return 0;
> +       driver->driver.bus = &host1x_bus_type;
> +       driver->driver.owner = owner;
> +
> +       return driver_register(&driver->driver);
>  }
> -EXPORT_SYMBOL(host1x_driver_register);
> +EXPORT_SYMBOL(host1x_driver_register_full);
>
>  void host1x_driver_unregister(struct host1x_driver *driver)
>  {
> diff --git a/drivers/gpu/host1x/bus.h b/drivers/gpu/host1x/bus.h
> index 4099e99212c8..c7d976e8ead7 100644
> --- a/drivers/gpu/host1x/bus.h
> +++ b/drivers/gpu/host1x/bus.h
> @@ -20,9 +20,6 @@
>
>  struct host1x;
>
> -int host1x_bus_init(void);
> -void host1x_bus_exit(void);
> -
>  int host1x_register(struct host1x *host1x);
>  int host1x_unregister(struct host1x *host1x);
>
> diff --git a/drivers/gpu/host1x/dev.c b/drivers/gpu/host1x/dev.c
> index 2529908d304b..18b36410347d 100644
> --- a/drivers/gpu/host1x/dev.c
> +++ b/drivers/gpu/host1x/dev.c
> @@ -216,13 +216,9 @@ static int __init tegra_host1x_init(void)
>  {
>         int err;
>
> -       err = host1x_bus_init();
> -       if (err < 0)
> -               return err;
> -
>         err = platform_driver_register(&tegra_host1x_driver);
>         if (err < 0)
> -               goto unregister_bus;
> +               return err;
>
>         err = platform_driver_register(&tegra_mipi_driver);
>         if (err < 0)
> @@ -232,8 +228,6 @@ static int __init tegra_host1x_init(void)
>
>  unregister_host1x:
>         platform_driver_unregister(&tegra_host1x_driver);
> -unregister_bus:
> -       host1x_bus_exit();
>         return err;
>  }
>  module_init(tegra_host1x_init);
> @@ -242,7 +236,6 @@ static void __exit tegra_host1x_exit(void)
>  {
>         platform_driver_unregister(&tegra_mipi_driver);
>         platform_driver_unregister(&tegra_host1x_driver);
> -       host1x_bus_exit();
>  }
>  module_exit(tegra_host1x_exit);
>
> diff --git a/include/linux/host1x.h b/include/linux/host1x.h
> index 7890b553d12e..464f33814a94 100644
> --- a/include/linux/host1x.h
> +++ b/include/linux/host1x.h
> @@ -250,17 +250,29 @@ void host1x_job_unpin(struct host1x_job *job);
>  struct host1x_device;
>
>  struct host1x_driver {
> +       struct device_driver driver;
> +
>         const struct of_device_id *subdevs;
>         struct list_head list;
> -       const char *name;
>
>         int (*probe)(struct host1x_device *device);
>         int (*remove)(struct host1x_device *device);
> +       void (*shutdown)(struct host1x_device *device);
>  };
>
> -int host1x_driver_register(struct host1x_driver *driver);
> +static inline struct host1x_driver *
> +to_host1x_driver(struct device_driver *driver)
> +{
> +       return container_of(driver, struct host1x_driver, driver);
> +}
> +
> +int host1x_driver_register_full(struct host1x_driver *driver,
> +                               struct module *owner);
>  void host1x_driver_unregister(struct host1x_driver *driver);
>
> +#define host1x_driver_register(driver) \
> +       host1x_driver_register_full(driver, THIS_MODULE)
> +
>  struct host1x_device {
>         struct host1x_driver *driver;
>         struct list_head list;
> @@ -273,7 +285,7 @@ struct host1x_device {
>         struct mutex clients_lock;
>         struct list_head clients;
>
> -       bool bound;
> +       bool registered;
>  };
>
>  static inline struct host1x_device *to_host1x_device(struct device *dev)
> --
> 2.1.3
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-tegra" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


More information about the dri-devel mailing list