xref: /openbmc/linux/drivers/gpu/host1x/bus.c (revision e0d77d0f38aa60ca61b3ce6e60d64fad2aa0853d)
19952f691SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2776dc384SThierry Reding /*
3776dc384SThierry Reding  * Copyright (C) 2012 Avionic Design GmbH
4776dc384SThierry Reding  * Copyright (C) 2012-2013, NVIDIA Corporation
5776dc384SThierry Reding  */
6776dc384SThierry Reding 
7f67524caSThierry Reding #include <linux/debugfs.h>
84abfc0e3SRobin Murphy #include <linux/dma-mapping.h>
9776dc384SThierry Reding #include <linux/host1x.h>
10776dc384SThierry Reding #include <linux/of.h>
11f67524caSThierry Reding #include <linux/seq_file.h>
12776dc384SThierry Reding #include <linux/slab.h>
13c95469aaSAlexandre Courbot #include <linux/of_device.h>
14776dc384SThierry Reding 
15d24b2898SThierry Reding #include "bus.h"
16776dc384SThierry Reding #include "dev.h"
17776dc384SThierry Reding 
18776dc384SThierry Reding static DEFINE_MUTEX(clients_lock);
19776dc384SThierry Reding static LIST_HEAD(clients);
20776dc384SThierry Reding 
21776dc384SThierry Reding static DEFINE_MUTEX(drivers_lock);
22776dc384SThierry Reding static LIST_HEAD(drivers);
23776dc384SThierry Reding 
24776dc384SThierry Reding static DEFINE_MUTEX(devices_lock);
25776dc384SThierry Reding static LIST_HEAD(devices);
26776dc384SThierry Reding 
27776dc384SThierry Reding struct host1x_subdev {
28776dc384SThierry Reding 	struct host1x_client *client;
29776dc384SThierry Reding 	struct device_node *np;
30776dc384SThierry Reding 	struct list_head list;
31776dc384SThierry Reding };
32776dc384SThierry Reding 
33776dc384SThierry Reding /**
34776dc384SThierry Reding  * host1x_subdev_add() - add a new subdevice with an associated device node
35466749f1SThierry Reding  * @device: host1x device to add the subdevice to
36d2a58fd1SLee Jones  * @driver: host1x driver containing the subdevices
37466749f1SThierry Reding  * @np: device node
38776dc384SThierry Reding  */
host1x_subdev_add(struct host1x_device * device,struct host1x_driver * driver,struct device_node * np)39776dc384SThierry Reding static int host1x_subdev_add(struct host1x_device *device,
4025ae30d2SThierry Reding 			     struct host1x_driver *driver,
41776dc384SThierry Reding 			     struct device_node *np)
42776dc384SThierry Reding {
43776dc384SThierry Reding 	struct host1x_subdev *subdev;
4425ae30d2SThierry Reding 	struct device_node *child;
4525ae30d2SThierry Reding 	int err;
46776dc384SThierry Reding 
47776dc384SThierry Reding 	subdev = kzalloc(sizeof(*subdev), GFP_KERNEL);
48776dc384SThierry Reding 	if (!subdev)
49776dc384SThierry Reding 		return -ENOMEM;
50776dc384SThierry Reding 
51776dc384SThierry Reding 	INIT_LIST_HEAD(&subdev->list);
52776dc384SThierry Reding 	subdev->np = of_node_get(np);
53776dc384SThierry Reding 
54776dc384SThierry Reding 	mutex_lock(&device->subdevs_lock);
55776dc384SThierry Reding 	list_add_tail(&subdev->list, &device->subdevs);
56776dc384SThierry Reding 	mutex_unlock(&device->subdevs_lock);
57776dc384SThierry Reding 
5825ae30d2SThierry Reding 	/* recursively add children */
5925ae30d2SThierry Reding 	for_each_child_of_node(np, child) {
6025ae30d2SThierry Reding 		if (of_match_node(driver->subdevs, child) &&
6125ae30d2SThierry Reding 		    of_device_is_available(child)) {
6225ae30d2SThierry Reding 			err = host1x_subdev_add(device, driver, child);
6325ae30d2SThierry Reding 			if (err < 0) {
6425ae30d2SThierry Reding 				/* XXX cleanup? */
6525ae30d2SThierry Reding 				of_node_put(child);
6625ae30d2SThierry Reding 				return err;
6725ae30d2SThierry Reding 			}
6825ae30d2SThierry Reding 		}
6925ae30d2SThierry Reding 	}
7025ae30d2SThierry Reding 
71776dc384SThierry Reding 	return 0;
72776dc384SThierry Reding }
73776dc384SThierry Reding 
74776dc384SThierry Reding /**
75776dc384SThierry Reding  * host1x_subdev_del() - remove subdevice
76466749f1SThierry Reding  * @subdev: subdevice to remove
77776dc384SThierry Reding  */
host1x_subdev_del(struct host1x_subdev * subdev)78776dc384SThierry Reding static void host1x_subdev_del(struct host1x_subdev *subdev)
79776dc384SThierry Reding {
80776dc384SThierry Reding 	list_del(&subdev->list);
81776dc384SThierry Reding 	of_node_put(subdev->np);
82776dc384SThierry Reding 	kfree(subdev);
83776dc384SThierry Reding }
84776dc384SThierry Reding 
85776dc384SThierry Reding /**
86776dc384SThierry Reding  * host1x_device_parse_dt() - scan device tree and add matching subdevices
87466749f1SThierry Reding  * @device: host1x logical device
88466749f1SThierry Reding  * @driver: host1x driver
89776dc384SThierry Reding  */
host1x_device_parse_dt(struct host1x_device * device,struct host1x_driver * driver)90f4c5cf88SThierry Reding static int host1x_device_parse_dt(struct host1x_device *device,
91f4c5cf88SThierry Reding 				  struct host1x_driver *driver)
92776dc384SThierry Reding {
93776dc384SThierry Reding 	struct device_node *np;
94776dc384SThierry Reding 	int err;
95776dc384SThierry Reding 
96776dc384SThierry Reding 	for_each_child_of_node(device->dev.parent->of_node, np) {
97f4c5cf88SThierry Reding 		if (of_match_node(driver->subdevs, np) &&
98776dc384SThierry Reding 		    of_device_is_available(np)) {
9925ae30d2SThierry Reding 			err = host1x_subdev_add(device, driver, np);
10093ec3029SAmitoj Kaur Chawla 			if (err < 0) {
10193ec3029SAmitoj Kaur Chawla 				of_node_put(np);
102776dc384SThierry Reding 				return err;
103776dc384SThierry Reding 			}
104776dc384SThierry Reding 		}
10593ec3029SAmitoj Kaur Chawla 	}
106776dc384SThierry Reding 
107776dc384SThierry Reding 	return 0;
108776dc384SThierry Reding }
109776dc384SThierry Reding 
host1x_subdev_register(struct host1x_device * device,struct host1x_subdev * subdev,struct host1x_client * client)110776dc384SThierry Reding static void host1x_subdev_register(struct host1x_device *device,
111776dc384SThierry Reding 				   struct host1x_subdev *subdev,
112776dc384SThierry Reding 				   struct host1x_client *client)
113776dc384SThierry Reding {
114776dc384SThierry Reding 	int err;
115776dc384SThierry Reding 
116776dc384SThierry Reding 	/*
117776dc384SThierry Reding 	 * Move the subdevice to the list of active (registered) subdevices
118776dc384SThierry Reding 	 * and associate it with a client. At the same time, associate the
119776dc384SThierry Reding 	 * client with its parent device.
120776dc384SThierry Reding 	 */
121776dc384SThierry Reding 	mutex_lock(&device->subdevs_lock);
122776dc384SThierry Reding 	mutex_lock(&device->clients_lock);
123776dc384SThierry Reding 	list_move_tail(&client->list, &device->clients);
124776dc384SThierry Reding 	list_move_tail(&subdev->list, &device->active);
125608f43adSThierry Reding 	client->host = &device->dev;
126776dc384SThierry Reding 	subdev->client = client;
127776dc384SThierry Reding 	mutex_unlock(&device->clients_lock);
128776dc384SThierry Reding 	mutex_unlock(&device->subdevs_lock);
129776dc384SThierry Reding 
130776dc384SThierry Reding 	if (list_empty(&device->subdevs)) {
131f4c5cf88SThierry Reding 		err = device_add(&device->dev);
132776dc384SThierry Reding 		if (err < 0)
133f4c5cf88SThierry Reding 			dev_err(&device->dev, "failed to add: %d\n", err);
134536e1715SThierry Reding 		else
135f4c5cf88SThierry Reding 			device->registered = true;
136776dc384SThierry Reding 	}
137776dc384SThierry Reding }
138776dc384SThierry Reding 
__host1x_subdev_unregister(struct host1x_device * device,struct host1x_subdev * subdev)139776dc384SThierry Reding static void __host1x_subdev_unregister(struct host1x_device *device,
140776dc384SThierry Reding 				       struct host1x_subdev *subdev)
141776dc384SThierry Reding {
142776dc384SThierry Reding 	struct host1x_client *client = subdev->client;
143776dc384SThierry Reding 
144776dc384SThierry Reding 	/*
145776dc384SThierry Reding 	 * If all subdevices have been activated, we're about to remove the
146776dc384SThierry Reding 	 * first active subdevice, so unload the driver first.
147776dc384SThierry Reding 	 */
148f4c5cf88SThierry Reding 	if (list_empty(&device->subdevs)) {
149f4c5cf88SThierry Reding 		if (device->registered) {
150f4c5cf88SThierry Reding 			device->registered = false;
151f4c5cf88SThierry Reding 			device_del(&device->dev);
152f4c5cf88SThierry Reding 		}
153776dc384SThierry Reding 	}
154776dc384SThierry Reding 
155776dc384SThierry Reding 	/*
156776dc384SThierry Reding 	 * Move the subdevice back to the list of idle subdevices and remove
157776dc384SThierry Reding 	 * it from list of clients.
158776dc384SThierry Reding 	 */
159776dc384SThierry Reding 	mutex_lock(&device->clients_lock);
160776dc384SThierry Reding 	subdev->client = NULL;
161608f43adSThierry Reding 	client->host = NULL;
162776dc384SThierry Reding 	list_move_tail(&subdev->list, &device->subdevs);
163776dc384SThierry Reding 	/*
164776dc384SThierry Reding 	 * XXX: Perhaps don't do this here, but rather explicitly remove it
165776dc384SThierry Reding 	 * when the device is about to be deleted.
166776dc384SThierry Reding 	 *
167776dc384SThierry Reding 	 * This is somewhat complicated by the fact that this function is
168776dc384SThierry Reding 	 * used to remove the subdevice when a client is unregistered but
169776dc384SThierry Reding 	 * also when the composite device is about to be removed.
170776dc384SThierry Reding 	 */
171776dc384SThierry Reding 	list_del_init(&client->list);
172776dc384SThierry Reding 	mutex_unlock(&device->clients_lock);
173776dc384SThierry Reding }
174776dc384SThierry Reding 
host1x_subdev_unregister(struct host1x_device * device,struct host1x_subdev * subdev)175776dc384SThierry Reding static void host1x_subdev_unregister(struct host1x_device *device,
176776dc384SThierry Reding 				     struct host1x_subdev *subdev)
177776dc384SThierry Reding {
178776dc384SThierry Reding 	mutex_lock(&device->subdevs_lock);
179776dc384SThierry Reding 	__host1x_subdev_unregister(device, subdev);
180776dc384SThierry Reding 	mutex_unlock(&device->subdevs_lock);
181776dc384SThierry Reding }
182776dc384SThierry Reding 
183466749f1SThierry Reding /**
184466749f1SThierry Reding  * host1x_device_init() - initialize a host1x logical device
185466749f1SThierry Reding  * @device: host1x logical device
186466749f1SThierry Reding  *
187466749f1SThierry Reding  * The driver for the host1x logical device can call this during execution of
188466749f1SThierry Reding  * its &host1x_driver.probe implementation to initialize each of its clients.
189466749f1SThierry Reding  * The client drivers access the subsystem specific driver data using the
190466749f1SThierry Reding  * &host1x_client.parent field and driver data associated with it (usually by
191466749f1SThierry Reding  * calling dev_get_drvdata()).
192466749f1SThierry Reding  */
host1x_device_init(struct host1x_device * device)193776dc384SThierry Reding int host1x_device_init(struct host1x_device *device)
194776dc384SThierry Reding {
195776dc384SThierry Reding 	struct host1x_client *client;
196776dc384SThierry Reding 	int err;
197776dc384SThierry Reding 
198776dc384SThierry Reding 	mutex_lock(&device->clients_lock);
199776dc384SThierry Reding 
200776dc384SThierry Reding 	list_for_each_entry(client, &device->clients, list) {
201933deb8cSThierry Reding 		if (client->ops && client->ops->early_init) {
202933deb8cSThierry Reding 			err = client->ops->early_init(client);
203933deb8cSThierry Reding 			if (err < 0) {
204933deb8cSThierry Reding 				dev_err(&device->dev, "failed to early initialize %s: %d\n",
205933deb8cSThierry Reding 					dev_name(client->dev), err);
206933deb8cSThierry Reding 				goto teardown_late;
207933deb8cSThierry Reding 			}
208933deb8cSThierry Reding 		}
209933deb8cSThierry Reding 	}
210933deb8cSThierry Reding 
211933deb8cSThierry Reding 	list_for_each_entry(client, &device->clients, list) {
212776dc384SThierry Reding 		if (client->ops && client->ops->init) {
213776dc384SThierry Reding 			err = client->ops->init(client);
214776dc384SThierry Reding 			if (err < 0) {
215776dc384SThierry Reding 				dev_err(&device->dev,
216776dc384SThierry Reding 					"failed to initialize %s: %d\n",
217776dc384SThierry Reding 					dev_name(client->dev), err);
2188f7da157SThierry Reding 				goto teardown;
219776dc384SThierry Reding 			}
220776dc384SThierry Reding 		}
221776dc384SThierry Reding 	}
222776dc384SThierry Reding 
223776dc384SThierry Reding 	mutex_unlock(&device->clients_lock);
224776dc384SThierry Reding 
225776dc384SThierry Reding 	return 0;
2268f7da157SThierry Reding 
2278f7da157SThierry Reding teardown:
2288f7da157SThierry Reding 	list_for_each_entry_continue_reverse(client, &device->clients, list)
2298f7da157SThierry Reding 		if (client->ops->exit)
2308f7da157SThierry Reding 			client->ops->exit(client);
2318f7da157SThierry Reding 
232933deb8cSThierry Reding 	/* reset client to end of list for late teardown */
233933deb8cSThierry Reding 	client = list_entry(&device->clients, struct host1x_client, list);
234933deb8cSThierry Reding 
235933deb8cSThierry Reding teardown_late:
236933deb8cSThierry Reding 	list_for_each_entry_continue_reverse(client, &device->clients, list)
237933deb8cSThierry Reding 		if (client->ops->late_exit)
238933deb8cSThierry Reding 			client->ops->late_exit(client);
239933deb8cSThierry Reding 
2408f7da157SThierry Reding 	mutex_unlock(&device->clients_lock);
2418f7da157SThierry Reding 	return err;
242776dc384SThierry Reding }
243fae798a1SThierry Reding EXPORT_SYMBOL(host1x_device_init);
244776dc384SThierry Reding 
245466749f1SThierry Reding /**
246466749f1SThierry Reding  * host1x_device_exit() - uninitialize host1x logical device
247466749f1SThierry Reding  * @device: host1x logical device
248466749f1SThierry Reding  *
249466749f1SThierry Reding  * When the driver for a host1x logical device is unloaded, it can call this
250466749f1SThierry Reding  * function to tear down each of its clients. Typically this is done after a
251466749f1SThierry Reding  * subsystem-specific data structure is removed and the functionality can no
252466749f1SThierry Reding  * longer be used.
253466749f1SThierry Reding  */
host1x_device_exit(struct host1x_device * device)254776dc384SThierry Reding int host1x_device_exit(struct host1x_device *device)
255776dc384SThierry Reding {
256776dc384SThierry Reding 	struct host1x_client *client;
257776dc384SThierry Reding 	int err;
258776dc384SThierry Reding 
259776dc384SThierry Reding 	mutex_lock(&device->clients_lock);
260776dc384SThierry Reding 
261776dc384SThierry Reding 	list_for_each_entry_reverse(client, &device->clients, list) {
262776dc384SThierry Reding 		if (client->ops && client->ops->exit) {
263776dc384SThierry Reding 			err = client->ops->exit(client);
264776dc384SThierry Reding 			if (err < 0) {
265776dc384SThierry Reding 				dev_err(&device->dev,
266776dc384SThierry Reding 					"failed to cleanup %s: %d\n",
267776dc384SThierry Reding 					dev_name(client->dev), err);
268776dc384SThierry Reding 				mutex_unlock(&device->clients_lock);
269776dc384SThierry Reding 				return err;
270776dc384SThierry Reding 			}
271776dc384SThierry Reding 		}
272776dc384SThierry Reding 	}
273776dc384SThierry Reding 
274933deb8cSThierry Reding 	list_for_each_entry_reverse(client, &device->clients, list) {
275933deb8cSThierry Reding 		if (client->ops && client->ops->late_exit) {
276933deb8cSThierry Reding 			err = client->ops->late_exit(client);
277933deb8cSThierry Reding 			if (err < 0) {
278933deb8cSThierry Reding 				dev_err(&device->dev, "failed to late cleanup %s: %d\n",
279933deb8cSThierry Reding 					dev_name(client->dev), err);
280933deb8cSThierry Reding 				mutex_unlock(&device->clients_lock);
281933deb8cSThierry Reding 				return err;
282933deb8cSThierry Reding 			}
283933deb8cSThierry Reding 		}
284933deb8cSThierry Reding 	}
285933deb8cSThierry Reding 
286776dc384SThierry Reding 	mutex_unlock(&device->clients_lock);
287776dc384SThierry Reding 
288776dc384SThierry Reding 	return 0;
289776dc384SThierry Reding }
290fae798a1SThierry Reding EXPORT_SYMBOL(host1x_device_exit);
291776dc384SThierry Reding 
host1x_add_client(struct host1x * host1x,struct host1x_client * client)2920c7dfd36SThierry Reding static int host1x_add_client(struct host1x *host1x,
293776dc384SThierry Reding 			     struct host1x_client *client)
294776dc384SThierry Reding {
295776dc384SThierry Reding 	struct host1x_device *device;
296776dc384SThierry Reding 	struct host1x_subdev *subdev;
297776dc384SThierry Reding 
298776dc384SThierry Reding 	mutex_lock(&host1x->devices_lock);
299776dc384SThierry Reding 
300776dc384SThierry Reding 	list_for_each_entry(device, &host1x->devices, list) {
301776dc384SThierry Reding 		list_for_each_entry(subdev, &device->subdevs, list) {
302776dc384SThierry Reding 			if (subdev->np == client->dev->of_node) {
303776dc384SThierry Reding 				host1x_subdev_register(device, subdev, client);
304776dc384SThierry Reding 				mutex_unlock(&host1x->devices_lock);
305776dc384SThierry Reding 				return 0;
306776dc384SThierry Reding 			}
307776dc384SThierry Reding 		}
308776dc384SThierry Reding 	}
309776dc384SThierry Reding 
310776dc384SThierry Reding 	mutex_unlock(&host1x->devices_lock);
311776dc384SThierry Reding 	return -ENODEV;
312776dc384SThierry Reding }
313776dc384SThierry Reding 
host1x_del_client(struct host1x * host1x,struct host1x_client * client)3140c7dfd36SThierry Reding static int host1x_del_client(struct host1x *host1x,
315776dc384SThierry Reding 			     struct host1x_client *client)
316776dc384SThierry Reding {
317776dc384SThierry Reding 	struct host1x_device *device, *dt;
318776dc384SThierry Reding 	struct host1x_subdev *subdev;
319776dc384SThierry Reding 
320776dc384SThierry Reding 	mutex_lock(&host1x->devices_lock);
321776dc384SThierry Reding 
322776dc384SThierry Reding 	list_for_each_entry_safe(device, dt, &host1x->devices, list) {
323776dc384SThierry Reding 		list_for_each_entry(subdev, &device->active, list) {
324776dc384SThierry Reding 			if (subdev->client == client) {
325776dc384SThierry Reding 				host1x_subdev_unregister(device, subdev);
326776dc384SThierry Reding 				mutex_unlock(&host1x->devices_lock);
327776dc384SThierry Reding 				return 0;
328776dc384SThierry Reding 			}
329776dc384SThierry Reding 		}
330776dc384SThierry Reding 	}
331776dc384SThierry Reding 
332776dc384SThierry Reding 	mutex_unlock(&host1x->devices_lock);
333776dc384SThierry Reding 	return -ENODEV;
334776dc384SThierry Reding }
335776dc384SThierry Reding 
host1x_device_match(struct device * dev,struct device_driver * drv)336f4c5cf88SThierry Reding static int host1x_device_match(struct device *dev, struct device_driver *drv)
337f4c5cf88SThierry Reding {
338f4c5cf88SThierry Reding 	return strcmp(dev_name(dev), drv->name) == 0;
339f4c5cf88SThierry Reding }
340f4c5cf88SThierry Reding 
34131fa25f1SThierry Reding /*
34231fa25f1SThierry Reding  * Note that this is really only needed for backwards compatibility
34331fa25f1SThierry Reding  * with libdrm, which parses this information from sysfs and will
34431fa25f1SThierry Reding  * fail if it can't find the OF_FULLNAME, specifically.
34531fa25f1SThierry Reding  */
host1x_device_uevent(const struct device * dev,struct kobj_uevent_env * env)346*e4681be3SMiquel Raynal static int host1x_device_uevent(const struct device *dev,
347*e4681be3SMiquel Raynal 				struct kobj_uevent_env *env)
348*e4681be3SMiquel Raynal {
349*e4681be3SMiquel Raynal 	of_device_uevent(dev->parent, env);
35031fa25f1SThierry Reding 
35131fa25f1SThierry Reding 	return 0;
35231fa25f1SThierry Reding }
35331fa25f1SThierry Reding 
354f4c5cf88SThierry Reding static const struct dev_pm_ops host1x_device_pm_ops = {
355f4c5cf88SThierry Reding 	.suspend = pm_generic_suspend,
356f4c5cf88SThierry Reding 	.resume = pm_generic_resume,
357f4c5cf88SThierry Reding 	.freeze = pm_generic_freeze,
358f4c5cf88SThierry Reding 	.thaw = pm_generic_thaw,
359f4c5cf88SThierry Reding 	.poweroff = pm_generic_poweroff,
360f4c5cf88SThierry Reding 	.restore = pm_generic_restore,
361776dc384SThierry Reding };
362776dc384SThierry Reding 
363f4c5cf88SThierry Reding struct bus_type host1x_bus_type = {
364f4c5cf88SThierry Reding 	.name = "host1x",
365f4c5cf88SThierry Reding 	.match = host1x_device_match,
36631fa25f1SThierry Reding 	.uevent = host1x_device_uevent,
367f4c5cf88SThierry Reding 	.pm = &host1x_device_pm_ops,
368f4c5cf88SThierry Reding };
369776dc384SThierry Reding 
__host1x_device_del(struct host1x_device * device)37099d2cd81SThierry Reding static void __host1x_device_del(struct host1x_device *device)
37199d2cd81SThierry Reding {
37299d2cd81SThierry Reding 	struct host1x_subdev *subdev, *sd;
37399d2cd81SThierry Reding 	struct host1x_client *client, *cl;
37499d2cd81SThierry Reding 
37599d2cd81SThierry Reding 	mutex_lock(&device->subdevs_lock);
37699d2cd81SThierry Reding 
37799d2cd81SThierry Reding 	/* unregister subdevices */
37899d2cd81SThierry Reding 	list_for_each_entry_safe(subdev, sd, &device->active, list) {
37999d2cd81SThierry Reding 		/*
38099d2cd81SThierry Reding 		 * host1x_subdev_unregister() will remove the client from
38199d2cd81SThierry Reding 		 * any lists, so we'll need to manually add it back to the
38299d2cd81SThierry Reding 		 * list of idle clients.
38399d2cd81SThierry Reding 		 *
38499d2cd81SThierry Reding 		 * XXX: Alternatively, perhaps don't remove the client from
38599d2cd81SThierry Reding 		 * any lists in host1x_subdev_unregister() and instead do
38699d2cd81SThierry Reding 		 * that explicitly from host1x_unregister_client()?
38799d2cd81SThierry Reding 		 */
38899d2cd81SThierry Reding 		client = subdev->client;
38999d2cd81SThierry Reding 
39099d2cd81SThierry Reding 		__host1x_subdev_unregister(device, subdev);
39199d2cd81SThierry Reding 
39299d2cd81SThierry Reding 		/* add the client to the list of idle clients */
39399d2cd81SThierry Reding 		mutex_lock(&clients_lock);
39499d2cd81SThierry Reding 		list_add_tail(&client->list, &clients);
39599d2cd81SThierry Reding 		mutex_unlock(&clients_lock);
39699d2cd81SThierry Reding 	}
39799d2cd81SThierry Reding 
39899d2cd81SThierry Reding 	/* remove subdevices */
39999d2cd81SThierry Reding 	list_for_each_entry_safe(subdev, sd, &device->subdevs, list)
40099d2cd81SThierry Reding 		host1x_subdev_del(subdev);
40199d2cd81SThierry Reding 
40299d2cd81SThierry Reding 	mutex_unlock(&device->subdevs_lock);
40399d2cd81SThierry Reding 
40499d2cd81SThierry Reding 	/* move clients to idle list */
40599d2cd81SThierry Reding 	mutex_lock(&clients_lock);
40699d2cd81SThierry Reding 	mutex_lock(&device->clients_lock);
40799d2cd81SThierry Reding 
40899d2cd81SThierry Reding 	list_for_each_entry_safe(client, cl, &device->clients, list)
40999d2cd81SThierry Reding 		list_move_tail(&client->list, &clients);
41099d2cd81SThierry Reding 
41199d2cd81SThierry Reding 	mutex_unlock(&device->clients_lock);
41299d2cd81SThierry Reding 	mutex_unlock(&clients_lock);
41399d2cd81SThierry Reding 
41499d2cd81SThierry Reding 	/* finally remove the device */
41599d2cd81SThierry Reding 	list_del_init(&device->list);
41699d2cd81SThierry Reding }
41799d2cd81SThierry Reding 
host1x_device_release(struct device * dev)418776dc384SThierry Reding static void host1x_device_release(struct device *dev)
419776dc384SThierry Reding {
420776dc384SThierry Reding 	struct host1x_device *device = to_host1x_device(dev);
421776dc384SThierry Reding 
42299d2cd81SThierry Reding 	__host1x_device_del(device);
423776dc384SThierry Reding 	kfree(device);
424776dc384SThierry Reding }
425776dc384SThierry Reding 
host1x_device_add(struct host1x * host1x,struct host1x_driver * driver)426776dc384SThierry Reding static int host1x_device_add(struct host1x *host1x,
427776dc384SThierry Reding 			     struct host1x_driver *driver)
428776dc384SThierry Reding {
429776dc384SThierry Reding 	struct host1x_client *client, *tmp;
430776dc384SThierry Reding 	struct host1x_subdev *subdev;
431776dc384SThierry Reding 	struct host1x_device *device;
432776dc384SThierry Reding 	int err;
433776dc384SThierry Reding 
434776dc384SThierry Reding 	device = kzalloc(sizeof(*device), GFP_KERNEL);
435776dc384SThierry Reding 	if (!device)
436776dc384SThierry Reding 		return -ENOMEM;
437776dc384SThierry Reding 
438f4c5cf88SThierry Reding 	device_initialize(&device->dev);
439f4c5cf88SThierry Reding 
440776dc384SThierry Reding 	mutex_init(&device->subdevs_lock);
441776dc384SThierry Reding 	INIT_LIST_HEAD(&device->subdevs);
442776dc384SThierry Reding 	INIT_LIST_HEAD(&device->active);
443776dc384SThierry Reding 	mutex_init(&device->clients_lock);
444776dc384SThierry Reding 	INIT_LIST_HEAD(&device->clients);
445776dc384SThierry Reding 	INIT_LIST_HEAD(&device->list);
446776dc384SThierry Reding 	device->driver = driver;
447776dc384SThierry Reding 
448776dc384SThierry Reding 	device->dev.coherent_dma_mask = host1x->dev->coherent_dma_mask;
449776dc384SThierry Reding 	device->dev.dma_mask = &device->dev.coherent_dma_mask;
450f4c5cf88SThierry Reding 	dev_set_name(&device->dev, "%s", driver->driver.name);
451776dc384SThierry Reding 	device->dev.release = host1x_device_release;
452776dc384SThierry Reding 	device->dev.bus = &host1x_bus_type;
453776dc384SThierry Reding 	device->dev.parent = host1x->dev;
454776dc384SThierry Reding 
4551e390478SThierry Reding 	device->dev.dma_parms = &device->dma_parms;
456d98914ebSThierry Reding 	dma_set_max_seg_size(&device->dev, UINT_MAX);
4571e390478SThierry Reding 
458f4c5cf88SThierry Reding 	err = host1x_device_parse_dt(device, driver);
459776dc384SThierry Reding 	if (err < 0) {
460f4c5cf88SThierry Reding 		kfree(device);
461776dc384SThierry Reding 		return err;
462776dc384SThierry Reding 	}
463776dc384SThierry Reding 
464776dc384SThierry Reding 	list_add_tail(&device->list, &host1x->devices);
465776dc384SThierry Reding 
466776dc384SThierry Reding 	mutex_lock(&clients_lock);
467776dc384SThierry Reding 
468776dc384SThierry Reding 	list_for_each_entry_safe(client, tmp, &clients, list) {
469776dc384SThierry Reding 		list_for_each_entry(subdev, &device->subdevs, list) {
470776dc384SThierry Reding 			if (subdev->np == client->dev->of_node) {
471776dc384SThierry Reding 				host1x_subdev_register(device, subdev, client);
472776dc384SThierry Reding 				break;
473776dc384SThierry Reding 			}
474776dc384SThierry Reding 		}
475776dc384SThierry Reding 	}
476776dc384SThierry Reding 
477776dc384SThierry Reding 	mutex_unlock(&clients_lock);
478776dc384SThierry Reding 
479776dc384SThierry Reding 	return 0;
480776dc384SThierry Reding }
481776dc384SThierry Reding 
482776dc384SThierry Reding /*
483776dc384SThierry Reding  * Removes a device by first unregistering any subdevices and then removing
484776dc384SThierry Reding  * itself from the list of devices.
485776dc384SThierry Reding  *
486776dc384SThierry Reding  * This function must be called with the host1x->devices_lock held.
487776dc384SThierry Reding  */
host1x_device_del(struct host1x * host1x,struct host1x_device * device)488776dc384SThierry Reding static void host1x_device_del(struct host1x *host1x,
489776dc384SThierry Reding 			      struct host1x_device *device)
490776dc384SThierry Reding {
491f4c5cf88SThierry Reding 	if (device->registered) {
492f4c5cf88SThierry Reding 		device->registered = false;
493f4c5cf88SThierry Reding 		device_del(&device->dev);
494f4c5cf88SThierry Reding 	}
495f4c5cf88SThierry Reding 
496f4c5cf88SThierry Reding 	put_device(&device->dev);
497776dc384SThierry Reding }
498776dc384SThierry Reding 
host1x_attach_driver(struct host1x * host1x,struct host1x_driver * driver)499776dc384SThierry Reding static void host1x_attach_driver(struct host1x *host1x,
500776dc384SThierry Reding 				 struct host1x_driver *driver)
501776dc384SThierry Reding {
502776dc384SThierry Reding 	struct host1x_device *device;
503776dc384SThierry Reding 	int err;
504776dc384SThierry Reding 
505776dc384SThierry Reding 	mutex_lock(&host1x->devices_lock);
506776dc384SThierry Reding 
507776dc384SThierry Reding 	list_for_each_entry(device, &host1x->devices, list) {
508776dc384SThierry Reding 		if (device->driver == driver) {
509776dc384SThierry Reding 			mutex_unlock(&host1x->devices_lock);
510776dc384SThierry Reding 			return;
511776dc384SThierry Reding 		}
512776dc384SThierry Reding 	}
513776dc384SThierry Reding 
514776dc384SThierry Reding 	err = host1x_device_add(host1x, driver);
515776dc384SThierry Reding 	if (err < 0)
516776dc384SThierry Reding 		dev_err(host1x->dev, "failed to allocate device: %d\n", err);
51738d98de4SThierry Reding 
51838d98de4SThierry Reding 	mutex_unlock(&host1x->devices_lock);
519776dc384SThierry Reding }
520776dc384SThierry Reding 
host1x_detach_driver(struct host1x * host1x,struct host1x_driver * driver)521776dc384SThierry Reding static void host1x_detach_driver(struct host1x *host1x,
522776dc384SThierry Reding 				 struct host1x_driver *driver)
523776dc384SThierry Reding {
524776dc384SThierry Reding 	struct host1x_device *device, *tmp;
525776dc384SThierry Reding 
526776dc384SThierry Reding 	mutex_lock(&host1x->devices_lock);
527776dc384SThierry Reding 
528776dc384SThierry Reding 	list_for_each_entry_safe(device, tmp, &host1x->devices, list)
529776dc384SThierry Reding 		if (device->driver == driver)
530776dc384SThierry Reding 			host1x_device_del(host1x, device);
531776dc384SThierry Reding 
532776dc384SThierry Reding 	mutex_unlock(&host1x->devices_lock);
533776dc384SThierry Reding }
534776dc384SThierry Reding 
host1x_devices_show(struct seq_file * s,void * data)535f67524caSThierry Reding static int host1x_devices_show(struct seq_file *s, void *data)
536f67524caSThierry Reding {
537f67524caSThierry Reding 	struct host1x *host1x = s->private;
538f67524caSThierry Reding 	struct host1x_device *device;
539f67524caSThierry Reding 
540f67524caSThierry Reding 	mutex_lock(&host1x->devices_lock);
541f67524caSThierry Reding 
542f67524caSThierry Reding 	list_for_each_entry(device, &host1x->devices, list) {
543f67524caSThierry Reding 		struct host1x_subdev *subdev;
544f67524caSThierry Reding 
545f67524caSThierry Reding 		seq_printf(s, "%s\n", dev_name(&device->dev));
546f67524caSThierry Reding 
547f67524caSThierry Reding 		mutex_lock(&device->subdevs_lock);
548f67524caSThierry Reding 
549f67524caSThierry Reding 		list_for_each_entry(subdev, &device->active, list)
550f67524caSThierry Reding 			seq_printf(s, "  %pOFf: %s\n", subdev->np,
551f67524caSThierry Reding 				   dev_name(subdev->client->dev));
552f67524caSThierry Reding 
553f67524caSThierry Reding 		list_for_each_entry(subdev, &device->subdevs, list)
554f67524caSThierry Reding 			seq_printf(s, "  %pOFf:\n", subdev->np);
555f67524caSThierry Reding 
556f67524caSThierry Reding 		mutex_unlock(&device->subdevs_lock);
557f67524caSThierry Reding 	}
558f67524caSThierry Reding 
559f67524caSThierry Reding 	mutex_unlock(&host1x->devices_lock);
560f67524caSThierry Reding 
561f67524caSThierry Reding 	return 0;
562f67524caSThierry Reding }
563f67524caSThierry Reding DEFINE_SHOW_ATTRIBUTE(host1x_devices);
564f67524caSThierry Reding 
565466749f1SThierry Reding /**
566466749f1SThierry Reding  * host1x_register() - register a host1x controller
567466749f1SThierry Reding  * @host1x: host1x controller
568466749f1SThierry Reding  *
569466749f1SThierry Reding  * The host1x controller driver uses this to register a host1x controller with
570466749f1SThierry Reding  * the infrastructure. Note that all Tegra SoC generations have only ever come
571466749f1SThierry Reding  * with a single host1x instance, so this function is somewhat academic.
572466749f1SThierry Reding  */
host1x_register(struct host1x * host1x)573776dc384SThierry Reding int host1x_register(struct host1x *host1x)
574776dc384SThierry Reding {
575776dc384SThierry Reding 	struct host1x_driver *driver;
576776dc384SThierry Reding 
577776dc384SThierry Reding 	mutex_lock(&devices_lock);
578776dc384SThierry Reding 	list_add_tail(&host1x->list, &devices);
579776dc384SThierry Reding 	mutex_unlock(&devices_lock);
580776dc384SThierry Reding 
581776dc384SThierry Reding 	mutex_lock(&drivers_lock);
582776dc384SThierry Reding 
583776dc384SThierry Reding 	list_for_each_entry(driver, &drivers, list)
584776dc384SThierry Reding 		host1x_attach_driver(host1x, driver);
585776dc384SThierry Reding 
586776dc384SThierry Reding 	mutex_unlock(&drivers_lock);
587776dc384SThierry Reding 
588f67524caSThierry Reding 	debugfs_create_file("devices", S_IRUGO, host1x->debugfs, host1x,
589f67524caSThierry Reding 			    &host1x_devices_fops);
590f67524caSThierry Reding 
591776dc384SThierry Reding 	return 0;
592776dc384SThierry Reding }
593776dc384SThierry Reding 
594466749f1SThierry Reding /**
595466749f1SThierry Reding  * host1x_unregister() - unregister a host1x controller
596466749f1SThierry Reding  * @host1x: host1x controller
597466749f1SThierry Reding  *
598466749f1SThierry Reding  * The host1x controller driver uses this to remove a host1x controller from
599466749f1SThierry Reding  * the infrastructure.
600466749f1SThierry Reding  */
host1x_unregister(struct host1x * host1x)601776dc384SThierry Reding int host1x_unregister(struct host1x *host1x)
602776dc384SThierry Reding {
603776dc384SThierry Reding 	struct host1x_driver *driver;
604776dc384SThierry Reding 
605776dc384SThierry Reding 	mutex_lock(&drivers_lock);
606776dc384SThierry Reding 
607776dc384SThierry Reding 	list_for_each_entry(driver, &drivers, list)
608776dc384SThierry Reding 		host1x_detach_driver(host1x, driver);
609776dc384SThierry Reding 
610776dc384SThierry Reding 	mutex_unlock(&drivers_lock);
611776dc384SThierry Reding 
612776dc384SThierry Reding 	mutex_lock(&devices_lock);
613776dc384SThierry Reding 	list_del_init(&host1x->list);
614776dc384SThierry Reding 	mutex_unlock(&devices_lock);
615776dc384SThierry Reding 
616776dc384SThierry Reding 	return 0;
617776dc384SThierry Reding }
618776dc384SThierry Reding 
host1x_device_probe(struct device * dev)619b0d36daaSThierry Reding static int host1x_device_probe(struct device *dev)
620b0d36daaSThierry Reding {
621b0d36daaSThierry Reding 	struct host1x_driver *driver = to_host1x_driver(dev->driver);
622b0d36daaSThierry Reding 	struct host1x_device *device = to_host1x_device(dev);
623b0d36daaSThierry Reding 
624b0d36daaSThierry Reding 	if (driver->probe)
625b0d36daaSThierry Reding 		return driver->probe(device);
626b0d36daaSThierry Reding 
627b0d36daaSThierry Reding 	return 0;
628b0d36daaSThierry Reding }
629b0d36daaSThierry Reding 
host1x_device_remove(struct device * dev)630b0d36daaSThierry Reding static int host1x_device_remove(struct device *dev)
631b0d36daaSThierry Reding {
632b0d36daaSThierry Reding 	struct host1x_driver *driver = to_host1x_driver(dev->driver);
633b0d36daaSThierry Reding 	struct host1x_device *device = to_host1x_device(dev);
634b0d36daaSThierry Reding 
635b0d36daaSThierry Reding 	if (driver->remove)
636b0d36daaSThierry Reding 		return driver->remove(device);
637b0d36daaSThierry Reding 
638b0d36daaSThierry Reding 	return 0;
639b0d36daaSThierry Reding }
640b0d36daaSThierry Reding 
host1x_device_shutdown(struct device * dev)641b0d36daaSThierry Reding static void host1x_device_shutdown(struct device *dev)
642b0d36daaSThierry Reding {
643b0d36daaSThierry Reding 	struct host1x_driver *driver = to_host1x_driver(dev->driver);
644b0d36daaSThierry Reding 	struct host1x_device *device = to_host1x_device(dev);
645b0d36daaSThierry Reding 
646b0d36daaSThierry Reding 	if (driver->shutdown)
647b0d36daaSThierry Reding 		driver->shutdown(device);
648b0d36daaSThierry Reding }
649b0d36daaSThierry Reding 
650466749f1SThierry Reding /**
651466749f1SThierry Reding  * host1x_driver_register_full() - register a host1x driver
652466749f1SThierry Reding  * @driver: host1x driver
653466749f1SThierry Reding  * @owner: owner module
654466749f1SThierry Reding  *
655466749f1SThierry Reding  * Drivers for host1x logical devices call this function to register a driver
656466749f1SThierry Reding  * with the infrastructure. Note that since these drive logical devices, the
657466749f1SThierry Reding  * registration of the driver actually triggers tho logical device creation.
658466749f1SThierry Reding  * A logical device will be created for each host1x instance.
659466749f1SThierry Reding  */
host1x_driver_register_full(struct host1x_driver * driver,struct module * owner)660f4c5cf88SThierry Reding int host1x_driver_register_full(struct host1x_driver *driver,
661f4c5cf88SThierry Reding 				struct module *owner)
662776dc384SThierry Reding {
663776dc384SThierry Reding 	struct host1x *host1x;
664776dc384SThierry Reding 
665776dc384SThierry Reding 	INIT_LIST_HEAD(&driver->list);
666776dc384SThierry Reding 
667776dc384SThierry Reding 	mutex_lock(&drivers_lock);
668776dc384SThierry Reding 	list_add_tail(&driver->list, &drivers);
669776dc384SThierry Reding 	mutex_unlock(&drivers_lock);
670776dc384SThierry Reding 
671776dc384SThierry Reding 	mutex_lock(&devices_lock);
672776dc384SThierry Reding 
673776dc384SThierry Reding 	list_for_each_entry(host1x, &devices, list)
674776dc384SThierry Reding 		host1x_attach_driver(host1x, driver);
675776dc384SThierry Reding 
676776dc384SThierry Reding 	mutex_unlock(&devices_lock);
677776dc384SThierry Reding 
678f4c5cf88SThierry Reding 	driver->driver.bus = &host1x_bus_type;
679f4c5cf88SThierry Reding 	driver->driver.owner = owner;
680b0d36daaSThierry Reding 	driver->driver.probe = host1x_device_probe;
681b0d36daaSThierry Reding 	driver->driver.remove = host1x_device_remove;
682b0d36daaSThierry Reding 	driver->driver.shutdown = host1x_device_shutdown;
683f4c5cf88SThierry Reding 
684f4c5cf88SThierry Reding 	return driver_register(&driver->driver);
685776dc384SThierry Reding }
686f4c5cf88SThierry Reding EXPORT_SYMBOL(host1x_driver_register_full);
687776dc384SThierry Reding 
688466749f1SThierry Reding /**
689466749f1SThierry Reding  * host1x_driver_unregister() - unregister a host1x driver
690466749f1SThierry Reding  * @driver: host1x driver
691466749f1SThierry Reding  *
692466749f1SThierry Reding  * Unbinds the driver from each of the host1x logical devices that it is
693466749f1SThierry Reding  * bound to, effectively removing the subsystem devices that they represent.
694466749f1SThierry Reding  */
host1x_driver_unregister(struct host1x_driver * driver)695776dc384SThierry Reding void host1x_driver_unregister(struct host1x_driver *driver)
696776dc384SThierry Reding {
697d9a0a05bSThierry Reding 	struct host1x *host1x;
698d9a0a05bSThierry Reding 
699e3e70814SThierry Reding 	driver_unregister(&driver->driver);
700e3e70814SThierry Reding 
701d9a0a05bSThierry Reding 	mutex_lock(&devices_lock);
702d9a0a05bSThierry Reding 
703d9a0a05bSThierry Reding 	list_for_each_entry(host1x, &devices, list)
704d9a0a05bSThierry Reding 		host1x_detach_driver(host1x, driver);
705d9a0a05bSThierry Reding 
706d9a0a05bSThierry Reding 	mutex_unlock(&devices_lock);
707d9a0a05bSThierry Reding 
708776dc384SThierry Reding 	mutex_lock(&drivers_lock);
709776dc384SThierry Reding 	list_del_init(&driver->list);
710776dc384SThierry Reding 	mutex_unlock(&drivers_lock);
711776dc384SThierry Reding }
712776dc384SThierry Reding EXPORT_SYMBOL(host1x_driver_unregister);
713776dc384SThierry Reding 
714466749f1SThierry Reding /**
7150cfe5a6eSThierry Reding  * __host1x_client_init() - initialize a host1x client
7160cfe5a6eSThierry Reding  * @client: host1x client
7170cfe5a6eSThierry Reding  * @key: lock class key for the client-specific mutex
7180cfe5a6eSThierry Reding  */
__host1x_client_init(struct host1x_client * client,struct lock_class_key * key)7190cfe5a6eSThierry Reding void __host1x_client_init(struct host1x_client *client, struct lock_class_key *key)
7200cfe5a6eSThierry Reding {
7211f39b1dfSThierry Reding 	host1x_bo_cache_init(&client->cache);
7220cfe5a6eSThierry Reding 	INIT_LIST_HEAD(&client->list);
7230cfe5a6eSThierry Reding 	__mutex_init(&client->lock, "host1x client lock", key);
7240cfe5a6eSThierry Reding 	client->usecount = 0;
7250cfe5a6eSThierry Reding }
7260cfe5a6eSThierry Reding EXPORT_SYMBOL(__host1x_client_init);
7270cfe5a6eSThierry Reding 
7280cfe5a6eSThierry Reding /**
7290cfe5a6eSThierry Reding  * host1x_client_exit() - uninitialize a host1x client
7300cfe5a6eSThierry Reding  * @client: host1x client
7310cfe5a6eSThierry Reding  */
host1x_client_exit(struct host1x_client * client)7320cfe5a6eSThierry Reding void host1x_client_exit(struct host1x_client *client)
7330cfe5a6eSThierry Reding {
7340cfe5a6eSThierry Reding 	mutex_destroy(&client->lock);
7350cfe5a6eSThierry Reding }
7360cfe5a6eSThierry Reding EXPORT_SYMBOL(host1x_client_exit);
7370cfe5a6eSThierry Reding 
7380cfe5a6eSThierry Reding /**
739a24f9817SMikko Perttunen  * __host1x_client_register() - register a host1x client
740466749f1SThierry Reding  * @client: host1x client
741466749f1SThierry Reding  *
742466749f1SThierry Reding  * Registers a host1x client with each host1x controller instance. Note that
743466749f1SThierry Reding  * each client will only match their parent host1x controller and will only be
744466749f1SThierry Reding  * associated with that instance. Once all clients have been registered with
745466749f1SThierry Reding  * their parent host1x controller, the infrastructure will set up the logical
746466749f1SThierry Reding  * device and call host1x_device_init(), which will in turn call each client's
747466749f1SThierry Reding  * &host1x_client_ops.init implementation.
748466749f1SThierry Reding  */
__host1x_client_register(struct host1x_client * client)7490cfe5a6eSThierry Reding int __host1x_client_register(struct host1x_client *client)
750776dc384SThierry Reding {
751776dc384SThierry Reding 	struct host1x *host1x;
752776dc384SThierry Reding 	int err;
753776dc384SThierry Reding 
754776dc384SThierry Reding 	mutex_lock(&devices_lock);
755776dc384SThierry Reding 
756776dc384SThierry Reding 	list_for_each_entry(host1x, &devices, list) {
7570c7dfd36SThierry Reding 		err = host1x_add_client(host1x, client);
758776dc384SThierry Reding 		if (!err) {
759776dc384SThierry Reding 			mutex_unlock(&devices_lock);
760776dc384SThierry Reding 			return 0;
761776dc384SThierry Reding 		}
762776dc384SThierry Reding 	}
763776dc384SThierry Reding 
764776dc384SThierry Reding 	mutex_unlock(&devices_lock);
765776dc384SThierry Reding 
766776dc384SThierry Reding 	mutex_lock(&clients_lock);
767776dc384SThierry Reding 	list_add_tail(&client->list, &clients);
768776dc384SThierry Reding 	mutex_unlock(&clients_lock);
769776dc384SThierry Reding 
770776dc384SThierry Reding 	return 0;
771776dc384SThierry Reding }
772a24f9817SMikko Perttunen EXPORT_SYMBOL(__host1x_client_register);
773776dc384SThierry Reding 
774466749f1SThierry Reding /**
775466749f1SThierry Reding  * host1x_client_unregister() - unregister a host1x client
776466749f1SThierry Reding  * @client: host1x client
777466749f1SThierry Reding  *
778466749f1SThierry Reding  * Removes a host1x client from its host1x controller instance. If a logical
779466749f1SThierry Reding  * device has already been initialized, it will be torn down.
780466749f1SThierry Reding  */
host1x_client_unregister(struct host1x_client * client)7811d83d1a2SUwe Kleine-König void host1x_client_unregister(struct host1x_client *client)
782776dc384SThierry Reding {
783776dc384SThierry Reding 	struct host1x_client *c;
784776dc384SThierry Reding 	struct host1x *host1x;
785776dc384SThierry Reding 	int err;
786776dc384SThierry Reding 
787776dc384SThierry Reding 	mutex_lock(&devices_lock);
788776dc384SThierry Reding 
789776dc384SThierry Reding 	list_for_each_entry(host1x, &devices, list) {
7900c7dfd36SThierry Reding 		err = host1x_del_client(host1x, client);
791776dc384SThierry Reding 		if (!err) {
792776dc384SThierry Reding 			mutex_unlock(&devices_lock);
7931d83d1a2SUwe Kleine-König 			return;
794776dc384SThierry Reding 		}
795776dc384SThierry Reding 	}
796776dc384SThierry Reding 
797776dc384SThierry Reding 	mutex_unlock(&devices_lock);
798776dc384SThierry Reding 	mutex_lock(&clients_lock);
799776dc384SThierry Reding 
800776dc384SThierry Reding 	list_for_each_entry(c, &clients, list) {
801776dc384SThierry Reding 		if (c == client) {
802776dc384SThierry Reding 			list_del_init(&c->list);
803776dc384SThierry Reding 			break;
804776dc384SThierry Reding 		}
805776dc384SThierry Reding 	}
806776dc384SThierry Reding 
807776dc384SThierry Reding 	mutex_unlock(&clients_lock);
808776dc384SThierry Reding 
8091f39b1dfSThierry Reding 	host1x_bo_cache_destroy(&client->cache);
810776dc384SThierry Reding }
811776dc384SThierry Reding EXPORT_SYMBOL(host1x_client_unregister);
812fd67e9c6SThierry Reding 
host1x_client_suspend(struct host1x_client * client)813fd67e9c6SThierry Reding int host1x_client_suspend(struct host1x_client *client)
814fd67e9c6SThierry Reding {
815fd67e9c6SThierry Reding 	int err = 0;
816fd67e9c6SThierry Reding 
817fd67e9c6SThierry Reding 	mutex_lock(&client->lock);
818fd67e9c6SThierry Reding 
819fd67e9c6SThierry Reding 	if (client->usecount == 1) {
820fd67e9c6SThierry Reding 		if (client->ops && client->ops->suspend) {
821fd67e9c6SThierry Reding 			err = client->ops->suspend(client);
822fd67e9c6SThierry Reding 			if (err < 0)
823fd67e9c6SThierry Reding 				goto unlock;
824fd67e9c6SThierry Reding 		}
825fd67e9c6SThierry Reding 	}
826fd67e9c6SThierry Reding 
827fd67e9c6SThierry Reding 	client->usecount--;
828fd67e9c6SThierry Reding 	dev_dbg(client->dev, "use count: %u\n", client->usecount);
829fd67e9c6SThierry Reding 
830fd67e9c6SThierry Reding 	if (client->parent) {
831fd67e9c6SThierry Reding 		err = host1x_client_suspend(client->parent);
832fd67e9c6SThierry Reding 		if (err < 0)
833fd67e9c6SThierry Reding 			goto resume;
834fd67e9c6SThierry Reding 	}
835fd67e9c6SThierry Reding 
836fd67e9c6SThierry Reding 	goto unlock;
837fd67e9c6SThierry Reding 
838fd67e9c6SThierry Reding resume:
839fd67e9c6SThierry Reding 	if (client->usecount == 0)
840fd67e9c6SThierry Reding 		if (client->ops && client->ops->resume)
841fd67e9c6SThierry Reding 			client->ops->resume(client);
842fd67e9c6SThierry Reding 
843fd67e9c6SThierry Reding 	client->usecount++;
844fd67e9c6SThierry Reding unlock:
845fd67e9c6SThierry Reding 	mutex_unlock(&client->lock);
846fd67e9c6SThierry Reding 	return err;
847fd67e9c6SThierry Reding }
848fd67e9c6SThierry Reding EXPORT_SYMBOL(host1x_client_suspend);
849fd67e9c6SThierry Reding 
host1x_client_resume(struct host1x_client * client)850fd67e9c6SThierry Reding int host1x_client_resume(struct host1x_client *client)
851fd67e9c6SThierry Reding {
852fd67e9c6SThierry Reding 	int err = 0;
853fd67e9c6SThierry Reding 
854fd67e9c6SThierry Reding 	mutex_lock(&client->lock);
855fd67e9c6SThierry Reding 
856fd67e9c6SThierry Reding 	if (client->parent) {
857fd67e9c6SThierry Reding 		err = host1x_client_resume(client->parent);
858fd67e9c6SThierry Reding 		if (err < 0)
859fd67e9c6SThierry Reding 			goto unlock;
860fd67e9c6SThierry Reding 	}
861fd67e9c6SThierry Reding 
862fd67e9c6SThierry Reding 	if (client->usecount == 0) {
863fd67e9c6SThierry Reding 		if (client->ops && client->ops->resume) {
864fd67e9c6SThierry Reding 			err = client->ops->resume(client);
865fd67e9c6SThierry Reding 			if (err < 0)
866fd67e9c6SThierry Reding 				goto suspend;
867fd67e9c6SThierry Reding 		}
868fd67e9c6SThierry Reding 	}
869fd67e9c6SThierry Reding 
870fd67e9c6SThierry Reding 	client->usecount++;
871fd67e9c6SThierry Reding 	dev_dbg(client->dev, "use count: %u\n", client->usecount);
872fd67e9c6SThierry Reding 
873fd67e9c6SThierry Reding 	goto unlock;
874fd67e9c6SThierry Reding 
875fd67e9c6SThierry Reding suspend:
876fd67e9c6SThierry Reding 	if (client->parent)
877fd67e9c6SThierry Reding 		host1x_client_suspend(client->parent);
878fd67e9c6SThierry Reding unlock:
879fd67e9c6SThierry Reding 	mutex_unlock(&client->lock);
880fd67e9c6SThierry Reding 	return err;
881fd67e9c6SThierry Reding }
882fd67e9c6SThierry Reding EXPORT_SYMBOL(host1x_client_resume);
8831f39b1dfSThierry Reding 
host1x_bo_pin(struct device * dev,struct host1x_bo * bo,enum dma_data_direction dir,struct host1x_bo_cache * cache)8841f39b1dfSThierry Reding struct host1x_bo_mapping *host1x_bo_pin(struct device *dev, struct host1x_bo *bo,
8851f39b1dfSThierry Reding 					enum dma_data_direction dir,
8861f39b1dfSThierry Reding 					struct host1x_bo_cache *cache)
8871f39b1dfSThierry Reding {
8881f39b1dfSThierry Reding 	struct host1x_bo_mapping *mapping;
8891f39b1dfSThierry Reding 
8901f39b1dfSThierry Reding 	if (cache) {
8911f39b1dfSThierry Reding 		mutex_lock(&cache->lock);
8921f39b1dfSThierry Reding 
8931f39b1dfSThierry Reding 		list_for_each_entry(mapping, &cache->mappings, entry) {
8941f39b1dfSThierry Reding 			if (mapping->bo == bo && mapping->direction == dir) {
8951f39b1dfSThierry Reding 				kref_get(&mapping->ref);
8961f39b1dfSThierry Reding 				goto unlock;
8971f39b1dfSThierry Reding 			}
8981f39b1dfSThierry Reding 		}
8991f39b1dfSThierry Reding 	}
9001f39b1dfSThierry Reding 
9011f39b1dfSThierry Reding 	mapping = bo->ops->pin(dev, bo, dir);
9021f39b1dfSThierry Reding 	if (IS_ERR(mapping))
9031f39b1dfSThierry Reding 		goto unlock;
9041f39b1dfSThierry Reding 
9051f39b1dfSThierry Reding 	spin_lock(&mapping->bo->lock);
9061f39b1dfSThierry Reding 	list_add_tail(&mapping->list, &bo->mappings);
9071f39b1dfSThierry Reding 	spin_unlock(&mapping->bo->lock);
9081f39b1dfSThierry Reding 
9091f39b1dfSThierry Reding 	if (cache) {
9101f39b1dfSThierry Reding 		INIT_LIST_HEAD(&mapping->entry);
9111f39b1dfSThierry Reding 		mapping->cache = cache;
9121f39b1dfSThierry Reding 
9131f39b1dfSThierry Reding 		list_add_tail(&mapping->entry, &cache->mappings);
9141f39b1dfSThierry Reding 
9151f39b1dfSThierry Reding 		/* bump reference count to track the copy in the cache */
9161f39b1dfSThierry Reding 		kref_get(&mapping->ref);
9171f39b1dfSThierry Reding 	}
9181f39b1dfSThierry Reding 
9191f39b1dfSThierry Reding unlock:
9201f39b1dfSThierry Reding 	if (cache)
9211f39b1dfSThierry Reding 		mutex_unlock(&cache->lock);
9221f39b1dfSThierry Reding 
9231f39b1dfSThierry Reding 	return mapping;
9241f39b1dfSThierry Reding }
9251f39b1dfSThierry Reding EXPORT_SYMBOL(host1x_bo_pin);
9261f39b1dfSThierry Reding 
__host1x_bo_unpin(struct kref * ref)9271f39b1dfSThierry Reding static void __host1x_bo_unpin(struct kref *ref)
9281f39b1dfSThierry Reding {
9291f39b1dfSThierry Reding 	struct host1x_bo_mapping *mapping = to_host1x_bo_mapping(ref);
9301f39b1dfSThierry Reding 
9311f39b1dfSThierry Reding 	/*
9321f39b1dfSThierry Reding 	 * When the last reference of the mapping goes away, make sure to remove the mapping from
9331f39b1dfSThierry Reding 	 * the cache.
9341f39b1dfSThierry Reding 	 */
9351f39b1dfSThierry Reding 	if (mapping->cache)
9361f39b1dfSThierry Reding 		list_del(&mapping->entry);
9371f39b1dfSThierry Reding 
9381f39b1dfSThierry Reding 	spin_lock(&mapping->bo->lock);
9391f39b1dfSThierry Reding 	list_del(&mapping->list);
9401f39b1dfSThierry Reding 	spin_unlock(&mapping->bo->lock);
9411f39b1dfSThierry Reding 
9421f39b1dfSThierry Reding 	mapping->bo->ops->unpin(mapping);
9431f39b1dfSThierry Reding }
9441f39b1dfSThierry Reding 
host1x_bo_unpin(struct host1x_bo_mapping * mapping)9451f39b1dfSThierry Reding void host1x_bo_unpin(struct host1x_bo_mapping *mapping)
9461f39b1dfSThierry Reding {
9471f39b1dfSThierry Reding 	struct host1x_bo_cache *cache = mapping->cache;
9481f39b1dfSThierry Reding 
9491f39b1dfSThierry Reding 	if (cache)
9501f39b1dfSThierry Reding 		mutex_lock(&cache->lock);
9511f39b1dfSThierry Reding 
9521f39b1dfSThierry Reding 	kref_put(&mapping->ref, __host1x_bo_unpin);
9531f39b1dfSThierry Reding 
9541f39b1dfSThierry Reding 	if (cache)
9551f39b1dfSThierry Reding 		mutex_unlock(&cache->lock);
9561f39b1dfSThierry Reding }
9571f39b1dfSThierry Reding EXPORT_SYMBOL(host1x_bo_unpin);
958