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_writeback.c (15593B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * (C) COPYRIGHT 2016 ARM Limited. All rights reserved.
      4 * Author: Brian Starkey <brian.starkey@arm.com>
      5 *
      6 * This program is free software and is provided to you under the terms of the
      7 * GNU General Public License version 2 as published by the Free Software
      8 * Foundation, and any use by you of this program is subject to the terms
      9 * of such GNU licence.
     10 */
     11
     12#include <linux/dma-fence.h>
     13
     14#include <drm/drm_crtc.h>
     15#include <drm/drm_device.h>
     16#include <drm/drm_drv.h>
     17#include <drm/drm_modeset_helper_vtables.h>
     18#include <drm/drm_property.h>
     19#include <drm/drm_writeback.h>
     20
     21/**
     22 * DOC: overview
     23 *
     24 * Writeback connectors are used to expose hardware which can write the output
     25 * from a CRTC to a memory buffer. They are used and act similarly to other
     26 * types of connectors, with some important differences:
     27 *
     28 * * Writeback connectors don't provide a way to output visually to the user.
     29 *
     30 * * Writeback connectors are visible to userspace only when the client sets
     31 *   DRM_CLIENT_CAP_WRITEBACK_CONNECTORS.
     32 *
     33 * * Writeback connectors don't have EDID.
     34 *
     35 * A framebuffer may only be attached to a writeback connector when the
     36 * connector is attached to a CRTC. The WRITEBACK_FB_ID property which sets the
     37 * framebuffer applies only to a single commit (see below). A framebuffer may
     38 * not be attached while the CRTC is off.
     39 *
     40 * Unlike with planes, when a writeback framebuffer is removed by userspace DRM
     41 * makes no attempt to remove it from active use by the connector. This is
     42 * because no method is provided to abort a writeback operation, and in any
     43 * case making a new commit whilst a writeback is ongoing is undefined (see
     44 * WRITEBACK_OUT_FENCE_PTR below). As soon as the current writeback is finished,
     45 * the framebuffer will automatically no longer be in active use. As it will
     46 * also have already been removed from the framebuffer list, there will be no
     47 * way for any userspace application to retrieve a reference to it in the
     48 * intervening period.
     49 *
     50 * Writeback connectors have some additional properties, which userspace
     51 * can use to query and control them:
     52 *
     53 *  "WRITEBACK_FB_ID":
     54 *	Write-only object property storing a DRM_MODE_OBJECT_FB: it stores the
     55 *	framebuffer to be written by the writeback connector. This property is
     56 *	similar to the FB_ID property on planes, but will always read as zero
     57 *	and is not preserved across commits.
     58 *	Userspace must set this property to an output buffer every time it
     59 *	wishes the buffer to get filled.
     60 *
     61 *  "WRITEBACK_PIXEL_FORMATS":
     62 *	Immutable blob property to store the supported pixel formats table. The
     63 *	data is an array of u32 DRM_FORMAT_* fourcc values.
     64 *	Userspace can use this blob to find out what pixel formats are supported
     65 *	by the connector's writeback engine.
     66 *
     67 *  "WRITEBACK_OUT_FENCE_PTR":
     68 *	Userspace can use this property to provide a pointer for the kernel to
     69 *	fill with a sync_file file descriptor, which will signal once the
     70 *	writeback is finished. The value should be the address of a 32-bit
     71 *	signed integer, cast to a u64.
     72 *	Userspace should wait for this fence to signal before making another
     73 *	commit affecting any of the same CRTCs, Planes or Connectors.
     74 *	**Failure to do so will result in undefined behaviour.**
     75 *	For this reason it is strongly recommended that all userspace
     76 *	applications making use of writeback connectors *always* retrieve an
     77 *	out-fence for the commit and use it appropriately.
     78 *	From userspace, this property will always read as zero.
     79 */
     80
     81#define fence_to_wb_connector(x) container_of(x->lock, \
     82					      struct drm_writeback_connector, \
     83					      fence_lock)
     84
     85static const char *drm_writeback_fence_get_driver_name(struct dma_fence *fence)
     86{
     87	struct drm_writeback_connector *wb_connector =
     88		fence_to_wb_connector(fence);
     89
     90	return wb_connector->base.dev->driver->name;
     91}
     92
     93static const char *
     94drm_writeback_fence_get_timeline_name(struct dma_fence *fence)
     95{
     96	struct drm_writeback_connector *wb_connector =
     97		fence_to_wb_connector(fence);
     98
     99	return wb_connector->timeline_name;
    100}
    101
    102static bool drm_writeback_fence_enable_signaling(struct dma_fence *fence)
    103{
    104	return true;
    105}
    106
    107static const struct dma_fence_ops drm_writeback_fence_ops = {
    108	.get_driver_name = drm_writeback_fence_get_driver_name,
    109	.get_timeline_name = drm_writeback_fence_get_timeline_name,
    110	.enable_signaling = drm_writeback_fence_enable_signaling,
    111};
    112
    113static int create_writeback_properties(struct drm_device *dev)
    114{
    115	struct drm_property *prop;
    116
    117	if (!dev->mode_config.writeback_fb_id_property) {
    118		prop = drm_property_create_object(dev, DRM_MODE_PROP_ATOMIC,
    119						  "WRITEBACK_FB_ID",
    120						  DRM_MODE_OBJECT_FB);
    121		if (!prop)
    122			return -ENOMEM;
    123		dev->mode_config.writeback_fb_id_property = prop;
    124	}
    125
    126	if (!dev->mode_config.writeback_pixel_formats_property) {
    127		prop = drm_property_create(dev, DRM_MODE_PROP_BLOB |
    128					   DRM_MODE_PROP_ATOMIC |
    129					   DRM_MODE_PROP_IMMUTABLE,
    130					   "WRITEBACK_PIXEL_FORMATS", 0);
    131		if (!prop)
    132			return -ENOMEM;
    133		dev->mode_config.writeback_pixel_formats_property = prop;
    134	}
    135
    136	if (!dev->mode_config.writeback_out_fence_ptr_property) {
    137		prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
    138						 "WRITEBACK_OUT_FENCE_PTR", 0,
    139						 U64_MAX);
    140		if (!prop)
    141			return -ENOMEM;
    142		dev->mode_config.writeback_out_fence_ptr_property = prop;
    143	}
    144
    145	return 0;
    146}
    147
    148static const struct drm_encoder_funcs drm_writeback_encoder_funcs = {
    149	.destroy = drm_encoder_cleanup,
    150};
    151
    152/**
    153 * drm_writeback_connector_init - Initialize a writeback connector and its properties
    154 * @dev: DRM device
    155 * @wb_connector: Writeback connector to initialize
    156 * @con_funcs: Connector funcs vtable
    157 * @enc_helper_funcs: Encoder helper funcs vtable to be used by the internal encoder
    158 * @formats: Array of supported pixel formats for the writeback engine
    159 * @n_formats: Length of the formats array
    160 * @possible_crtcs: possible crtcs for the internal writeback encoder
    161 *
    162 * This function creates the writeback-connector-specific properties if they
    163 * have not been already created, initializes the connector as
    164 * type DRM_MODE_CONNECTOR_WRITEBACK, and correctly initializes the property
    165 * values. It will also create an internal encoder associated with the
    166 * drm_writeback_connector and set it to use the @enc_helper_funcs vtable for
    167 * the encoder helper.
    168 *
    169 * Drivers should always use this function instead of drm_connector_init() to
    170 * set up writeback connectors.
    171 *
    172 * Returns: 0 on success, or a negative error code
    173 */
    174int drm_writeback_connector_init(struct drm_device *dev,
    175				 struct drm_writeback_connector *wb_connector,
    176				 const struct drm_connector_funcs *con_funcs,
    177				 const struct drm_encoder_helper_funcs *enc_helper_funcs,
    178				 const u32 *formats, int n_formats,
    179				 u32 possible_crtcs)
    180{
    181	int ret = 0;
    182
    183	drm_encoder_helper_add(&wb_connector->encoder, enc_helper_funcs);
    184
    185	wb_connector->encoder.possible_crtcs = possible_crtcs;
    186
    187	ret = drm_encoder_init(dev, &wb_connector->encoder,
    188			       &drm_writeback_encoder_funcs,
    189			       DRM_MODE_ENCODER_VIRTUAL, NULL);
    190	if (ret)
    191		return ret;
    192
    193	ret = drm_writeback_connector_init_with_encoder(dev, wb_connector, &wb_connector->encoder,
    194			con_funcs, formats, n_formats);
    195
    196	if (ret)
    197		drm_encoder_cleanup(&wb_connector->encoder);
    198
    199	return ret;
    200}
    201EXPORT_SYMBOL(drm_writeback_connector_init);
    202
    203/**
    204 * drm_writeback_connector_init_with_encoder - Initialize a writeback connector with
    205 * a custom encoder
    206 *
    207 * @dev: DRM device
    208 * @wb_connector: Writeback connector to initialize
    209 * @enc: handle to the already initialized drm encoder
    210 * @con_funcs: Connector funcs vtable
    211 * @formats: Array of supported pixel formats for the writeback engine
    212 * @n_formats: Length of the formats array
    213 *
    214 * This function creates the writeback-connector-specific properties if they
    215 * have not been already created, initializes the connector as
    216 * type DRM_MODE_CONNECTOR_WRITEBACK, and correctly initializes the property
    217 * values.
    218 *
    219 * This function assumes that the drm_writeback_connector's encoder has already been
    220 * created and initialized before invoking this function.
    221 *
    222 * In addition, this function also assumes that callers of this API will manage
    223 * assigning the encoder helper functions, possible_crtcs and any other encoder
    224 * specific operation.
    225 *
    226 * Drivers should always use this function instead of drm_connector_init() to
    227 * set up writeback connectors if they want to manage themselves the lifetime of the
    228 * associated encoder.
    229 *
    230 * Returns: 0 on success, or a negative error code
    231 */
    232int drm_writeback_connector_init_with_encoder(struct drm_device *dev,
    233		struct drm_writeback_connector *wb_connector, struct drm_encoder *enc,
    234		const struct drm_connector_funcs *con_funcs, const u32 *formats,
    235		int n_formats)
    236{
    237	struct drm_property_blob *blob;
    238	struct drm_connector *connector = &wb_connector->base;
    239	struct drm_mode_config *config = &dev->mode_config;
    240	int ret = create_writeback_properties(dev);
    241
    242	if (ret != 0)
    243		return ret;
    244
    245	blob = drm_property_create_blob(dev, n_formats * sizeof(*formats),
    246					formats);
    247	if (IS_ERR(blob))
    248		return PTR_ERR(blob);
    249
    250
    251	connector->interlace_allowed = 0;
    252
    253	ret = drm_connector_init(dev, connector, con_funcs,
    254				 DRM_MODE_CONNECTOR_WRITEBACK);
    255	if (ret)
    256		goto connector_fail;
    257
    258	ret = drm_connector_attach_encoder(connector, enc);
    259	if (ret)
    260		goto attach_fail;
    261
    262	INIT_LIST_HEAD(&wb_connector->job_queue);
    263	spin_lock_init(&wb_connector->job_lock);
    264
    265	wb_connector->fence_context = dma_fence_context_alloc(1);
    266	spin_lock_init(&wb_connector->fence_lock);
    267	snprintf(wb_connector->timeline_name,
    268		 sizeof(wb_connector->timeline_name),
    269		 "CONNECTOR:%d-%s", connector->base.id, connector->name);
    270
    271	drm_object_attach_property(&connector->base,
    272				   config->writeback_out_fence_ptr_property, 0);
    273
    274	drm_object_attach_property(&connector->base,
    275				   config->writeback_fb_id_property, 0);
    276
    277	drm_object_attach_property(&connector->base,
    278				   config->writeback_pixel_formats_property,
    279				   blob->base.id);
    280	wb_connector->pixel_formats_blob_ptr = blob;
    281
    282	return 0;
    283
    284attach_fail:
    285	drm_connector_cleanup(connector);
    286connector_fail:
    287	drm_property_blob_put(blob);
    288	return ret;
    289}
    290EXPORT_SYMBOL(drm_writeback_connector_init_with_encoder);
    291
    292int drm_writeback_set_fb(struct drm_connector_state *conn_state,
    293			 struct drm_framebuffer *fb)
    294{
    295	WARN_ON(conn_state->connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK);
    296
    297	if (!conn_state->writeback_job) {
    298		conn_state->writeback_job =
    299			kzalloc(sizeof(*conn_state->writeback_job), GFP_KERNEL);
    300		if (!conn_state->writeback_job)
    301			return -ENOMEM;
    302
    303		conn_state->writeback_job->connector =
    304			drm_connector_to_writeback(conn_state->connector);
    305	}
    306
    307	drm_framebuffer_assign(&conn_state->writeback_job->fb, fb);
    308	return 0;
    309}
    310
    311int drm_writeback_prepare_job(struct drm_writeback_job *job)
    312{
    313	struct drm_writeback_connector *connector = job->connector;
    314	const struct drm_connector_helper_funcs *funcs =
    315		connector->base.helper_private;
    316	int ret;
    317
    318	if (funcs->prepare_writeback_job) {
    319		ret = funcs->prepare_writeback_job(connector, job);
    320		if (ret < 0)
    321			return ret;
    322	}
    323
    324	job->prepared = true;
    325	return 0;
    326}
    327EXPORT_SYMBOL(drm_writeback_prepare_job);
    328
    329/**
    330 * drm_writeback_queue_job - Queue a writeback job for later signalling
    331 * @wb_connector: The writeback connector to queue a job on
    332 * @conn_state: The connector state containing the job to queue
    333 *
    334 * This function adds the job contained in @conn_state to the job_queue for a
    335 * writeback connector. It takes ownership of the writeback job and sets the
    336 * @conn_state->writeback_job to NULL, and so no access to the job may be
    337 * performed by the caller after this function returns.
    338 *
    339 * Drivers must ensure that for a given writeback connector, jobs are queued in
    340 * exactly the same order as they will be completed by the hardware (and
    341 * signaled via drm_writeback_signal_completion).
    342 *
    343 * For every call to drm_writeback_queue_job() there must be exactly one call to
    344 * drm_writeback_signal_completion()
    345 *
    346 * See also: drm_writeback_signal_completion()
    347 */
    348void drm_writeback_queue_job(struct drm_writeback_connector *wb_connector,
    349			     struct drm_connector_state *conn_state)
    350{
    351	struct drm_writeback_job *job;
    352	unsigned long flags;
    353
    354	job = conn_state->writeback_job;
    355	conn_state->writeback_job = NULL;
    356
    357	spin_lock_irqsave(&wb_connector->job_lock, flags);
    358	list_add_tail(&job->list_entry, &wb_connector->job_queue);
    359	spin_unlock_irqrestore(&wb_connector->job_lock, flags);
    360}
    361EXPORT_SYMBOL(drm_writeback_queue_job);
    362
    363void drm_writeback_cleanup_job(struct drm_writeback_job *job)
    364{
    365	struct drm_writeback_connector *connector = job->connector;
    366	const struct drm_connector_helper_funcs *funcs =
    367		connector->base.helper_private;
    368
    369	if (job->prepared && funcs->cleanup_writeback_job)
    370		funcs->cleanup_writeback_job(connector, job);
    371
    372	if (job->fb)
    373		drm_framebuffer_put(job->fb);
    374
    375	if (job->out_fence)
    376		dma_fence_put(job->out_fence);
    377
    378	kfree(job);
    379}
    380EXPORT_SYMBOL(drm_writeback_cleanup_job);
    381
    382/*
    383 * @cleanup_work: deferred cleanup of a writeback job
    384 *
    385 * The job cannot be cleaned up directly in drm_writeback_signal_completion,
    386 * because it may be called in interrupt context. Dropping the framebuffer
    387 * reference can sleep, and so the cleanup is deferred to a workqueue.
    388 */
    389static void cleanup_work(struct work_struct *work)
    390{
    391	struct drm_writeback_job *job = container_of(work,
    392						     struct drm_writeback_job,
    393						     cleanup_work);
    394
    395	drm_writeback_cleanup_job(job);
    396}
    397
    398/**
    399 * drm_writeback_signal_completion - Signal the completion of a writeback job
    400 * @wb_connector: The writeback connector whose job is complete
    401 * @status: Status code to set in the writeback out_fence (0 for success)
    402 *
    403 * Drivers should call this to signal the completion of a previously queued
    404 * writeback job. It should be called as soon as possible after the hardware
    405 * has finished writing, and may be called from interrupt context.
    406 * It is the driver's responsibility to ensure that for a given connector, the
    407 * hardware completes writeback jobs in the same order as they are queued.
    408 *
    409 * Unless the driver is holding its own reference to the framebuffer, it must
    410 * not be accessed after calling this function.
    411 *
    412 * See also: drm_writeback_queue_job()
    413 */
    414void
    415drm_writeback_signal_completion(struct drm_writeback_connector *wb_connector,
    416				int status)
    417{
    418	unsigned long flags;
    419	struct drm_writeback_job *job;
    420	struct dma_fence *out_fence;
    421
    422	spin_lock_irqsave(&wb_connector->job_lock, flags);
    423	job = list_first_entry_or_null(&wb_connector->job_queue,
    424				       struct drm_writeback_job,
    425				       list_entry);
    426	if (job)
    427		list_del(&job->list_entry);
    428
    429	spin_unlock_irqrestore(&wb_connector->job_lock, flags);
    430
    431	if (WARN_ON(!job))
    432		return;
    433
    434	out_fence = job->out_fence;
    435	if (out_fence) {
    436		if (status)
    437			dma_fence_set_error(out_fence, status);
    438		dma_fence_signal(out_fence);
    439		dma_fence_put(out_fence);
    440		job->out_fence = NULL;
    441	}
    442
    443	INIT_WORK(&job->cleanup_work, cleanup_work);
    444	queue_work(system_long_wq, &job->cleanup_work);
    445}
    446EXPORT_SYMBOL(drm_writeback_signal_completion);
    447
    448struct dma_fence *
    449drm_writeback_get_out_fence(struct drm_writeback_connector *wb_connector)
    450{
    451	struct dma_fence *fence;
    452
    453	if (WARN_ON(wb_connector->base.connector_type !=
    454		    DRM_MODE_CONNECTOR_WRITEBACK))
    455		return NULL;
    456
    457	fence = kzalloc(sizeof(*fence), GFP_KERNEL);
    458	if (!fence)
    459		return NULL;
    460
    461	dma_fence_init(fence, &drm_writeback_fence_ops,
    462		       &wb_connector->fence_lock, wb_connector->fence_context,
    463		       ++wb_connector->fence_seqno);
    464
    465	return fence;
    466}
    467EXPORT_SYMBOL(drm_writeback_get_out_fence);