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