Line data Source code
1 : // SPDX-License-Identifier: GPL-2.0 or MIT
2 : /*
3 : * Copyright 2018 Noralf Trønnes
4 : */
5 :
6 : #include <linux/iosys-map.h>
7 : #include <linux/list.h>
8 : #include <linux/module.h>
9 : #include <linux/mutex.h>
10 : #include <linux/seq_file.h>
11 : #include <linux/slab.h>
12 :
13 : #include <drm/drm_client.h>
14 : #include <drm/drm_debugfs.h>
15 : #include <drm/drm_device.h>
16 : #include <drm/drm_drv.h>
17 : #include <drm/drm_file.h>
18 : #include <drm/drm_fourcc.h>
19 : #include <drm/drm_framebuffer.h>
20 : #include <drm/drm_gem.h>
21 : #include <drm/drm_mode.h>
22 : #include <drm/drm_print.h>
23 :
24 : #include "drm_crtc_internal.h"
25 : #include "drm_internal.h"
26 :
27 : /**
28 : * DOC: overview
29 : *
30 : * This library provides support for clients running in the kernel like fbdev and bootsplash.
31 : *
32 : * GEM drivers which provide a GEM based dumb buffer with a virtual address are supported.
33 : */
34 :
35 0 : static int drm_client_open(struct drm_client_dev *client)
36 : {
37 0 : struct drm_device *dev = client->dev;
38 : struct drm_file *file;
39 :
40 0 : file = drm_file_alloc(dev->primary);
41 0 : if (IS_ERR(file))
42 0 : return PTR_ERR(file);
43 :
44 0 : mutex_lock(&dev->filelist_mutex);
45 0 : list_add(&file->lhead, &dev->filelist_internal);
46 0 : mutex_unlock(&dev->filelist_mutex);
47 :
48 0 : client->file = file;
49 :
50 : return 0;
51 : }
52 :
53 0 : static void drm_client_close(struct drm_client_dev *client)
54 : {
55 0 : struct drm_device *dev = client->dev;
56 :
57 0 : mutex_lock(&dev->filelist_mutex);
58 0 : list_del(&client->file->lhead);
59 0 : mutex_unlock(&dev->filelist_mutex);
60 :
61 0 : drm_file_free(client->file);
62 0 : }
63 :
64 : /**
65 : * drm_client_init - Initialise a DRM client
66 : * @dev: DRM device
67 : * @client: DRM client
68 : * @name: Client name
69 : * @funcs: DRM client functions (optional)
70 : *
71 : * This initialises the client and opens a &drm_file.
72 : * Use drm_client_register() to complete the process.
73 : * The caller needs to hold a reference on @dev before calling this function.
74 : * The client is freed when the &drm_device is unregistered. See drm_client_release().
75 : *
76 : * Returns:
77 : * Zero on success or negative error code on failure.
78 : */
79 0 : int drm_client_init(struct drm_device *dev, struct drm_client_dev *client,
80 : const char *name, const struct drm_client_funcs *funcs)
81 : {
82 : int ret;
83 :
84 0 : if (!drm_core_check_feature(dev, DRIVER_MODESET) || !dev->driver->dumb_create)
85 : return -EOPNOTSUPP;
86 :
87 : if (funcs && !try_module_get(funcs->owner))
88 : return -ENODEV;
89 :
90 0 : client->dev = dev;
91 0 : client->name = name;
92 0 : client->funcs = funcs;
93 :
94 0 : ret = drm_client_modeset_create(client);
95 0 : if (ret)
96 : goto err_put_module;
97 :
98 0 : ret = drm_client_open(client);
99 0 : if (ret)
100 : goto err_free;
101 :
102 0 : drm_dev_get(dev);
103 :
104 0 : return 0;
105 :
106 : err_free:
107 0 : drm_client_modeset_free(client);
108 : err_put_module:
109 : if (funcs)
110 : module_put(funcs->owner);
111 :
112 : return ret;
113 : }
114 : EXPORT_SYMBOL(drm_client_init);
115 :
116 : /**
117 : * drm_client_register - Register client
118 : * @client: DRM client
119 : *
120 : * Add the client to the &drm_device client list to activate its callbacks.
121 : * @client must be initialized by a call to drm_client_init(). After
122 : * drm_client_register() it is no longer permissible to call drm_client_release()
123 : * directly (outside the unregister callback), instead cleanup will happen
124 : * automatically on driver unload.
125 : *
126 : * Registering a client generates a hotplug event that allows the client
127 : * to set up its display from pre-existing outputs. The client must have
128 : * initialized its state to able to handle the hotplug event successfully.
129 : */
130 0 : void drm_client_register(struct drm_client_dev *client)
131 : {
132 0 : struct drm_device *dev = client->dev;
133 : int ret;
134 :
135 0 : mutex_lock(&dev->clientlist_mutex);
136 0 : list_add(&client->list, &dev->clientlist);
137 :
138 0 : if (client->funcs && client->funcs->hotplug) {
139 : /*
140 : * Perform an initial hotplug event to pick up the
141 : * display configuration for the client. This step
142 : * has to be performed *after* registering the client
143 : * in the list of clients, or a concurrent hotplug
144 : * event might be lost; leaving the display off.
145 : *
146 : * Hold the clientlist_mutex as for a regular hotplug
147 : * event.
148 : */
149 0 : ret = client->funcs->hotplug(client);
150 0 : if (ret)
151 0 : drm_dbg_kms(dev, "client hotplug ret=%d\n", ret);
152 : }
153 0 : mutex_unlock(&dev->clientlist_mutex);
154 0 : }
155 : EXPORT_SYMBOL(drm_client_register);
156 :
157 : /**
158 : * drm_client_release - Release DRM client resources
159 : * @client: DRM client
160 : *
161 : * Releases resources by closing the &drm_file that was opened by drm_client_init().
162 : * It is called automatically if the &drm_client_funcs.unregister callback is _not_ set.
163 : *
164 : * This function should only be called from the unregister callback. An exception
165 : * is fbdev which cannot free the buffer if userspace has open file descriptors.
166 : *
167 : * Note:
168 : * Clients cannot initiate a release by themselves. This is done to keep the code simple.
169 : * The driver has to be unloaded before the client can be unloaded.
170 : */
171 0 : void drm_client_release(struct drm_client_dev *client)
172 : {
173 0 : struct drm_device *dev = client->dev;
174 :
175 0 : drm_dbg_kms(dev, "%s\n", client->name);
176 :
177 0 : drm_client_modeset_free(client);
178 0 : drm_client_close(client);
179 0 : drm_dev_put(dev);
180 0 : if (client->funcs)
181 : module_put(client->funcs->owner);
182 0 : }
183 : EXPORT_SYMBOL(drm_client_release);
184 :
185 0 : void drm_client_dev_unregister(struct drm_device *dev)
186 : {
187 : struct drm_client_dev *client, *tmp;
188 :
189 0 : if (!drm_core_check_feature(dev, DRIVER_MODESET))
190 : return;
191 :
192 0 : mutex_lock(&dev->clientlist_mutex);
193 0 : list_for_each_entry_safe(client, tmp, &dev->clientlist, list) {
194 0 : list_del(&client->list);
195 0 : if (client->funcs && client->funcs->unregister) {
196 0 : client->funcs->unregister(client);
197 : } else {
198 0 : drm_client_release(client);
199 0 : kfree(client);
200 : }
201 : }
202 0 : mutex_unlock(&dev->clientlist_mutex);
203 : }
204 :
205 : /**
206 : * drm_client_dev_hotplug - Send hotplug event to clients
207 : * @dev: DRM device
208 : *
209 : * This function calls the &drm_client_funcs.hotplug callback on the attached clients.
210 : *
211 : * drm_kms_helper_hotplug_event() calls this function, so drivers that use it
212 : * don't need to call this function themselves.
213 : */
214 0 : void drm_client_dev_hotplug(struct drm_device *dev)
215 : {
216 : struct drm_client_dev *client;
217 : int ret;
218 :
219 0 : if (!drm_core_check_feature(dev, DRIVER_MODESET))
220 : return;
221 :
222 0 : if (!dev->mode_config.num_connector) {
223 0 : drm_dbg_kms(dev, "No connectors found, will not send hotplug events!\n");
224 0 : return;
225 : }
226 :
227 0 : mutex_lock(&dev->clientlist_mutex);
228 0 : list_for_each_entry(client, &dev->clientlist, list) {
229 0 : if (!client->funcs || !client->funcs->hotplug)
230 0 : continue;
231 :
232 0 : if (client->hotplug_failed)
233 0 : continue;
234 :
235 0 : ret = client->funcs->hotplug(client);
236 0 : drm_dbg_kms(dev, "%s: ret=%d\n", client->name, ret);
237 0 : if (ret)
238 0 : client->hotplug_failed = true;
239 : }
240 0 : mutex_unlock(&dev->clientlist_mutex);
241 : }
242 : EXPORT_SYMBOL(drm_client_dev_hotplug);
243 :
244 0 : void drm_client_dev_restore(struct drm_device *dev)
245 : {
246 : struct drm_client_dev *client;
247 : int ret;
248 :
249 0 : if (!drm_core_check_feature(dev, DRIVER_MODESET))
250 : return;
251 :
252 0 : mutex_lock(&dev->clientlist_mutex);
253 0 : list_for_each_entry(client, &dev->clientlist, list) {
254 0 : if (!client->funcs || !client->funcs->restore)
255 0 : continue;
256 :
257 0 : ret = client->funcs->restore(client);
258 0 : drm_dbg_kms(dev, "%s: ret=%d\n", client->name, ret);
259 0 : if (!ret) /* The first one to return zero gets the privilege to restore */
260 : break;
261 : }
262 0 : mutex_unlock(&dev->clientlist_mutex);
263 : }
264 :
265 0 : static void drm_client_buffer_delete(struct drm_client_buffer *buffer)
266 : {
267 0 : if (buffer->gem) {
268 0 : drm_gem_vunmap_unlocked(buffer->gem, &buffer->map);
269 0 : drm_gem_object_put(buffer->gem);
270 : }
271 :
272 0 : kfree(buffer);
273 0 : }
274 :
275 : static struct drm_client_buffer *
276 0 : drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height,
277 : u32 format, u32 *handle)
278 : {
279 0 : const struct drm_format_info *info = drm_format_info(format);
280 0 : struct drm_mode_create_dumb dumb_args = { };
281 0 : struct drm_device *dev = client->dev;
282 : struct drm_client_buffer *buffer;
283 : struct drm_gem_object *obj;
284 : int ret;
285 :
286 0 : buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
287 0 : if (!buffer)
288 : return ERR_PTR(-ENOMEM);
289 :
290 0 : buffer->client = client;
291 :
292 0 : dumb_args.width = width;
293 0 : dumb_args.height = height;
294 0 : dumb_args.bpp = drm_format_info_bpp(info, 0);
295 0 : ret = drm_mode_create_dumb(dev, &dumb_args, client->file);
296 0 : if (ret)
297 : goto err_delete;
298 :
299 0 : obj = drm_gem_object_lookup(client->file, dumb_args.handle);
300 0 : if (!obj) {
301 : ret = -ENOENT;
302 : goto err_delete;
303 : }
304 :
305 0 : buffer->pitch = dumb_args.pitch;
306 0 : buffer->gem = obj;
307 0 : *handle = dumb_args.handle;
308 :
309 0 : return buffer;
310 :
311 : err_delete:
312 0 : drm_client_buffer_delete(buffer);
313 :
314 0 : return ERR_PTR(ret);
315 : }
316 :
317 : /**
318 : * drm_client_buffer_vmap - Map DRM client buffer into address space
319 : * @buffer: DRM client buffer
320 : * @map_copy: Returns the mapped memory's address
321 : *
322 : * This function maps a client buffer into kernel address space. If the
323 : * buffer is already mapped, it returns the existing mapping's address.
324 : *
325 : * Client buffer mappings are not ref'counted. Each call to
326 : * drm_client_buffer_vmap() should be followed by a call to
327 : * drm_client_buffer_vunmap(); or the client buffer should be mapped
328 : * throughout its lifetime.
329 : *
330 : * The returned address is a copy of the internal value. In contrast to
331 : * other vmap interfaces, you don't need it for the client's vunmap
332 : * function. So you can modify it at will during blit and draw operations.
333 : *
334 : * Returns:
335 : * 0 on success, or a negative errno code otherwise.
336 : */
337 : int
338 0 : drm_client_buffer_vmap(struct drm_client_buffer *buffer,
339 : struct iosys_map *map_copy)
340 : {
341 0 : struct iosys_map *map = &buffer->map;
342 : int ret;
343 :
344 : /*
345 : * FIXME: The dependency on GEM here isn't required, we could
346 : * convert the driver handle to a dma-buf instead and use the
347 : * backend-agnostic dma-buf vmap support instead. This would
348 : * require that the handle2fd prime ioctl is reworked to pull the
349 : * fd_install step out of the driver backend hooks, to make that
350 : * final step optional for internal users.
351 : */
352 0 : ret = drm_gem_vmap_unlocked(buffer->gem, map);
353 0 : if (ret)
354 : return ret;
355 :
356 0 : *map_copy = *map;
357 :
358 0 : return 0;
359 : }
360 : EXPORT_SYMBOL(drm_client_buffer_vmap);
361 :
362 : /**
363 : * drm_client_buffer_vunmap - Unmap DRM client buffer
364 : * @buffer: DRM client buffer
365 : *
366 : * This function removes a client buffer's memory mapping. Calling this
367 : * function is only required by clients that manage their buffer mappings
368 : * by themselves.
369 : */
370 0 : void drm_client_buffer_vunmap(struct drm_client_buffer *buffer)
371 : {
372 0 : struct iosys_map *map = &buffer->map;
373 :
374 0 : drm_gem_vunmap_unlocked(buffer->gem, map);
375 0 : }
376 : EXPORT_SYMBOL(drm_client_buffer_vunmap);
377 :
378 0 : static void drm_client_buffer_rmfb(struct drm_client_buffer *buffer)
379 : {
380 : int ret;
381 :
382 0 : if (!buffer->fb)
383 : return;
384 :
385 0 : ret = drm_mode_rmfb(buffer->client->dev, buffer->fb->base.id, buffer->client->file);
386 0 : if (ret)
387 0 : drm_err(buffer->client->dev,
388 : "Error removing FB:%u (%d)\n", buffer->fb->base.id, ret);
389 :
390 0 : buffer->fb = NULL;
391 : }
392 :
393 0 : static int drm_client_buffer_addfb(struct drm_client_buffer *buffer,
394 : u32 width, u32 height, u32 format,
395 : u32 handle)
396 : {
397 0 : struct drm_client_dev *client = buffer->client;
398 0 : struct drm_mode_fb_cmd fb_req = { };
399 : const struct drm_format_info *info;
400 : int ret;
401 :
402 0 : info = drm_format_info(format);
403 0 : fb_req.bpp = drm_format_info_bpp(info, 0);
404 0 : fb_req.depth = info->depth;
405 0 : fb_req.width = width;
406 0 : fb_req.height = height;
407 0 : fb_req.handle = handle;
408 0 : fb_req.pitch = buffer->pitch;
409 :
410 0 : ret = drm_mode_addfb(client->dev, &fb_req, client->file);
411 0 : if (ret)
412 : return ret;
413 :
414 0 : buffer->fb = drm_framebuffer_lookup(client->dev, buffer->client->file, fb_req.fb_id);
415 0 : if (WARN_ON(!buffer->fb))
416 : return -ENOENT;
417 :
418 : /* drop the reference we picked up in framebuffer lookup */
419 0 : drm_framebuffer_put(buffer->fb);
420 :
421 0 : strscpy(buffer->fb->comm, client->name, TASK_COMM_LEN);
422 :
423 : return 0;
424 : }
425 :
426 : /**
427 : * drm_client_framebuffer_create - Create a client framebuffer
428 : * @client: DRM client
429 : * @width: Framebuffer width
430 : * @height: Framebuffer height
431 : * @format: Buffer format
432 : *
433 : * This function creates a &drm_client_buffer which consists of a
434 : * &drm_framebuffer backed by a dumb buffer.
435 : * Call drm_client_framebuffer_delete() to free the buffer.
436 : *
437 : * Returns:
438 : * Pointer to a client buffer or an error pointer on failure.
439 : */
440 : struct drm_client_buffer *
441 0 : drm_client_framebuffer_create(struct drm_client_dev *client, u32 width, u32 height, u32 format)
442 : {
443 : struct drm_client_buffer *buffer;
444 : u32 handle;
445 : int ret;
446 :
447 0 : buffer = drm_client_buffer_create(client, width, height, format,
448 : &handle);
449 0 : if (IS_ERR(buffer))
450 : return buffer;
451 :
452 0 : ret = drm_client_buffer_addfb(buffer, width, height, format, handle);
453 :
454 : /*
455 : * The handle is only needed for creating the framebuffer, destroy it
456 : * again to solve a circular dependency should anybody export the GEM
457 : * object as DMA-buf. The framebuffer and our buffer structure are still
458 : * holding references to the GEM object to prevent its destruction.
459 : */
460 0 : drm_mode_destroy_dumb(client->dev, handle, client->file);
461 :
462 0 : if (ret) {
463 0 : drm_client_buffer_delete(buffer);
464 0 : return ERR_PTR(ret);
465 : }
466 :
467 : return buffer;
468 : }
469 : EXPORT_SYMBOL(drm_client_framebuffer_create);
470 :
471 : /**
472 : * drm_client_framebuffer_delete - Delete a client framebuffer
473 : * @buffer: DRM client buffer (can be NULL)
474 : */
475 0 : void drm_client_framebuffer_delete(struct drm_client_buffer *buffer)
476 : {
477 0 : if (!buffer)
478 : return;
479 :
480 0 : drm_client_buffer_rmfb(buffer);
481 0 : drm_client_buffer_delete(buffer);
482 : }
483 : EXPORT_SYMBOL(drm_client_framebuffer_delete);
484 :
485 : /**
486 : * drm_client_framebuffer_flush - Manually flush client framebuffer
487 : * @buffer: DRM client buffer (can be NULL)
488 : * @rect: Damage rectangle (if NULL flushes all)
489 : *
490 : * This calls &drm_framebuffer_funcs->dirty (if present) to flush buffer changes
491 : * for drivers that need it.
492 : *
493 : * Returns:
494 : * Zero on success or negative error code on failure.
495 : */
496 0 : int drm_client_framebuffer_flush(struct drm_client_buffer *buffer, struct drm_rect *rect)
497 : {
498 0 : if (!buffer || !buffer->fb || !buffer->fb->funcs->dirty)
499 : return 0;
500 :
501 0 : if (rect) {
502 0 : struct drm_clip_rect clip = {
503 0 : .x1 = rect->x1,
504 0 : .y1 = rect->y1,
505 0 : .x2 = rect->x2,
506 0 : .y2 = rect->y2,
507 : };
508 :
509 0 : return buffer->fb->funcs->dirty(buffer->fb, buffer->client->file,
510 : 0, 0, &clip, 1);
511 : }
512 :
513 0 : return buffer->fb->funcs->dirty(buffer->fb, buffer->client->file,
514 : 0, 0, NULL, 0);
515 : }
516 : EXPORT_SYMBOL(drm_client_framebuffer_flush);
517 :
518 : #ifdef CONFIG_DEBUG_FS
519 : static int drm_client_debugfs_internal_clients(struct seq_file *m, void *data)
520 : {
521 : struct drm_debugfs_entry *entry = m->private;
522 : struct drm_device *dev = entry->dev;
523 : struct drm_printer p = drm_seq_file_printer(m);
524 : struct drm_client_dev *client;
525 :
526 : mutex_lock(&dev->clientlist_mutex);
527 : list_for_each_entry(client, &dev->clientlist, list)
528 : drm_printf(&p, "%s\n", client->name);
529 : mutex_unlock(&dev->clientlist_mutex);
530 :
531 : return 0;
532 : }
533 :
534 : static const struct drm_debugfs_info drm_client_debugfs_list[] = {
535 : { "internal_clients", drm_client_debugfs_internal_clients, 0 },
536 : };
537 :
538 : void drm_client_debugfs_init(struct drm_minor *minor)
539 : {
540 : drm_debugfs_add_files(minor->dev, drm_client_debugfs_list,
541 : ARRAY_SIZE(drm_client_debugfs_list));
542 : }
543 : #endif
|