aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorThierry Reding <treding@nvidia.com>2014-12-18 09:29:14 -0500
committerThierry Reding <treding@nvidia.com>2015-01-27 04:09:14 -0500
commitf4c5cf88fbd50e4779042268947b2e2f90c20484 (patch)
tree79a50b0a3ed21314f1893a7c9bea685df976b6d2 /drivers/gpu
parent99d2cd81d7261e6ddd325189134faf752206bfe7 (diff)
gpu: host1x: Provide a proper struct bus_type
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. This is automatically ensured if all drivers are built as loadable modules (via symbol dependencies). If all drivers are built-in there are no such guarantees and the link order determines the initcall ordering. Adjust drivers/gpu/Makefile to make sure that the host1x bus infrastructure is initialized prior to any of its users (only drm/tegra currently). v2: Fix building host1x and tegra-drm as modules Reported-by: Dave Airlie <airlied@gmail.com> Reviewed-by: Sean Paul <seanpaul@chromium.org> Reviewed-by: Mark Zhang <markz@nvidia.com> Signed-off-by: Thierry Reding <treding@nvidia.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/Makefile5
-rw-r--r--drivers/gpu/drm/tegra/drm.c4
-rw-r--r--drivers/gpu/host1x/bus.c111
-rw-r--r--drivers/gpu/host1x/bus.h4
-rw-r--r--drivers/gpu/host1x/dev.c6
5 files changed, 88 insertions, 42 deletions
diff --git a/drivers/gpu/Makefile b/drivers/gpu/Makefile
index 70da9eb52a42..e9ed439a5b65 100644
--- a/drivers/gpu/Makefile
+++ b/drivers/gpu/Makefile
@@ -1,3 +1,6 @@
1obj-y += drm/ vga/ 1# drm/tegra depends on host1x, so if both drivers are built-in care must be
2# taken to initialize them in the correct order. Link order is the only way
3# to ensure this currently.
2obj-$(CONFIG_TEGRA_HOST1X) += host1x/ 4obj-$(CONFIG_TEGRA_HOST1X) += host1x/
5obj-y += drm/ vga/
3obj-$(CONFIG_IMX_IPUV3_CORE) += ipu-v3/ 6obj-$(CONFIG_IMX_IPUV3_CORE) += ipu-v3/
diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c
index d4f827593dfa..a0c18ae79029 100644
--- a/drivers/gpu/drm/tegra/drm.c
+++ b/drivers/gpu/drm/tegra/drm.c
@@ -912,7 +912,9 @@ static const struct of_device_id host1x_drm_subdevs[] = {
912}; 912};
913 913
914static struct host1x_driver host1x_drm_driver = { 914static struct host1x_driver host1x_drm_driver = {
915 .name = "drm", 915 .driver = {
916 .name = "drm",
917 },
916 .probe = host1x_drm_probe, 918 .probe = host1x_drm_probe,
917 .remove = host1x_drm_remove, 919 .remove = host1x_drm_remove,
918 .subdevs = host1x_drm_subdevs, 920 .subdevs = host1x_drm_subdevs,
diff --git a/drivers/gpu/host1x/bus.c b/drivers/gpu/host1x/bus.c
index 0b52f0ea8871..4a99c6416e6a 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)
72/** 72/**
73 * host1x_device_parse_dt() - scan device tree and add matching subdevices 73 * host1x_device_parse_dt() - scan device tree and add matching subdevices
74 */ 74 */
75static int host1x_device_parse_dt(struct host1x_device *device) 75static int host1x_device_parse_dt(struct host1x_device *device,
76 struct host1x_driver *driver)
76{ 77{
77 struct device_node *np; 78 struct device_node *np;
78 int err; 79 int err;
79 80
80 for_each_child_of_node(device->dev.parent->of_node, np) { 81 for_each_child_of_node(device->dev.parent->of_node, np) {
81 if (of_match_node(device->driver->subdevs, np) && 82 if (of_match_node(driver->subdevs, np) &&
82 of_device_is_available(np)) { 83 of_device_is_available(np)) {
83 err = host1x_subdev_add(device, np); 84 err = host1x_subdev_add(device, np);
84 if (err < 0) 85 if (err < 0)
@@ -109,17 +110,12 @@ static void host1x_subdev_register(struct host1x_device *device,
109 mutex_unlock(&device->clients_lock); 110 mutex_unlock(&device->clients_lock);
110 mutex_unlock(&device->subdevs_lock); 111 mutex_unlock(&device->subdevs_lock);
111 112
112 /*
113 * When all subdevices have been registered, the composite device is
114 * ready to be probed.
115 */
116 if (list_empty(&device->subdevs)) { 113 if (list_empty(&device->subdevs)) {
117 err = device->driver->probe(device); 114 err = device_add(&device->dev);
118 if (err < 0) 115 if (err < 0)
119 dev_err(&device->dev, "probe failed for %ps: %d\n", 116 dev_err(&device->dev, "failed to add: %d\n", err);
120 device->driver, err);
121 else 117 else
122 device->bound = true; 118 device->registered = true;
123 } 119 }
124} 120}
125 121
@@ -127,18 +123,16 @@ static void __host1x_subdev_unregister(struct host1x_device *device,
127 struct host1x_subdev *subdev) 123 struct host1x_subdev *subdev)
128{ 124{
129 struct host1x_client *client = subdev->client; 125 struct host1x_client *client = subdev->client;
130 int err;
131 126
132 /* 127 /*
133 * If all subdevices have been activated, we're about to remove the 128 * If all subdevices have been activated, we're about to remove the
134 * first active subdevice, so unload the driver first. 129 * first active subdevice, so unload the driver first.
135 */ 130 */
136 if (list_empty(&device->subdevs) && device->bound) { 131 if (list_empty(&device->subdevs)) {
137 err = device->driver->remove(device); 132 if (device->registered) {
138 if (err < 0) 133 device->registered = false;
139 dev_err(&device->dev, "remove failed: %d\n", err); 134 device_del(&device->dev);
140 135 }
141 device->bound = false;
142 } 136 }
143 137
144 /* 138 /*
@@ -265,20 +259,60 @@ static int host1x_del_client(struct host1x *host1x,
265 return -ENODEV; 259 return -ENODEV;
266} 260}
267 261
268static struct bus_type host1x_bus_type = { 262static int host1x_device_match(struct device *dev, struct device_driver *drv)
269 .name = "host1x", 263{
270}; 264 return strcmp(dev_name(dev), drv->name) == 0;
265}
271 266
272int host1x_bus_init(void) 267static int host1x_device_probe(struct device *dev)
273{ 268{
274 return bus_register(&host1x_bus_type); 269 struct host1x_driver *driver = to_host1x_driver(dev->driver);
270 struct host1x_device *device = to_host1x_device(dev);
271
272 if (driver->probe)
273 return driver->probe(device);
274
275 return 0;
275} 276}
276 277
277void host1x_bus_exit(void) 278static int host1x_device_remove(struct device *dev)
278{ 279{
279 bus_unregister(&host1x_bus_type); 280 struct host1x_driver *driver = to_host1x_driver(dev->driver);
281 struct host1x_device *device = to_host1x_device(dev);
282
283 if (driver->remove)
284 return driver->remove(device);
285
286 return 0;
280} 287}
281 288
289static void host1x_device_shutdown(struct device *dev)
290{
291 struct host1x_driver *driver = to_host1x_driver(dev->driver);
292 struct host1x_device *device = to_host1x_device(dev);
293
294 if (driver->shutdown)
295 driver->shutdown(device);
296}
297
298static const struct dev_pm_ops host1x_device_pm_ops = {
299 .suspend = pm_generic_suspend,
300 .resume = pm_generic_resume,
301 .freeze = pm_generic_freeze,
302 .thaw = pm_generic_thaw,
303 .poweroff = pm_generic_poweroff,
304 .restore = pm_generic_restore,
305};
306
307struct bus_type host1x_bus_type = {
308 .name = "host1x",
309 .match = host1x_device_match,
310 .probe = host1x_device_probe,
311 .remove = host1x_device_remove,
312 .shutdown = host1x_device_shutdown,
313 .pm = &host1x_device_pm_ops,
314};
315
282static void __host1x_device_del(struct host1x_device *device) 316static void __host1x_device_del(struct host1x_device *device)
283{ 317{
284 struct host1x_subdev *subdev, *sd; 318 struct host1x_subdev *subdev, *sd;
@@ -347,6 +381,8 @@ static int host1x_device_add(struct host1x *host1x,
347 if (!device) 381 if (!device)
348 return -ENOMEM; 382 return -ENOMEM;
349 383
384 device_initialize(&device->dev);
385
350 mutex_init(&device->subdevs_lock); 386 mutex_init(&device->subdevs_lock);
351 INIT_LIST_HEAD(&device->subdevs); 387 INIT_LIST_HEAD(&device->subdevs);
352 INIT_LIST_HEAD(&device->active); 388 INIT_LIST_HEAD(&device->active);
@@ -357,18 +393,14 @@ static int host1x_device_add(struct host1x *host1x,
357 393
358 device->dev.coherent_dma_mask = host1x->dev->coherent_dma_mask; 394 device->dev.coherent_dma_mask = host1x->dev->coherent_dma_mask;
359 device->dev.dma_mask = &device->dev.coherent_dma_mask; 395 device->dev.dma_mask = &device->dev.coherent_dma_mask;
396 dev_set_name(&device->dev, "%s", driver->driver.name);
360 device->dev.release = host1x_device_release; 397 device->dev.release = host1x_device_release;
361 dev_set_name(&device->dev, "%s", driver->name);
362 device->dev.bus = &host1x_bus_type; 398 device->dev.bus = &host1x_bus_type;
363 device->dev.parent = host1x->dev; 399 device->dev.parent = host1x->dev;
364 400
365 err = device_register(&device->dev); 401 err = host1x_device_parse_dt(device, driver);
366 if (err < 0)
367 return err;
368
369 err = host1x_device_parse_dt(device);
370 if (err < 0) { 402 if (err < 0) {
371 device_unregister(&device->dev); 403 kfree(device);
372 return err; 404 return err;
373 } 405 }
374 406
@@ -399,7 +431,12 @@ static int host1x_device_add(struct host1x *host1x,
399static void host1x_device_del(struct host1x *host1x, 431static void host1x_device_del(struct host1x *host1x,
400 struct host1x_device *device) 432 struct host1x_device *device)
401{ 433{
402 device_unregister(&device->dev); 434 if (device->registered) {
435 device->registered = false;
436 device_del(&device->dev);
437 }
438
439 put_device(&device->dev);
403} 440}
404 441
405static void host1x_attach_driver(struct host1x *host1x, 442static void host1x_attach_driver(struct host1x *host1x,
@@ -474,7 +511,8 @@ int host1x_unregister(struct host1x *host1x)
474 return 0; 511 return 0;
475} 512}
476 513
477int host1x_driver_register(struct host1x_driver *driver) 514int host1x_driver_register_full(struct host1x_driver *driver,
515 struct module *owner)
478{ 516{
479 struct host1x *host1x; 517 struct host1x *host1x;
480 518
@@ -491,9 +529,12 @@ int host1x_driver_register(struct host1x_driver *driver)
491 529
492 mutex_unlock(&devices_lock); 530 mutex_unlock(&devices_lock);
493 531
494 return 0; 532 driver->driver.bus = &host1x_bus_type;
533 driver->driver.owner = owner;
534
535 return driver_register(&driver->driver);
495} 536}
496EXPORT_SYMBOL(host1x_driver_register); 537EXPORT_SYMBOL(host1x_driver_register_full);
497 538
498void host1x_driver_unregister(struct host1x_driver *driver) 539void host1x_driver_unregister(struct host1x_driver *driver)
499{ 540{
diff --git a/drivers/gpu/host1x/bus.h b/drivers/gpu/host1x/bus.h
index 4099e99212c8..88fb1c4aac68 100644
--- a/drivers/gpu/host1x/bus.h
+++ b/drivers/gpu/host1x/bus.h
@@ -18,10 +18,10 @@
18#ifndef HOST1X_BUS_H 18#ifndef HOST1X_BUS_H
19#define HOST1X_BUS_H 19#define HOST1X_BUS_H
20 20
21struct bus_type;
21struct host1x; 22struct host1x;
22 23
23int host1x_bus_init(void); 24extern struct bus_type host1x_bus_type;
24void host1x_bus_exit(void);
25 25
26int host1x_register(struct host1x *host1x); 26int host1x_register(struct host1x *host1x);
27int host1x_unregister(struct host1x *host1x); 27int host1x_unregister(struct host1x *host1x);
diff --git a/drivers/gpu/host1x/dev.c b/drivers/gpu/host1x/dev.c
index 2529908d304b..53d3d1d45b48 100644
--- a/drivers/gpu/host1x/dev.c
+++ b/drivers/gpu/host1x/dev.c
@@ -216,7 +216,7 @@ static int __init tegra_host1x_init(void)
216{ 216{
217 int err; 217 int err;
218 218
219 err = host1x_bus_init(); 219 err = bus_register(&host1x_bus_type);
220 if (err < 0) 220 if (err < 0)
221 return err; 221 return err;
222 222
@@ -233,7 +233,7 @@ static int __init tegra_host1x_init(void)
233unregister_host1x: 233unregister_host1x:
234 platform_driver_unregister(&tegra_host1x_driver); 234 platform_driver_unregister(&tegra_host1x_driver);
235unregister_bus: 235unregister_bus:
236 host1x_bus_exit(); 236 bus_unregister(&host1x_bus_type);
237 return err; 237 return err;
238} 238}
239module_init(tegra_host1x_init); 239module_init(tegra_host1x_init);
@@ -242,7 +242,7 @@ static void __exit tegra_host1x_exit(void)
242{ 242{
243 platform_driver_unregister(&tegra_mipi_driver); 243 platform_driver_unregister(&tegra_mipi_driver);
244 platform_driver_unregister(&tegra_host1x_driver); 244 platform_driver_unregister(&tegra_host1x_driver);
245 host1x_bus_exit(); 245 bus_unregister(&host1x_bus_type);
246} 246}
247module_exit(tegra_host1x_exit); 247module_exit(tegra_host1x_exit);
248 248