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