cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

drm_client.c (13254B)


      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
     35static 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
     53static 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 */
     79int 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
    106err_free:
    107	drm_client_modeset_free(client);
    108err_put_module:
    109	if (funcs)
    110		module_put(funcs->owner);
    111
    112	return ret;
    113}
    114EXPORT_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 */
    126void drm_client_register(struct drm_client_dev *client)
    127{
    128	struct drm_device *dev = client->dev;
    129
    130	mutex_lock(&dev->clientlist_mutex);
    131	list_add(&client->list, &dev->clientlist);
    132	mutex_unlock(&dev->clientlist_mutex);
    133}
    134EXPORT_SYMBOL(drm_client_register);
    135
    136/**
    137 * drm_client_release - Release DRM client resources
    138 * @client: DRM client
    139 *
    140 * Releases resources by closing the &drm_file that was opened by drm_client_init().
    141 * It is called automatically if the &drm_client_funcs.unregister callback is _not_ set.
    142 *
    143 * This function should only be called from the unregister callback. An exception
    144 * is fbdev which cannot free the buffer if userspace has open file descriptors.
    145 *
    146 * Note:
    147 * Clients cannot initiate a release by themselves. This is done to keep the code simple.
    148 * The driver has to be unloaded before the client can be unloaded.
    149 */
    150void drm_client_release(struct drm_client_dev *client)
    151{
    152	struct drm_device *dev = client->dev;
    153
    154	drm_dbg_kms(dev, "%s\n", client->name);
    155
    156	drm_client_modeset_free(client);
    157	drm_client_close(client);
    158	drm_dev_put(dev);
    159	if (client->funcs)
    160		module_put(client->funcs->owner);
    161}
    162EXPORT_SYMBOL(drm_client_release);
    163
    164void drm_client_dev_unregister(struct drm_device *dev)
    165{
    166	struct drm_client_dev *client, *tmp;
    167
    168	if (!drm_core_check_feature(dev, DRIVER_MODESET))
    169		return;
    170
    171	mutex_lock(&dev->clientlist_mutex);
    172	list_for_each_entry_safe(client, tmp, &dev->clientlist, list) {
    173		list_del(&client->list);
    174		if (client->funcs && client->funcs->unregister) {
    175			client->funcs->unregister(client);
    176		} else {
    177			drm_client_release(client);
    178			kfree(client);
    179		}
    180	}
    181	mutex_unlock(&dev->clientlist_mutex);
    182}
    183
    184/**
    185 * drm_client_dev_hotplug - Send hotplug event to clients
    186 * @dev: DRM device
    187 *
    188 * This function calls the &drm_client_funcs.hotplug callback on the attached clients.
    189 *
    190 * drm_kms_helper_hotplug_event() calls this function, so drivers that use it
    191 * don't need to call this function themselves.
    192 */
    193void drm_client_dev_hotplug(struct drm_device *dev)
    194{
    195	struct drm_client_dev *client;
    196	int ret;
    197
    198	if (!drm_core_check_feature(dev, DRIVER_MODESET))
    199		return;
    200
    201	mutex_lock(&dev->clientlist_mutex);
    202	list_for_each_entry(client, &dev->clientlist, list) {
    203		if (!client->funcs || !client->funcs->hotplug)
    204			continue;
    205
    206		ret = client->funcs->hotplug(client);
    207		drm_dbg_kms(dev, "%s: ret=%d\n", client->name, ret);
    208	}
    209	mutex_unlock(&dev->clientlist_mutex);
    210}
    211EXPORT_SYMBOL(drm_client_dev_hotplug);
    212
    213void drm_client_dev_restore(struct drm_device *dev)
    214{
    215	struct drm_client_dev *client;
    216	int ret;
    217
    218	if (!drm_core_check_feature(dev, DRIVER_MODESET))
    219		return;
    220
    221	mutex_lock(&dev->clientlist_mutex);
    222	list_for_each_entry(client, &dev->clientlist, list) {
    223		if (!client->funcs || !client->funcs->restore)
    224			continue;
    225
    226		ret = client->funcs->restore(client);
    227		drm_dbg_kms(dev, "%s: ret=%d\n", client->name, ret);
    228		if (!ret) /* The first one to return zero gets the privilege to restore */
    229			break;
    230	}
    231	mutex_unlock(&dev->clientlist_mutex);
    232}
    233
    234static void drm_client_buffer_delete(struct drm_client_buffer *buffer)
    235{
    236	struct drm_device *dev = buffer->client->dev;
    237
    238	drm_gem_vunmap(buffer->gem, &buffer->map);
    239
    240	if (buffer->gem)
    241		drm_gem_object_put(buffer->gem);
    242
    243	if (buffer->handle)
    244		drm_mode_destroy_dumb(dev, buffer->handle, buffer->client->file);
    245
    246	kfree(buffer);
    247}
    248
    249static struct drm_client_buffer *
    250drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height, u32 format)
    251{
    252	const struct drm_format_info *info = drm_format_info(format);
    253	struct drm_mode_create_dumb dumb_args = { };
    254	struct drm_device *dev = client->dev;
    255	struct drm_client_buffer *buffer;
    256	struct drm_gem_object *obj;
    257	int ret;
    258
    259	buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
    260	if (!buffer)
    261		return ERR_PTR(-ENOMEM);
    262
    263	buffer->client = client;
    264
    265	dumb_args.width = width;
    266	dumb_args.height = height;
    267	dumb_args.bpp = info->cpp[0] * 8;
    268	ret = drm_mode_create_dumb(dev, &dumb_args, client->file);
    269	if (ret)
    270		goto err_delete;
    271
    272	buffer->handle = dumb_args.handle;
    273	buffer->pitch = dumb_args.pitch;
    274
    275	obj = drm_gem_object_lookup(client->file, dumb_args.handle);
    276	if (!obj)  {
    277		ret = -ENOENT;
    278		goto err_delete;
    279	}
    280
    281	buffer->gem = obj;
    282
    283	return buffer;
    284
    285err_delete:
    286	drm_client_buffer_delete(buffer);
    287
    288	return ERR_PTR(ret);
    289}
    290
    291/**
    292 * drm_client_buffer_vmap - Map DRM client buffer into address space
    293 * @buffer: DRM client buffer
    294 * @map_copy: Returns the mapped memory's address
    295 *
    296 * This function maps a client buffer into kernel address space. If the
    297 * buffer is already mapped, it returns the existing mapping's address.
    298 *
    299 * Client buffer mappings are not ref'counted. Each call to
    300 * drm_client_buffer_vmap() should be followed by a call to
    301 * drm_client_buffer_vunmap(); or the client buffer should be mapped
    302 * throughout its lifetime.
    303 *
    304 * The returned address is a copy of the internal value. In contrast to
    305 * other vmap interfaces, you don't need it for the client's vunmap
    306 * function. So you can modify it at will during blit and draw operations.
    307 *
    308 * Returns:
    309 *	0 on success, or a negative errno code otherwise.
    310 */
    311int
    312drm_client_buffer_vmap(struct drm_client_buffer *buffer,
    313		       struct iosys_map *map_copy)
    314{
    315	struct iosys_map *map = &buffer->map;
    316	int ret;
    317
    318	/*
    319	 * FIXME: The dependency on GEM here isn't required, we could
    320	 * convert the driver handle to a dma-buf instead and use the
    321	 * backend-agnostic dma-buf vmap support instead. This would
    322	 * require that the handle2fd prime ioctl is reworked to pull the
    323	 * fd_install step out of the driver backend hooks, to make that
    324	 * final step optional for internal users.
    325	 */
    326	ret = drm_gem_vmap(buffer->gem, map);
    327	if (ret)
    328		return ret;
    329
    330	*map_copy = *map;
    331
    332	return 0;
    333}
    334EXPORT_SYMBOL(drm_client_buffer_vmap);
    335
    336/**
    337 * drm_client_buffer_vunmap - Unmap DRM client buffer
    338 * @buffer: DRM client buffer
    339 *
    340 * This function removes a client buffer's memory mapping. Calling this
    341 * function is only required by clients that manage their buffer mappings
    342 * by themselves.
    343 */
    344void drm_client_buffer_vunmap(struct drm_client_buffer *buffer)
    345{
    346	struct iosys_map *map = &buffer->map;
    347
    348	drm_gem_vunmap(buffer->gem, map);
    349}
    350EXPORT_SYMBOL(drm_client_buffer_vunmap);
    351
    352static void drm_client_buffer_rmfb(struct drm_client_buffer *buffer)
    353{
    354	int ret;
    355
    356	if (!buffer->fb)
    357		return;
    358
    359	ret = drm_mode_rmfb(buffer->client->dev, buffer->fb->base.id, buffer->client->file);
    360	if (ret)
    361		drm_err(buffer->client->dev,
    362			"Error removing FB:%u (%d)\n", buffer->fb->base.id, ret);
    363
    364	buffer->fb = NULL;
    365}
    366
    367static int drm_client_buffer_addfb(struct drm_client_buffer *buffer,
    368				   u32 width, u32 height, u32 format)
    369{
    370	struct drm_client_dev *client = buffer->client;
    371	struct drm_mode_fb_cmd fb_req = { };
    372	const struct drm_format_info *info;
    373	int ret;
    374
    375	info = drm_format_info(format);
    376	fb_req.bpp = info->cpp[0] * 8;
    377	fb_req.depth = info->depth;
    378	fb_req.width = width;
    379	fb_req.height = height;
    380	fb_req.handle = buffer->handle;
    381	fb_req.pitch = buffer->pitch;
    382
    383	ret = drm_mode_addfb(client->dev, &fb_req, client->file);
    384	if (ret)
    385		return ret;
    386
    387	buffer->fb = drm_framebuffer_lookup(client->dev, buffer->client->file, fb_req.fb_id);
    388	if (WARN_ON(!buffer->fb))
    389		return -ENOENT;
    390
    391	/* drop the reference we picked up in framebuffer lookup */
    392	drm_framebuffer_put(buffer->fb);
    393
    394	strscpy(buffer->fb->comm, client->name, TASK_COMM_LEN);
    395
    396	return 0;
    397}
    398
    399/**
    400 * drm_client_framebuffer_create - Create a client framebuffer
    401 * @client: DRM client
    402 * @width: Framebuffer width
    403 * @height: Framebuffer height
    404 * @format: Buffer format
    405 *
    406 * This function creates a &drm_client_buffer which consists of a
    407 * &drm_framebuffer backed by a dumb buffer.
    408 * Call drm_client_framebuffer_delete() to free the buffer.
    409 *
    410 * Returns:
    411 * Pointer to a client buffer or an error pointer on failure.
    412 */
    413struct drm_client_buffer *
    414drm_client_framebuffer_create(struct drm_client_dev *client, u32 width, u32 height, u32 format)
    415{
    416	struct drm_client_buffer *buffer;
    417	int ret;
    418
    419	buffer = drm_client_buffer_create(client, width, height, format);
    420	if (IS_ERR(buffer))
    421		return buffer;
    422
    423	ret = drm_client_buffer_addfb(buffer, width, height, format);
    424	if (ret) {
    425		drm_client_buffer_delete(buffer);
    426		return ERR_PTR(ret);
    427	}
    428
    429	return buffer;
    430}
    431EXPORT_SYMBOL(drm_client_framebuffer_create);
    432
    433/**
    434 * drm_client_framebuffer_delete - Delete a client framebuffer
    435 * @buffer: DRM client buffer (can be NULL)
    436 */
    437void drm_client_framebuffer_delete(struct drm_client_buffer *buffer)
    438{
    439	if (!buffer)
    440		return;
    441
    442	drm_client_buffer_rmfb(buffer);
    443	drm_client_buffer_delete(buffer);
    444}
    445EXPORT_SYMBOL(drm_client_framebuffer_delete);
    446
    447/**
    448 * drm_client_framebuffer_flush - Manually flush client framebuffer
    449 * @buffer: DRM client buffer (can be NULL)
    450 * @rect: Damage rectangle (if NULL flushes all)
    451 *
    452 * This calls &drm_framebuffer_funcs->dirty (if present) to flush buffer changes
    453 * for drivers that need it.
    454 *
    455 * Returns:
    456 * Zero on success or negative error code on failure.
    457 */
    458int drm_client_framebuffer_flush(struct drm_client_buffer *buffer, struct drm_rect *rect)
    459{
    460	if (!buffer || !buffer->fb || !buffer->fb->funcs->dirty)
    461		return 0;
    462
    463	if (rect) {
    464		struct drm_clip_rect clip = {
    465			.x1 = rect->x1,
    466			.y1 = rect->y1,
    467			.x2 = rect->x2,
    468			.y2 = rect->y2,
    469		};
    470
    471		return buffer->fb->funcs->dirty(buffer->fb, buffer->client->file,
    472						0, 0, &clip, 1);
    473	}
    474
    475	return buffer->fb->funcs->dirty(buffer->fb, buffer->client->file,
    476					0, 0, NULL, 0);
    477}
    478EXPORT_SYMBOL(drm_client_framebuffer_flush);
    479
    480#ifdef CONFIG_DEBUG_FS
    481static int drm_client_debugfs_internal_clients(struct seq_file *m, void *data)
    482{
    483	struct drm_info_node *node = m->private;
    484	struct drm_device *dev = node->minor->dev;
    485	struct drm_printer p = drm_seq_file_printer(m);
    486	struct drm_client_dev *client;
    487
    488	mutex_lock(&dev->clientlist_mutex);
    489	list_for_each_entry(client, &dev->clientlist, list)
    490		drm_printf(&p, "%s\n", client->name);
    491	mutex_unlock(&dev->clientlist_mutex);
    492
    493	return 0;
    494}
    495
    496static const struct drm_info_list drm_client_debugfs_list[] = {
    497	{ "internal_clients", drm_client_debugfs_internal_clients, 0 },
    498};
    499
    500void drm_client_debugfs_init(struct drm_minor *minor)
    501{
    502	drm_debugfs_create_files(drm_client_debugfs_list,
    503				 ARRAY_SIZE(drm_client_debugfs_list),
    504				 minor->debugfs_root, minor);
    505}
    506#endif