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 | static int drm_client_open(struct drm_client_dev *client) |
36 | { |
37 | struct drm_device *dev = client->dev; |
38 | struct drm_file *file; |
39 | |
40 | file = drm_file_alloc(minor: dev->primary); |
41 | if (IS_ERR(ptr: file)) |
42 | return PTR_ERR(ptr: file); |
43 | |
44 | mutex_lock(&dev->filelist_mutex); |
45 | list_add(new: &file->lhead, head: &dev->filelist_internal); |
46 | mutex_unlock(lock: &dev->filelist_mutex); |
47 | |
48 | client->file = file; |
49 | |
50 | return 0; |
51 | } |
52 | |
53 | static void drm_client_close(struct drm_client_dev *client) |
54 | { |
55 | struct drm_device *dev = client->dev; |
56 | |
57 | mutex_lock(&dev->filelist_mutex); |
58 | list_del(entry: &client->file->lhead); |
59 | mutex_unlock(lock: &dev->filelist_mutex); |
60 | |
61 | drm_file_free(file: client->file); |
62 | } |
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 | 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 | if (!drm_core_check_feature(dev, feature: DRIVER_MODESET) || !dev->driver->dumb_create) |
85 | return -EOPNOTSUPP; |
86 | |
87 | if (funcs && !try_module_get(module: funcs->owner)) |
88 | return -ENODEV; |
89 | |
90 | client->dev = dev; |
91 | client->name = name; |
92 | client->funcs = funcs; |
93 | |
94 | ret = drm_client_modeset_create(client); |
95 | if (ret) |
96 | goto err_put_module; |
97 | |
98 | ret = drm_client_open(client); |
99 | if (ret) |
100 | goto err_free; |
101 | |
102 | drm_dev_get(dev); |
103 | |
104 | return 0; |
105 | |
106 | err_free: |
107 | drm_client_modeset_free(client); |
108 | err_put_module: |
109 | if (funcs) |
110 | module_put(module: 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 | void drm_client_register(struct drm_client_dev *client) |
131 | { |
132 | struct drm_device *dev = client->dev; |
133 | int ret; |
134 | |
135 | mutex_lock(&dev->clientlist_mutex); |
136 | list_add(new: &client->list, head: &dev->clientlist); |
137 | |
138 | 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 | ret = client->funcs->hotplug(client); |
150 | if (ret) |
151 | drm_dbg_kms(dev, "client hotplug ret=%d\n" , ret); |
152 | } |
153 | mutex_unlock(lock: &dev->clientlist_mutex); |
154 | } |
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 | void drm_client_release(struct drm_client_dev *client) |
172 | { |
173 | struct drm_device *dev = client->dev; |
174 | |
175 | drm_dbg_kms(dev, "%s\n" , client->name); |
176 | |
177 | drm_client_modeset_free(client); |
178 | drm_client_close(client); |
179 | drm_dev_put(dev); |
180 | if (client->funcs) |
181 | module_put(module: client->funcs->owner); |
182 | } |
183 | EXPORT_SYMBOL(drm_client_release); |
184 | |
185 | void drm_client_dev_unregister(struct drm_device *dev) |
186 | { |
187 | struct drm_client_dev *client, *tmp; |
188 | |
189 | if (!drm_core_check_feature(dev, feature: DRIVER_MODESET)) |
190 | return; |
191 | |
192 | mutex_lock(&dev->clientlist_mutex); |
193 | list_for_each_entry_safe(client, tmp, &dev->clientlist, list) { |
194 | list_del(entry: &client->list); |
195 | if (client->funcs && client->funcs->unregister) { |
196 | client->funcs->unregister(client); |
197 | } else { |
198 | drm_client_release(client); |
199 | kfree(objp: client); |
200 | } |
201 | } |
202 | mutex_unlock(lock: &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 | void drm_client_dev_hotplug(struct drm_device *dev) |
215 | { |
216 | struct drm_client_dev *client; |
217 | int ret; |
218 | |
219 | if (!drm_core_check_feature(dev, feature: DRIVER_MODESET)) |
220 | return; |
221 | |
222 | if (!dev->mode_config.num_connector) { |
223 | drm_dbg_kms(dev, "No connectors found, will not send hotplug events!\n" ); |
224 | return; |
225 | } |
226 | |
227 | mutex_lock(&dev->clientlist_mutex); |
228 | list_for_each_entry(client, &dev->clientlist, list) { |
229 | if (!client->funcs || !client->funcs->hotplug) |
230 | continue; |
231 | |
232 | if (client->hotplug_failed) |
233 | continue; |
234 | |
235 | ret = client->funcs->hotplug(client); |
236 | drm_dbg_kms(dev, "%s: ret=%d\n" , client->name, ret); |
237 | if (ret) |
238 | client->hotplug_failed = true; |
239 | } |
240 | mutex_unlock(lock: &dev->clientlist_mutex); |
241 | } |
242 | EXPORT_SYMBOL(drm_client_dev_hotplug); |
243 | |
244 | void drm_client_dev_restore(struct drm_device *dev) |
245 | { |
246 | struct drm_client_dev *client; |
247 | int ret; |
248 | |
249 | if (!drm_core_check_feature(dev, feature: DRIVER_MODESET)) |
250 | return; |
251 | |
252 | mutex_lock(&dev->clientlist_mutex); |
253 | list_for_each_entry(client, &dev->clientlist, list) { |
254 | if (!client->funcs || !client->funcs->restore) |
255 | continue; |
256 | |
257 | ret = client->funcs->restore(client); |
258 | drm_dbg_kms(dev, "%s: ret=%d\n" , client->name, ret); |
259 | if (!ret) /* The first one to return zero gets the privilege to restore */ |
260 | break; |
261 | } |
262 | mutex_unlock(lock: &dev->clientlist_mutex); |
263 | } |
264 | |
265 | static void drm_client_buffer_delete(struct drm_client_buffer *buffer) |
266 | { |
267 | if (buffer->gem) { |
268 | drm_gem_vunmap_unlocked(obj: buffer->gem, map: &buffer->map); |
269 | drm_gem_object_put(obj: buffer->gem); |
270 | } |
271 | |
272 | kfree(objp: buffer); |
273 | } |
274 | |
275 | static struct drm_client_buffer * |
276 | drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height, |
277 | u32 format, u32 *handle) |
278 | { |
279 | const struct drm_format_info *info = drm_format_info(format); |
280 | struct drm_mode_create_dumb dumb_args = { }; |
281 | struct drm_device *dev = client->dev; |
282 | struct drm_client_buffer *buffer; |
283 | struct drm_gem_object *obj; |
284 | int ret; |
285 | |
286 | buffer = kzalloc(size: sizeof(*buffer), GFP_KERNEL); |
287 | if (!buffer) |
288 | return ERR_PTR(error: -ENOMEM); |
289 | |
290 | buffer->client = client; |
291 | |
292 | dumb_args.width = width; |
293 | dumb_args.height = height; |
294 | dumb_args.bpp = drm_format_info_bpp(info, plane: 0); |
295 | ret = drm_mode_create_dumb(dev, args: &dumb_args, file_priv: client->file); |
296 | if (ret) |
297 | goto err_delete; |
298 | |
299 | obj = drm_gem_object_lookup(filp: client->file, handle: dumb_args.handle); |
300 | if (!obj) { |
301 | ret = -ENOENT; |
302 | goto err_delete; |
303 | } |
304 | |
305 | buffer->pitch = dumb_args.pitch; |
306 | buffer->gem = obj; |
307 | *handle = dumb_args.handle; |
308 | |
309 | return buffer; |
310 | |
311 | err_delete: |
312 | drm_client_buffer_delete(buffer); |
313 | |
314 | return ERR_PTR(error: 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 | drm_client_buffer_vmap(struct drm_client_buffer *buffer, |
339 | struct iosys_map *map_copy) |
340 | { |
341 | 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 | ret = drm_gem_vmap_unlocked(obj: buffer->gem, map); |
353 | if (ret) |
354 | return ret; |
355 | |
356 | *map_copy = *map; |
357 | |
358 | 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 | void drm_client_buffer_vunmap(struct drm_client_buffer *buffer) |
371 | { |
372 | struct iosys_map *map = &buffer->map; |
373 | |
374 | drm_gem_vunmap_unlocked(obj: buffer->gem, map); |
375 | } |
376 | EXPORT_SYMBOL(drm_client_buffer_vunmap); |
377 | |
378 | static void drm_client_buffer_rmfb(struct drm_client_buffer *buffer) |
379 | { |
380 | int ret; |
381 | |
382 | if (!buffer->fb) |
383 | return; |
384 | |
385 | ret = drm_mode_rmfb(dev: buffer->client->dev, fb_id: buffer->fb->base.id, file_priv: buffer->client->file); |
386 | if (ret) |
387 | drm_err(buffer->client->dev, |
388 | "Error removing FB:%u (%d)\n" , buffer->fb->base.id, ret); |
389 | |
390 | buffer->fb = NULL; |
391 | } |
392 | |
393 | static int drm_client_buffer_addfb(struct drm_client_buffer *buffer, |
394 | u32 width, u32 height, u32 format, |
395 | u32 handle) |
396 | { |
397 | struct drm_client_dev *client = buffer->client; |
398 | struct drm_mode_fb_cmd2 fb_req = { }; |
399 | int ret; |
400 | |
401 | fb_req.width = width; |
402 | fb_req.height = height; |
403 | fb_req.pixel_format = format; |
404 | fb_req.handles[0] = handle; |
405 | fb_req.pitches[0] = buffer->pitch; |
406 | |
407 | ret = drm_mode_addfb2(dev: client->dev, data: &fb_req, file_priv: client->file); |
408 | if (ret) |
409 | return ret; |
410 | |
411 | buffer->fb = drm_framebuffer_lookup(dev: client->dev, file_priv: buffer->client->file, id: fb_req.fb_id); |
412 | if (WARN_ON(!buffer->fb)) |
413 | return -ENOENT; |
414 | |
415 | /* drop the reference we picked up in framebuffer lookup */ |
416 | drm_framebuffer_put(fb: buffer->fb); |
417 | |
418 | strscpy(p: buffer->fb->comm, q: client->name, size: TASK_COMM_LEN); |
419 | |
420 | return 0; |
421 | } |
422 | |
423 | /** |
424 | * drm_client_framebuffer_create - Create a client framebuffer |
425 | * @client: DRM client |
426 | * @width: Framebuffer width |
427 | * @height: Framebuffer height |
428 | * @format: Buffer format |
429 | * |
430 | * This function creates a &drm_client_buffer which consists of a |
431 | * &drm_framebuffer backed by a dumb buffer. |
432 | * Call drm_client_framebuffer_delete() to free the buffer. |
433 | * |
434 | * Returns: |
435 | * Pointer to a client buffer or an error pointer on failure. |
436 | */ |
437 | struct drm_client_buffer * |
438 | drm_client_framebuffer_create(struct drm_client_dev *client, u32 width, u32 height, u32 format) |
439 | { |
440 | struct drm_client_buffer *buffer; |
441 | u32 handle; |
442 | int ret; |
443 | |
444 | buffer = drm_client_buffer_create(client, width, height, format, |
445 | handle: &handle); |
446 | if (IS_ERR(ptr: buffer)) |
447 | return buffer; |
448 | |
449 | ret = drm_client_buffer_addfb(buffer, width, height, format, handle); |
450 | |
451 | /* |
452 | * The handle is only needed for creating the framebuffer, destroy it |
453 | * again to solve a circular dependency should anybody export the GEM |
454 | * object as DMA-buf. The framebuffer and our buffer structure are still |
455 | * holding references to the GEM object to prevent its destruction. |
456 | */ |
457 | drm_mode_destroy_dumb(dev: client->dev, handle, file_priv: client->file); |
458 | |
459 | if (ret) { |
460 | drm_client_buffer_delete(buffer); |
461 | return ERR_PTR(error: ret); |
462 | } |
463 | |
464 | return buffer; |
465 | } |
466 | EXPORT_SYMBOL(drm_client_framebuffer_create); |
467 | |
468 | /** |
469 | * drm_client_framebuffer_delete - Delete a client framebuffer |
470 | * @buffer: DRM client buffer (can be NULL) |
471 | */ |
472 | void drm_client_framebuffer_delete(struct drm_client_buffer *buffer) |
473 | { |
474 | if (!buffer) |
475 | return; |
476 | |
477 | drm_client_buffer_rmfb(buffer); |
478 | drm_client_buffer_delete(buffer); |
479 | } |
480 | EXPORT_SYMBOL(drm_client_framebuffer_delete); |
481 | |
482 | /** |
483 | * drm_client_framebuffer_flush - Manually flush client framebuffer |
484 | * @buffer: DRM client buffer (can be NULL) |
485 | * @rect: Damage rectangle (if NULL flushes all) |
486 | * |
487 | * This calls &drm_framebuffer_funcs->dirty (if present) to flush buffer changes |
488 | * for drivers that need it. |
489 | * |
490 | * Returns: |
491 | * Zero on success or negative error code on failure. |
492 | */ |
493 | int drm_client_framebuffer_flush(struct drm_client_buffer *buffer, struct drm_rect *rect) |
494 | { |
495 | if (!buffer || !buffer->fb || !buffer->fb->funcs->dirty) |
496 | return 0; |
497 | |
498 | if (rect) { |
499 | struct drm_clip_rect clip = { |
500 | .x1 = rect->x1, |
501 | .y1 = rect->y1, |
502 | .x2 = rect->x2, |
503 | .y2 = rect->y2, |
504 | }; |
505 | |
506 | return buffer->fb->funcs->dirty(buffer->fb, buffer->client->file, |
507 | 0, 0, &clip, 1); |
508 | } |
509 | |
510 | return buffer->fb->funcs->dirty(buffer->fb, buffer->client->file, |
511 | 0, 0, NULL, 0); |
512 | } |
513 | EXPORT_SYMBOL(drm_client_framebuffer_flush); |
514 | |
515 | #ifdef CONFIG_DEBUG_FS |
516 | static int drm_client_debugfs_internal_clients(struct seq_file *m, void *data) |
517 | { |
518 | struct drm_debugfs_entry *entry = m->private; |
519 | struct drm_device *dev = entry->dev; |
520 | struct drm_printer p = drm_seq_file_printer(f: m); |
521 | struct drm_client_dev *client; |
522 | |
523 | mutex_lock(&dev->clientlist_mutex); |
524 | list_for_each_entry(client, &dev->clientlist, list) |
525 | drm_printf(p: &p, f: "%s\n" , client->name); |
526 | mutex_unlock(lock: &dev->clientlist_mutex); |
527 | |
528 | return 0; |
529 | } |
530 | |
531 | static const struct drm_debugfs_info drm_client_debugfs_list[] = { |
532 | { "internal_clients" , drm_client_debugfs_internal_clients, 0 }, |
533 | }; |
534 | |
535 | void drm_client_debugfs_init(struct drm_device *dev) |
536 | { |
537 | drm_debugfs_add_files(dev, files: drm_client_debugfs_list, |
538 | ARRAY_SIZE(drm_client_debugfs_list)); |
539 | } |
540 | #endif |
541 | |