xref: /openbsd-src/sys/dev/pci/drm/drm_client.c (revision 1ad61ae0a79a724d2d3ec69e69c8e1d1ff6b53a0)
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(dev->primary);
41 	if (IS_ERR(file))
42 		return PTR_ERR(file);
43 
44 	mutex_lock(&dev->filelist_mutex);
45 	list_add(&file->lhead, &dev->filelist_internal);
46 	mutex_unlock(&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(&client->file->lhead);
59 	mutex_unlock(&dev->filelist_mutex);
60 
61 	drm_file_free(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, DRIVER_MODESET) || !dev->driver->dumb_create)
85 		return -EOPNOTSUPP;
86 
87 	if (funcs && !try_module_get(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(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(&client->list, &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(&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(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, 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(&client->list);
195 		if (client->funcs && client->funcs->unregister) {
196 			client->funcs->unregister(client);
197 		} else {
198 			drm_client_release(client);
199 			kfree(client);
200 		}
201 	}
202 	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 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, DRIVER_MODESET))
220 		return;
221 
222 	mutex_lock(&dev->clientlist_mutex);
223 	list_for_each_entry(client, &dev->clientlist, list) {
224 		if (!client->funcs || !client->funcs->hotplug)
225 			continue;
226 
227 		ret = client->funcs->hotplug(client);
228 		drm_dbg_kms(dev, "%s: ret=%d\n", client->name, ret);
229 	}
230 	mutex_unlock(&dev->clientlist_mutex);
231 }
232 EXPORT_SYMBOL(drm_client_dev_hotplug);
233 
234 void drm_client_dev_restore(struct drm_device *dev)
235 {
236 	struct drm_client_dev *client;
237 	int ret;
238 
239 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
240 		return;
241 
242 	mutex_lock(&dev->clientlist_mutex);
243 	list_for_each_entry(client, &dev->clientlist, list) {
244 		if (!client->funcs || !client->funcs->restore)
245 			continue;
246 
247 		ret = client->funcs->restore(client);
248 		drm_dbg_kms(dev, "%s: ret=%d\n", client->name, ret);
249 		if (!ret) /* The first one to return zero gets the privilege to restore */
250 			break;
251 	}
252 	mutex_unlock(&dev->clientlist_mutex);
253 }
254 
255 static void drm_client_buffer_delete(struct drm_client_buffer *buffer)
256 {
257 	struct drm_device *dev = buffer->client->dev;
258 
259 	drm_gem_vunmap(buffer->gem, &buffer->map);
260 
261 	if (buffer->gem)
262 		drm_gem_object_put(buffer->gem);
263 
264 	if (buffer->handle)
265 		drm_mode_destroy_dumb(dev, buffer->handle, buffer->client->file);
266 
267 	kfree(buffer);
268 }
269 
270 static struct drm_client_buffer *
271 drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height, u32 format)
272 {
273 	const struct drm_format_info *info = drm_format_info(format);
274 	struct drm_mode_create_dumb dumb_args = { };
275 	struct drm_device *dev = client->dev;
276 	struct drm_client_buffer *buffer;
277 	struct drm_gem_object *obj;
278 	int ret;
279 
280 	buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
281 	if (!buffer)
282 		return ERR_PTR(-ENOMEM);
283 
284 	buffer->client = client;
285 
286 	dumb_args.width = width;
287 	dumb_args.height = height;
288 	dumb_args.bpp = drm_format_info_bpp(info, 0);
289 	ret = drm_mode_create_dumb(dev, &dumb_args, client->file);
290 	if (ret)
291 		goto err_delete;
292 
293 	buffer->handle = dumb_args.handle;
294 	buffer->pitch = dumb_args.pitch;
295 
296 	obj = drm_gem_object_lookup(client->file, dumb_args.handle);
297 	if (!obj)  {
298 		ret = -ENOENT;
299 		goto err_delete;
300 	}
301 
302 	buffer->gem = obj;
303 
304 	return buffer;
305 
306 err_delete:
307 	drm_client_buffer_delete(buffer);
308 
309 	return ERR_PTR(ret);
310 }
311 
312 /**
313  * drm_client_buffer_vmap - Map DRM client buffer into address space
314  * @buffer: DRM client buffer
315  * @map_copy: Returns the mapped memory's address
316  *
317  * This function maps a client buffer into kernel address space. If the
318  * buffer is already mapped, it returns the existing mapping's address.
319  *
320  * Client buffer mappings are not ref'counted. Each call to
321  * drm_client_buffer_vmap() should be followed by a call to
322  * drm_client_buffer_vunmap(); or the client buffer should be mapped
323  * throughout its lifetime.
324  *
325  * The returned address is a copy of the internal value. In contrast to
326  * other vmap interfaces, you don't need it for the client's vunmap
327  * function. So you can modify it at will during blit and draw operations.
328  *
329  * Returns:
330  *	0 on success, or a negative errno code otherwise.
331  */
332 int
333 drm_client_buffer_vmap(struct drm_client_buffer *buffer,
334 		       struct iosys_map *map_copy)
335 {
336 	struct iosys_map *map = &buffer->map;
337 	int ret;
338 
339 	/*
340 	 * FIXME: The dependency on GEM here isn't required, we could
341 	 * convert the driver handle to a dma-buf instead and use the
342 	 * backend-agnostic dma-buf vmap support instead. This would
343 	 * require that the handle2fd prime ioctl is reworked to pull the
344 	 * fd_install step out of the driver backend hooks, to make that
345 	 * final step optional for internal users.
346 	 */
347 	ret = drm_gem_vmap(buffer->gem, map);
348 	if (ret)
349 		return ret;
350 
351 	*map_copy = *map;
352 
353 	return 0;
354 }
355 EXPORT_SYMBOL(drm_client_buffer_vmap);
356 
357 /**
358  * drm_client_buffer_vunmap - Unmap DRM client buffer
359  * @buffer: DRM client buffer
360  *
361  * This function removes a client buffer's memory mapping. Calling this
362  * function is only required by clients that manage their buffer mappings
363  * by themselves.
364  */
365 void drm_client_buffer_vunmap(struct drm_client_buffer *buffer)
366 {
367 	struct iosys_map *map = &buffer->map;
368 
369 	drm_gem_vunmap(buffer->gem, map);
370 }
371 EXPORT_SYMBOL(drm_client_buffer_vunmap);
372 
373 static void drm_client_buffer_rmfb(struct drm_client_buffer *buffer)
374 {
375 	int ret;
376 
377 	if (!buffer->fb)
378 		return;
379 
380 	ret = drm_mode_rmfb(buffer->client->dev, buffer->fb->base.id, buffer->client->file);
381 	if (ret)
382 		drm_err(buffer->client->dev,
383 			"Error removing FB:%u (%d)\n", buffer->fb->base.id, ret);
384 
385 	buffer->fb = NULL;
386 }
387 
388 static int drm_client_buffer_addfb(struct drm_client_buffer *buffer,
389 				   u32 width, u32 height, u32 format)
390 {
391 	struct drm_client_dev *client = buffer->client;
392 	struct drm_mode_fb_cmd fb_req = { };
393 	const struct drm_format_info *info;
394 	int ret;
395 
396 	info = drm_format_info(format);
397 	fb_req.bpp = drm_format_info_bpp(info, 0);
398 	fb_req.depth = info->depth;
399 	fb_req.width = width;
400 	fb_req.height = height;
401 	fb_req.handle = buffer->handle;
402 	fb_req.pitch = buffer->pitch;
403 
404 	ret = drm_mode_addfb(client->dev, &fb_req, client->file);
405 	if (ret)
406 		return ret;
407 
408 	buffer->fb = drm_framebuffer_lookup(client->dev, buffer->client->file, fb_req.fb_id);
409 	if (WARN_ON(!buffer->fb))
410 		return -ENOENT;
411 
412 	/* drop the reference we picked up in framebuffer lookup */
413 	drm_framebuffer_put(buffer->fb);
414 
415 	strscpy(buffer->fb->comm, client->name, TASK_COMM_LEN);
416 
417 	return 0;
418 }
419 
420 /**
421  * drm_client_framebuffer_create - Create a client framebuffer
422  * @client: DRM client
423  * @width: Framebuffer width
424  * @height: Framebuffer height
425  * @format: Buffer format
426  *
427  * This function creates a &drm_client_buffer which consists of a
428  * &drm_framebuffer backed by a dumb buffer.
429  * Call drm_client_framebuffer_delete() to free the buffer.
430  *
431  * Returns:
432  * Pointer to a client buffer or an error pointer on failure.
433  */
434 struct drm_client_buffer *
435 drm_client_framebuffer_create(struct drm_client_dev *client, u32 width, u32 height, u32 format)
436 {
437 	struct drm_client_buffer *buffer;
438 	int ret;
439 
440 	buffer = drm_client_buffer_create(client, width, height, format);
441 	if (IS_ERR(buffer))
442 		return buffer;
443 
444 	ret = drm_client_buffer_addfb(buffer, width, height, format);
445 	if (ret) {
446 		drm_client_buffer_delete(buffer);
447 		return ERR_PTR(ret);
448 	}
449 
450 	return buffer;
451 }
452 EXPORT_SYMBOL(drm_client_framebuffer_create);
453 
454 /**
455  * drm_client_framebuffer_delete - Delete a client framebuffer
456  * @buffer: DRM client buffer (can be NULL)
457  */
458 void drm_client_framebuffer_delete(struct drm_client_buffer *buffer)
459 {
460 	if (!buffer)
461 		return;
462 
463 	drm_client_buffer_rmfb(buffer);
464 	drm_client_buffer_delete(buffer);
465 }
466 EXPORT_SYMBOL(drm_client_framebuffer_delete);
467 
468 /**
469  * drm_client_framebuffer_flush - Manually flush client framebuffer
470  * @buffer: DRM client buffer (can be NULL)
471  * @rect: Damage rectangle (if NULL flushes all)
472  *
473  * This calls &drm_framebuffer_funcs->dirty (if present) to flush buffer changes
474  * for drivers that need it.
475  *
476  * Returns:
477  * Zero on success or negative error code on failure.
478  */
479 int drm_client_framebuffer_flush(struct drm_client_buffer *buffer, struct drm_rect *rect)
480 {
481 	if (!buffer || !buffer->fb || !buffer->fb->funcs->dirty)
482 		return 0;
483 
484 	if (rect) {
485 		struct drm_clip_rect clip = {
486 			.x1 = rect->x1,
487 			.y1 = rect->y1,
488 			.x2 = rect->x2,
489 			.y2 = rect->y2,
490 		};
491 
492 		return buffer->fb->funcs->dirty(buffer->fb, buffer->client->file,
493 						0, 0, &clip, 1);
494 	}
495 
496 	return buffer->fb->funcs->dirty(buffer->fb, buffer->client->file,
497 					0, 0, NULL, 0);
498 }
499 EXPORT_SYMBOL(drm_client_framebuffer_flush);
500 
501 #ifdef CONFIG_DEBUG_FS
502 static int drm_client_debugfs_internal_clients(struct seq_file *m, void *data)
503 {
504 	struct drm_info_node *node = m->private;
505 	struct drm_device *dev = node->minor->dev;
506 	struct drm_printer p = drm_seq_file_printer(m);
507 	struct drm_client_dev *client;
508 
509 	mutex_lock(&dev->clientlist_mutex);
510 	list_for_each_entry(client, &dev->clientlist, list)
511 		drm_printf(&p, "%s\n", client->name);
512 	mutex_unlock(&dev->clientlist_mutex);
513 
514 	return 0;
515 }
516 
517 static const struct drm_info_list drm_client_debugfs_list[] = {
518 	{ "internal_clients", drm_client_debugfs_internal_clients, 0 },
519 };
520 
521 void drm_client_debugfs_init(struct drm_minor *minor)
522 {
523 	drm_debugfs_create_files(drm_client_debugfs_list,
524 				 ARRAY_SIZE(drm_client_debugfs_list),
525 				 minor->debugfs_root, minor);
526 }
527 #endif
528