]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blob - drivers/gpu/host1x/bus.c
drm/tegra: Move subdevice infrastructure to host1x
[mirror_ubuntu-bionic-kernel.git] / drivers / gpu / host1x / bus.c
1 /*
2 * Copyright (C) 2012 Avionic Design GmbH
3 * Copyright (C) 2012-2013, NVIDIA Corporation
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include <linux/host1x.h>
19 #include <linux/of.h>
20 #include <linux/slab.h>
21
22 #include "dev.h"
23
24 static DEFINE_MUTEX(clients_lock);
25 static LIST_HEAD(clients);
26
27 static DEFINE_MUTEX(drivers_lock);
28 static LIST_HEAD(drivers);
29
30 static DEFINE_MUTEX(devices_lock);
31 static LIST_HEAD(devices);
32
33 struct host1x_subdev {
34 struct host1x_client *client;
35 struct device_node *np;
36 struct list_head list;
37 };
38
39 /**
40 * host1x_subdev_add() - add a new subdevice with an associated device node
41 */
42 static int host1x_subdev_add(struct host1x_device *device,
43 struct device_node *np)
44 {
45 struct host1x_subdev *subdev;
46
47 subdev = kzalloc(sizeof(*subdev), GFP_KERNEL);
48 if (!subdev)
49 return -ENOMEM;
50
51 INIT_LIST_HEAD(&subdev->list);
52 subdev->np = of_node_get(np);
53
54 mutex_lock(&device->subdevs_lock);
55 list_add_tail(&subdev->list, &device->subdevs);
56 mutex_unlock(&device->subdevs_lock);
57
58 return 0;
59 }
60
61 /**
62 * host1x_subdev_del() - remove subdevice
63 */
64 static void host1x_subdev_del(struct host1x_subdev *subdev)
65 {
66 list_del(&subdev->list);
67 of_node_put(subdev->np);
68 kfree(subdev);
69 }
70
71 /**
72 * host1x_device_parse_dt() - scan device tree and add matching subdevices
73 */
74 static int host1x_device_parse_dt(struct host1x_device *device)
75 {
76 struct device_node *np;
77 int err;
78
79 for_each_child_of_node(device->dev.parent->of_node, np) {
80 if (of_match_node(device->driver->subdevs, np) &&
81 of_device_is_available(np)) {
82 err = host1x_subdev_add(device, np);
83 if (err < 0)
84 return err;
85 }
86 }
87
88 return 0;
89 }
90
91 static void host1x_subdev_register(struct host1x_device *device,
92 struct host1x_subdev *subdev,
93 struct host1x_client *client)
94 {
95 int err;
96
97 /*
98 * Move the subdevice to the list of active (registered) subdevices
99 * and associate it with a client. At the same time, associate the
100 * client with its parent device.
101 */
102 mutex_lock(&device->subdevs_lock);
103 mutex_lock(&device->clients_lock);
104 list_move_tail(&client->list, &device->clients);
105 list_move_tail(&subdev->list, &device->active);
106 client->parent = &device->dev;
107 subdev->client = client;
108 mutex_unlock(&device->clients_lock);
109 mutex_unlock(&device->subdevs_lock);
110
111 /*
112 * When all subdevices have been registered, the composite device is
113 * ready to be probed.
114 */
115 if (list_empty(&device->subdevs)) {
116 err = device->driver->probe(device);
117 if (err < 0)
118 dev_err(&device->dev, "probe failed: %d\n", err);
119 }
120 }
121
122 static void __host1x_subdev_unregister(struct host1x_device *device,
123 struct host1x_subdev *subdev)
124 {
125 struct host1x_client *client = subdev->client;
126 int err;
127
128 /*
129 * If all subdevices have been activated, we're about to remove the
130 * first active subdevice, so unload the driver first.
131 */
132 if (list_empty(&device->subdevs)) {
133 err = device->driver->remove(device);
134 if (err < 0)
135 dev_err(&device->dev, "remove failed: %d\n", err);
136 }
137
138 /*
139 * Move the subdevice back to the list of idle subdevices and remove
140 * it from list of clients.
141 */
142 mutex_lock(&device->clients_lock);
143 subdev->client = NULL;
144 client->parent = NULL;
145 list_move_tail(&subdev->list, &device->subdevs);
146 /*
147 * XXX: Perhaps don't do this here, but rather explicitly remove it
148 * when the device is about to be deleted.
149 *
150 * This is somewhat complicated by the fact that this function is
151 * used to remove the subdevice when a client is unregistered but
152 * also when the composite device is about to be removed.
153 */
154 list_del_init(&client->list);
155 mutex_unlock(&device->clients_lock);
156 }
157
158 static void host1x_subdev_unregister(struct host1x_device *device,
159 struct host1x_subdev *subdev)
160 {
161 mutex_lock(&device->subdevs_lock);
162 __host1x_subdev_unregister(device, subdev);
163 mutex_unlock(&device->subdevs_lock);
164 }
165
166 int host1x_device_init(struct host1x_device *device)
167 {
168 struct host1x_client *client;
169 int err;
170
171 mutex_lock(&device->clients_lock);
172
173 list_for_each_entry(client, &device->clients, list) {
174 if (client->ops && client->ops->init) {
175 err = client->ops->init(client);
176 if (err < 0) {
177 dev_err(&device->dev,
178 "failed to initialize %s: %d\n",
179 dev_name(client->dev), err);
180 mutex_unlock(&device->clients_lock);
181 return err;
182 }
183 }
184 }
185
186 mutex_unlock(&device->clients_lock);
187
188 return 0;
189 }
190
191 int host1x_device_exit(struct host1x_device *device)
192 {
193 struct host1x_client *client;
194 int err;
195
196 mutex_lock(&device->clients_lock);
197
198 list_for_each_entry_reverse(client, &device->clients, list) {
199 if (client->ops && client->ops->exit) {
200 err = client->ops->exit(client);
201 if (err < 0) {
202 dev_err(&device->dev,
203 "failed to cleanup %s: %d\n",
204 dev_name(client->dev), err);
205 mutex_unlock(&device->clients_lock);
206 return err;
207 }
208 }
209 }
210
211 mutex_unlock(&device->clients_lock);
212
213 return 0;
214 }
215
216 static int host1x_register_client(struct host1x *host1x,
217 struct host1x_client *client)
218 {
219 struct host1x_device *device;
220 struct host1x_subdev *subdev;
221
222 mutex_lock(&host1x->devices_lock);
223
224 list_for_each_entry(device, &host1x->devices, list) {
225 list_for_each_entry(subdev, &device->subdevs, list) {
226 if (subdev->np == client->dev->of_node) {
227 host1x_subdev_register(device, subdev, client);
228 mutex_unlock(&host1x->devices_lock);
229 return 0;
230 }
231 }
232 }
233
234 mutex_unlock(&host1x->devices_lock);
235 return -ENODEV;
236 }
237
238 static int host1x_unregister_client(struct host1x *host1x,
239 struct host1x_client *client)
240 {
241 struct host1x_device *device, *dt;
242 struct host1x_subdev *subdev;
243
244 mutex_lock(&host1x->devices_lock);
245
246 list_for_each_entry_safe(device, dt, &host1x->devices, list) {
247 list_for_each_entry(subdev, &device->active, list) {
248 if (subdev->client == client) {
249 host1x_subdev_unregister(device, subdev);
250 mutex_unlock(&host1x->devices_lock);
251 return 0;
252 }
253 }
254 }
255
256 mutex_unlock(&host1x->devices_lock);
257 return -ENODEV;
258 }
259
260 struct bus_type host1x_bus_type = {
261 .name = "host1x",
262 };
263
264 int host1x_bus_init(void)
265 {
266 return bus_register(&host1x_bus_type);
267 }
268
269 void host1x_bus_exit(void)
270 {
271 bus_unregister(&host1x_bus_type);
272 }
273
274 static void host1x_device_release(struct device *dev)
275 {
276 struct host1x_device *device = to_host1x_device(dev);
277
278 kfree(device);
279 }
280
281 static int host1x_device_add(struct host1x *host1x,
282 struct host1x_driver *driver)
283 {
284 struct host1x_client *client, *tmp;
285 struct host1x_subdev *subdev;
286 struct host1x_device *device;
287 int err;
288
289 device = kzalloc(sizeof(*device), GFP_KERNEL);
290 if (!device)
291 return -ENOMEM;
292
293 mutex_init(&device->subdevs_lock);
294 INIT_LIST_HEAD(&device->subdevs);
295 INIT_LIST_HEAD(&device->active);
296 mutex_init(&device->clients_lock);
297 INIT_LIST_HEAD(&device->clients);
298 INIT_LIST_HEAD(&device->list);
299 device->driver = driver;
300
301 device->dev.coherent_dma_mask = host1x->dev->coherent_dma_mask;
302 device->dev.dma_mask = &device->dev.coherent_dma_mask;
303 device->dev.release = host1x_device_release;
304 dev_set_name(&device->dev, driver->name);
305 device->dev.bus = &host1x_bus_type;
306 device->dev.parent = host1x->dev;
307
308 err = device_register(&device->dev);
309 if (err < 0)
310 return err;
311
312 err = host1x_device_parse_dt(device);
313 if (err < 0) {
314 device_unregister(&device->dev);
315 return err;
316 }
317
318 mutex_lock(&host1x->devices_lock);
319 list_add_tail(&device->list, &host1x->devices);
320 mutex_unlock(&host1x->devices_lock);
321
322 mutex_lock(&clients_lock);
323
324 list_for_each_entry_safe(client, tmp, &clients, list) {
325 list_for_each_entry(subdev, &device->subdevs, list) {
326 if (subdev->np == client->dev->of_node) {
327 host1x_subdev_register(device, subdev, client);
328 break;
329 }
330 }
331 }
332
333 mutex_unlock(&clients_lock);
334
335 return 0;
336 }
337
338 /*
339 * Removes a device by first unregistering any subdevices and then removing
340 * itself from the list of devices.
341 *
342 * This function must be called with the host1x->devices_lock held.
343 */
344 static void host1x_device_del(struct host1x *host1x,
345 struct host1x_device *device)
346 {
347 struct host1x_subdev *subdev, *sd;
348 struct host1x_client *client, *cl;
349
350 mutex_lock(&device->subdevs_lock);
351
352 /* unregister subdevices */
353 list_for_each_entry_safe(subdev, sd, &device->active, list) {
354 /*
355 * host1x_subdev_unregister() will remove the client from
356 * any lists, so we'll need to manually add it back to the
357 * list of idle clients.
358 *
359 * XXX: Alternatively, perhaps don't remove the client from
360 * any lists in host1x_subdev_unregister() and instead do
361 * that explicitly from host1x_unregister_client()?
362 */
363 client = subdev->client;
364
365 __host1x_subdev_unregister(device, subdev);
366
367 /* add the client to the list of idle clients */
368 mutex_lock(&clients_lock);
369 list_add_tail(&client->list, &clients);
370 mutex_unlock(&clients_lock);
371 }
372
373 /* remove subdevices */
374 list_for_each_entry_safe(subdev, sd, &device->subdevs, list)
375 host1x_subdev_del(subdev);
376
377 mutex_unlock(&device->subdevs_lock);
378
379 /* move clients to idle list */
380 mutex_lock(&clients_lock);
381 mutex_lock(&device->clients_lock);
382
383 list_for_each_entry_safe(client, cl, &device->clients, list)
384 list_move_tail(&client->list, &clients);
385
386 mutex_unlock(&device->clients_lock);
387 mutex_unlock(&clients_lock);
388
389 /* finally remove the device */
390 list_del_init(&device->list);
391 device_unregister(&device->dev);
392 }
393
394 static void host1x_attach_driver(struct host1x *host1x,
395 struct host1x_driver *driver)
396 {
397 struct host1x_device *device;
398 int err;
399
400 mutex_lock(&host1x->devices_lock);
401
402 list_for_each_entry(device, &host1x->devices, list) {
403 if (device->driver == driver) {
404 mutex_unlock(&host1x->devices_lock);
405 return;
406 }
407 }
408
409 mutex_unlock(&host1x->devices_lock);
410
411 err = host1x_device_add(host1x, driver);
412 if (err < 0)
413 dev_err(host1x->dev, "failed to allocate device: %d\n", err);
414 }
415
416 static void host1x_detach_driver(struct host1x *host1x,
417 struct host1x_driver *driver)
418 {
419 struct host1x_device *device, *tmp;
420
421 mutex_lock(&host1x->devices_lock);
422
423 list_for_each_entry_safe(device, tmp, &host1x->devices, list)
424 if (device->driver == driver)
425 host1x_device_del(host1x, device);
426
427 mutex_unlock(&host1x->devices_lock);
428 }
429
430 int host1x_register(struct host1x *host1x)
431 {
432 struct host1x_driver *driver;
433
434 mutex_lock(&devices_lock);
435 list_add_tail(&host1x->list, &devices);
436 mutex_unlock(&devices_lock);
437
438 mutex_lock(&drivers_lock);
439
440 list_for_each_entry(driver, &drivers, list)
441 host1x_attach_driver(host1x, driver);
442
443 mutex_unlock(&drivers_lock);
444
445 return 0;
446 }
447
448 int host1x_unregister(struct host1x *host1x)
449 {
450 struct host1x_driver *driver;
451
452 mutex_lock(&drivers_lock);
453
454 list_for_each_entry(driver, &drivers, list)
455 host1x_detach_driver(host1x, driver);
456
457 mutex_unlock(&drivers_lock);
458
459 mutex_lock(&devices_lock);
460 list_del_init(&host1x->list);
461 mutex_unlock(&devices_lock);
462
463 return 0;
464 }
465
466 int host1x_driver_register(struct host1x_driver *driver)
467 {
468 struct host1x *host1x;
469
470 INIT_LIST_HEAD(&driver->list);
471
472 mutex_lock(&drivers_lock);
473 list_add_tail(&driver->list, &drivers);
474 mutex_unlock(&drivers_lock);
475
476 mutex_lock(&devices_lock);
477
478 list_for_each_entry(host1x, &devices, list)
479 host1x_attach_driver(host1x, driver);
480
481 mutex_unlock(&devices_lock);
482
483 return 0;
484 }
485 EXPORT_SYMBOL(host1x_driver_register);
486
487 void host1x_driver_unregister(struct host1x_driver *driver)
488 {
489 mutex_lock(&drivers_lock);
490 list_del_init(&driver->list);
491 mutex_unlock(&drivers_lock);
492 }
493 EXPORT_SYMBOL(host1x_driver_unregister);
494
495 int host1x_client_register(struct host1x_client *client)
496 {
497 struct host1x *host1x;
498 int err;
499
500 mutex_lock(&devices_lock);
501
502 list_for_each_entry(host1x, &devices, list) {
503 err = host1x_register_client(host1x, client);
504 if (!err) {
505 mutex_unlock(&devices_lock);
506 return 0;
507 }
508 }
509
510 mutex_unlock(&devices_lock);
511
512 mutex_lock(&clients_lock);
513 list_add_tail(&client->list, &clients);
514 mutex_unlock(&clients_lock);
515
516 return 0;
517 }
518 EXPORT_SYMBOL(host1x_client_register);
519
520 int host1x_client_unregister(struct host1x_client *client)
521 {
522 struct host1x_client *c;
523 struct host1x *host1x;
524 int err;
525
526 mutex_lock(&devices_lock);
527
528 list_for_each_entry(host1x, &devices, list) {
529 err = host1x_unregister_client(host1x, client);
530 if (!err) {
531 mutex_unlock(&devices_lock);
532 return 0;
533 }
534 }
535
536 mutex_unlock(&devices_lock);
537 mutex_lock(&clients_lock);
538
539 list_for_each_entry(c, &clients, list) {
540 if (c == client) {
541 list_del_init(&c->list);
542 break;
543 }
544 }
545
546 mutex_unlock(&clients_lock);
547
548 return 0;
549 }
550 EXPORT_SYMBOL(host1x_client_unregister);