Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0 or MIT
0002 /*
0003  * Copyright 2018 Noralf Trønnes
0004  */
0005 
0006 #include <linux/iosys-map.h>
0007 #include <linux/list.h>
0008 #include <linux/module.h>
0009 #include <linux/mutex.h>
0010 #include <linux/seq_file.h>
0011 #include <linux/slab.h>
0012 
0013 #include <drm/drm_client.h>
0014 #include <drm/drm_debugfs.h>
0015 #include <drm/drm_device.h>
0016 #include <drm/drm_drv.h>
0017 #include <drm/drm_file.h>
0018 #include <drm/drm_fourcc.h>
0019 #include <drm/drm_framebuffer.h>
0020 #include <drm/drm_gem.h>
0021 #include <drm/drm_mode.h>
0022 #include <drm/drm_print.h>
0023 
0024 #include "drm_crtc_internal.h"
0025 #include "drm_internal.h"
0026 
0027 /**
0028  * DOC: overview
0029  *
0030  * This library provides support for clients running in the kernel like fbdev and bootsplash.
0031  *
0032  * GEM drivers which provide a GEM based dumb buffer with a virtual address are supported.
0033  */
0034 
0035 static int drm_client_open(struct drm_client_dev *client)
0036 {
0037     struct drm_device *dev = client->dev;
0038     struct drm_file *file;
0039 
0040     file = drm_file_alloc(dev->primary);
0041     if (IS_ERR(file))
0042         return PTR_ERR(file);
0043 
0044     mutex_lock(&dev->filelist_mutex);
0045     list_add(&file->lhead, &dev->filelist_internal);
0046     mutex_unlock(&dev->filelist_mutex);
0047 
0048     client->file = file;
0049 
0050     return 0;
0051 }
0052 
0053 static void drm_client_close(struct drm_client_dev *client)
0054 {
0055     struct drm_device *dev = client->dev;
0056 
0057     mutex_lock(&dev->filelist_mutex);
0058     list_del(&client->file->lhead);
0059     mutex_unlock(&dev->filelist_mutex);
0060 
0061     drm_file_free(client->file);
0062 }
0063 
0064 /**
0065  * drm_client_init - Initialise a DRM client
0066  * @dev: DRM device
0067  * @client: DRM client
0068  * @name: Client name
0069  * @funcs: DRM client functions (optional)
0070  *
0071  * This initialises the client and opens a &drm_file.
0072  * Use drm_client_register() to complete the process.
0073  * The caller needs to hold a reference on @dev before calling this function.
0074  * The client is freed when the &drm_device is unregistered. See drm_client_release().
0075  *
0076  * Returns:
0077  * Zero on success or negative error code on failure.
0078  */
0079 int drm_client_init(struct drm_device *dev, struct drm_client_dev *client,
0080             const char *name, const struct drm_client_funcs *funcs)
0081 {
0082     int ret;
0083 
0084     if (!drm_core_check_feature(dev, DRIVER_MODESET) || !dev->driver->dumb_create)
0085         return -EOPNOTSUPP;
0086 
0087     if (funcs && !try_module_get(funcs->owner))
0088         return -ENODEV;
0089 
0090     client->dev = dev;
0091     client->name = name;
0092     client->funcs = funcs;
0093 
0094     ret = drm_client_modeset_create(client);
0095     if (ret)
0096         goto err_put_module;
0097 
0098     ret = drm_client_open(client);
0099     if (ret)
0100         goto err_free;
0101 
0102     drm_dev_get(dev);
0103 
0104     return 0;
0105 
0106 err_free:
0107     drm_client_modeset_free(client);
0108 err_put_module:
0109     if (funcs)
0110         module_put(funcs->owner);
0111 
0112     return ret;
0113 }
0114 EXPORT_SYMBOL(drm_client_init);
0115 
0116 /**
0117  * drm_client_register - Register client
0118  * @client: DRM client
0119  *
0120  * Add the client to the &drm_device client list to activate its callbacks.
0121  * @client must be initialized by a call to drm_client_init(). After
0122  * drm_client_register() it is no longer permissible to call drm_client_release()
0123  * directly (outside the unregister callback), instead cleanup will happen
0124  * automatically on driver unload.
0125  */
0126 void drm_client_register(struct drm_client_dev *client)
0127 {
0128     struct drm_device *dev = client->dev;
0129 
0130     mutex_lock(&dev->clientlist_mutex);
0131     list_add(&client->list, &dev->clientlist);
0132     mutex_unlock(&dev->clientlist_mutex);
0133 }
0134 EXPORT_SYMBOL(drm_client_register);
0135 
0136 /**
0137  * drm_client_release - Release DRM client resources
0138  * @client: DRM client
0139  *
0140  * Releases resources by closing the &drm_file that was opened by drm_client_init().
0141  * It is called automatically if the &drm_client_funcs.unregister callback is _not_ set.
0142  *
0143  * This function should only be called from the unregister callback. An exception
0144  * is fbdev which cannot free the buffer if userspace has open file descriptors.
0145  *
0146  * Note:
0147  * Clients cannot initiate a release by themselves. This is done to keep the code simple.
0148  * The driver has to be unloaded before the client can be unloaded.
0149  */
0150 void drm_client_release(struct drm_client_dev *client)
0151 {
0152     struct drm_device *dev = client->dev;
0153 
0154     drm_dbg_kms(dev, "%s\n", client->name);
0155 
0156     drm_client_modeset_free(client);
0157     drm_client_close(client);
0158     drm_dev_put(dev);
0159     if (client->funcs)
0160         module_put(client->funcs->owner);
0161 }
0162 EXPORT_SYMBOL(drm_client_release);
0163 
0164 void drm_client_dev_unregister(struct drm_device *dev)
0165 {
0166     struct drm_client_dev *client, *tmp;
0167 
0168     if (!drm_core_check_feature(dev, DRIVER_MODESET))
0169         return;
0170 
0171     mutex_lock(&dev->clientlist_mutex);
0172     list_for_each_entry_safe(client, tmp, &dev->clientlist, list) {
0173         list_del(&client->list);
0174         if (client->funcs && client->funcs->unregister) {
0175             client->funcs->unregister(client);
0176         } else {
0177             drm_client_release(client);
0178             kfree(client);
0179         }
0180     }
0181     mutex_unlock(&dev->clientlist_mutex);
0182 }
0183 
0184 /**
0185  * drm_client_dev_hotplug - Send hotplug event to clients
0186  * @dev: DRM device
0187  *
0188  * This function calls the &drm_client_funcs.hotplug callback on the attached clients.
0189  *
0190  * drm_kms_helper_hotplug_event() calls this function, so drivers that use it
0191  * don't need to call this function themselves.
0192  */
0193 void drm_client_dev_hotplug(struct drm_device *dev)
0194 {
0195     struct drm_client_dev *client;
0196     int ret;
0197 
0198     if (!drm_core_check_feature(dev, DRIVER_MODESET))
0199         return;
0200 
0201     mutex_lock(&dev->clientlist_mutex);
0202     list_for_each_entry(client, &dev->clientlist, list) {
0203         if (!client->funcs || !client->funcs->hotplug)
0204             continue;
0205 
0206         ret = client->funcs->hotplug(client);
0207         drm_dbg_kms(dev, "%s: ret=%d\n", client->name, ret);
0208     }
0209     mutex_unlock(&dev->clientlist_mutex);
0210 }
0211 EXPORT_SYMBOL(drm_client_dev_hotplug);
0212 
0213 void drm_client_dev_restore(struct drm_device *dev)
0214 {
0215     struct drm_client_dev *client;
0216     int ret;
0217 
0218     if (!drm_core_check_feature(dev, DRIVER_MODESET))
0219         return;
0220 
0221     mutex_lock(&dev->clientlist_mutex);
0222     list_for_each_entry(client, &dev->clientlist, list) {
0223         if (!client->funcs || !client->funcs->restore)
0224             continue;
0225 
0226         ret = client->funcs->restore(client);
0227         drm_dbg_kms(dev, "%s: ret=%d\n", client->name, ret);
0228         if (!ret) /* The first one to return zero gets the privilege to restore */
0229             break;
0230     }
0231     mutex_unlock(&dev->clientlist_mutex);
0232 }
0233 
0234 static void drm_client_buffer_delete(struct drm_client_buffer *buffer)
0235 {
0236     struct drm_device *dev = buffer->client->dev;
0237 
0238     drm_gem_vunmap(buffer->gem, &buffer->map);
0239 
0240     if (buffer->gem)
0241         drm_gem_object_put(buffer->gem);
0242 
0243     if (buffer->handle)
0244         drm_mode_destroy_dumb(dev, buffer->handle, buffer->client->file);
0245 
0246     kfree(buffer);
0247 }
0248 
0249 static struct drm_client_buffer *
0250 drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height, u32 format)
0251 {
0252     const struct drm_format_info *info = drm_format_info(format);
0253     struct drm_mode_create_dumb dumb_args = { };
0254     struct drm_device *dev = client->dev;
0255     struct drm_client_buffer *buffer;
0256     struct drm_gem_object *obj;
0257     int ret;
0258 
0259     buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
0260     if (!buffer)
0261         return ERR_PTR(-ENOMEM);
0262 
0263     buffer->client = client;
0264 
0265     dumb_args.width = width;
0266     dumb_args.height = height;
0267     dumb_args.bpp = info->cpp[0] * 8;
0268     ret = drm_mode_create_dumb(dev, &dumb_args, client->file);
0269     if (ret)
0270         goto err_delete;
0271 
0272     buffer->handle = dumb_args.handle;
0273     buffer->pitch = dumb_args.pitch;
0274 
0275     obj = drm_gem_object_lookup(client->file, dumb_args.handle);
0276     if (!obj)  {
0277         ret = -ENOENT;
0278         goto err_delete;
0279     }
0280 
0281     buffer->gem = obj;
0282 
0283     return buffer;
0284 
0285 err_delete:
0286     drm_client_buffer_delete(buffer);
0287 
0288     return ERR_PTR(ret);
0289 }
0290 
0291 /**
0292  * drm_client_buffer_vmap - Map DRM client buffer into address space
0293  * @buffer: DRM client buffer
0294  * @map_copy: Returns the mapped memory's address
0295  *
0296  * This function maps a client buffer into kernel address space. If the
0297  * buffer is already mapped, it returns the existing mapping's address.
0298  *
0299  * Client buffer mappings are not ref'counted. Each call to
0300  * drm_client_buffer_vmap() should be followed by a call to
0301  * drm_client_buffer_vunmap(); or the client buffer should be mapped
0302  * throughout its lifetime.
0303  *
0304  * The returned address is a copy of the internal value. In contrast to
0305  * other vmap interfaces, you don't need it for the client's vunmap
0306  * function. So you can modify it at will during blit and draw operations.
0307  *
0308  * Returns:
0309  *  0 on success, or a negative errno code otherwise.
0310  */
0311 int
0312 drm_client_buffer_vmap(struct drm_client_buffer *buffer,
0313                struct iosys_map *map_copy)
0314 {
0315     struct iosys_map *map = &buffer->map;
0316     int ret;
0317 
0318     /*
0319      * FIXME: The dependency on GEM here isn't required, we could
0320      * convert the driver handle to a dma-buf instead and use the
0321      * backend-agnostic dma-buf vmap support instead. This would
0322      * require that the handle2fd prime ioctl is reworked to pull the
0323      * fd_install step out of the driver backend hooks, to make that
0324      * final step optional for internal users.
0325      */
0326     ret = drm_gem_vmap(buffer->gem, map);
0327     if (ret)
0328         return ret;
0329 
0330     *map_copy = *map;
0331 
0332     return 0;
0333 }
0334 EXPORT_SYMBOL(drm_client_buffer_vmap);
0335 
0336 /**
0337  * drm_client_buffer_vunmap - Unmap DRM client buffer
0338  * @buffer: DRM client buffer
0339  *
0340  * This function removes a client buffer's memory mapping. Calling this
0341  * function is only required by clients that manage their buffer mappings
0342  * by themselves.
0343  */
0344 void drm_client_buffer_vunmap(struct drm_client_buffer *buffer)
0345 {
0346     struct iosys_map *map = &buffer->map;
0347 
0348     drm_gem_vunmap(buffer->gem, map);
0349 }
0350 EXPORT_SYMBOL(drm_client_buffer_vunmap);
0351 
0352 static void drm_client_buffer_rmfb(struct drm_client_buffer *buffer)
0353 {
0354     int ret;
0355 
0356     if (!buffer->fb)
0357         return;
0358 
0359     ret = drm_mode_rmfb(buffer->client->dev, buffer->fb->base.id, buffer->client->file);
0360     if (ret)
0361         drm_err(buffer->client->dev,
0362             "Error removing FB:%u (%d)\n", buffer->fb->base.id, ret);
0363 
0364     buffer->fb = NULL;
0365 }
0366 
0367 static int drm_client_buffer_addfb(struct drm_client_buffer *buffer,
0368                    u32 width, u32 height, u32 format)
0369 {
0370     struct drm_client_dev *client = buffer->client;
0371     struct drm_mode_fb_cmd fb_req = { };
0372     const struct drm_format_info *info;
0373     int ret;
0374 
0375     info = drm_format_info(format);
0376     fb_req.bpp = info->cpp[0] * 8;
0377     fb_req.depth = info->depth;
0378     fb_req.width = width;
0379     fb_req.height = height;
0380     fb_req.handle = buffer->handle;
0381     fb_req.pitch = buffer->pitch;
0382 
0383     ret = drm_mode_addfb(client->dev, &fb_req, client->file);
0384     if (ret)
0385         return ret;
0386 
0387     buffer->fb = drm_framebuffer_lookup(client->dev, buffer->client->file, fb_req.fb_id);
0388     if (WARN_ON(!buffer->fb))
0389         return -ENOENT;
0390 
0391     /* drop the reference we picked up in framebuffer lookup */
0392     drm_framebuffer_put(buffer->fb);
0393 
0394     strscpy(buffer->fb->comm, client->name, TASK_COMM_LEN);
0395 
0396     return 0;
0397 }
0398 
0399 /**
0400  * drm_client_framebuffer_create - Create a client framebuffer
0401  * @client: DRM client
0402  * @width: Framebuffer width
0403  * @height: Framebuffer height
0404  * @format: Buffer format
0405  *
0406  * This function creates a &drm_client_buffer which consists of a
0407  * &drm_framebuffer backed by a dumb buffer.
0408  * Call drm_client_framebuffer_delete() to free the buffer.
0409  *
0410  * Returns:
0411  * Pointer to a client buffer or an error pointer on failure.
0412  */
0413 struct drm_client_buffer *
0414 drm_client_framebuffer_create(struct drm_client_dev *client, u32 width, u32 height, u32 format)
0415 {
0416     struct drm_client_buffer *buffer;
0417     int ret;
0418 
0419     buffer = drm_client_buffer_create(client, width, height, format);
0420     if (IS_ERR(buffer))
0421         return buffer;
0422 
0423     ret = drm_client_buffer_addfb(buffer, width, height, format);
0424     if (ret) {
0425         drm_client_buffer_delete(buffer);
0426         return ERR_PTR(ret);
0427     }
0428 
0429     return buffer;
0430 }
0431 EXPORT_SYMBOL(drm_client_framebuffer_create);
0432 
0433 /**
0434  * drm_client_framebuffer_delete - Delete a client framebuffer
0435  * @buffer: DRM client buffer (can be NULL)
0436  */
0437 void drm_client_framebuffer_delete(struct drm_client_buffer *buffer)
0438 {
0439     if (!buffer)
0440         return;
0441 
0442     drm_client_buffer_rmfb(buffer);
0443     drm_client_buffer_delete(buffer);
0444 }
0445 EXPORT_SYMBOL(drm_client_framebuffer_delete);
0446 
0447 /**
0448  * drm_client_framebuffer_flush - Manually flush client framebuffer
0449  * @buffer: DRM client buffer (can be NULL)
0450  * @rect: Damage rectangle (if NULL flushes all)
0451  *
0452  * This calls &drm_framebuffer_funcs->dirty (if present) to flush buffer changes
0453  * for drivers that need it.
0454  *
0455  * Returns:
0456  * Zero on success or negative error code on failure.
0457  */
0458 int drm_client_framebuffer_flush(struct drm_client_buffer *buffer, struct drm_rect *rect)
0459 {
0460     if (!buffer || !buffer->fb || !buffer->fb->funcs->dirty)
0461         return 0;
0462 
0463     if (rect) {
0464         struct drm_clip_rect clip = {
0465             .x1 = rect->x1,
0466             .y1 = rect->y1,
0467             .x2 = rect->x2,
0468             .y2 = rect->y2,
0469         };
0470 
0471         return buffer->fb->funcs->dirty(buffer->fb, buffer->client->file,
0472                         0, 0, &clip, 1);
0473     }
0474 
0475     return buffer->fb->funcs->dirty(buffer->fb, buffer->client->file,
0476                     0, 0, NULL, 0);
0477 }
0478 EXPORT_SYMBOL(drm_client_framebuffer_flush);
0479 
0480 #ifdef CONFIG_DEBUG_FS
0481 static int drm_client_debugfs_internal_clients(struct seq_file *m, void *data)
0482 {
0483     struct drm_info_node *node = m->private;
0484     struct drm_device *dev = node->minor->dev;
0485     struct drm_printer p = drm_seq_file_printer(m);
0486     struct drm_client_dev *client;
0487 
0488     mutex_lock(&dev->clientlist_mutex);
0489     list_for_each_entry(client, &dev->clientlist, list)
0490         drm_printf(&p, "%s\n", client->name);
0491     mutex_unlock(&dev->clientlist_mutex);
0492 
0493     return 0;
0494 }
0495 
0496 static const struct drm_info_list drm_client_debugfs_list[] = {
0497     { "internal_clients", drm_client_debugfs_internal_clients, 0 },
0498 };
0499 
0500 void drm_client_debugfs_init(struct drm_minor *minor)
0501 {
0502     drm_debugfs_create_files(drm_client_debugfs_list,
0503                  ARRAY_SIZE(drm_client_debugfs_list),
0504                  minor->debugfs_root, minor);
0505 }
0506 #endif