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

mc-request.c (12787B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Media device request objects
      4 *
      5 * Copyright 2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
      6 * Copyright (C) 2018 Intel Corporation
      7 * Copyright (C) 2018 Google, Inc.
      8 *
      9 * Author: Hans Verkuil <hans.verkuil@cisco.com>
     10 * Author: Sakari Ailus <sakari.ailus@linux.intel.com>
     11 */
     12
     13#include <linux/anon_inodes.h>
     14#include <linux/file.h>
     15#include <linux/refcount.h>
     16
     17#include <media/media-device.h>
     18#include <media/media-request.h>
     19
     20static const char * const request_state[] = {
     21	[MEDIA_REQUEST_STATE_IDLE]	 = "idle",
     22	[MEDIA_REQUEST_STATE_VALIDATING] = "validating",
     23	[MEDIA_REQUEST_STATE_QUEUED]	 = "queued",
     24	[MEDIA_REQUEST_STATE_COMPLETE]	 = "complete",
     25	[MEDIA_REQUEST_STATE_CLEANING]	 = "cleaning",
     26	[MEDIA_REQUEST_STATE_UPDATING]	 = "updating",
     27};
     28
     29static const char *
     30media_request_state_str(enum media_request_state state)
     31{
     32	BUILD_BUG_ON(ARRAY_SIZE(request_state) != NR_OF_MEDIA_REQUEST_STATE);
     33
     34	if (WARN_ON(state >= ARRAY_SIZE(request_state)))
     35		return "invalid";
     36	return request_state[state];
     37}
     38
     39static void media_request_clean(struct media_request *req)
     40{
     41	struct media_request_object *obj, *obj_safe;
     42
     43	/* Just a sanity check. No other code path is allowed to change this. */
     44	WARN_ON(req->state != MEDIA_REQUEST_STATE_CLEANING);
     45	WARN_ON(req->updating_count);
     46	WARN_ON(req->access_count);
     47
     48	list_for_each_entry_safe(obj, obj_safe, &req->objects, list) {
     49		media_request_object_unbind(obj);
     50		media_request_object_put(obj);
     51	}
     52
     53	req->updating_count = 0;
     54	req->access_count = 0;
     55	WARN_ON(req->num_incomplete_objects);
     56	req->num_incomplete_objects = 0;
     57	wake_up_interruptible_all(&req->poll_wait);
     58}
     59
     60static void media_request_release(struct kref *kref)
     61{
     62	struct media_request *req =
     63		container_of(kref, struct media_request, kref);
     64	struct media_device *mdev = req->mdev;
     65
     66	dev_dbg(mdev->dev, "request: release %s\n", req->debug_str);
     67
     68	/* No other users, no need for a spinlock */
     69	req->state = MEDIA_REQUEST_STATE_CLEANING;
     70
     71	media_request_clean(req);
     72
     73	if (mdev->ops->req_free)
     74		mdev->ops->req_free(req);
     75	else
     76		kfree(req);
     77}
     78
     79void media_request_put(struct media_request *req)
     80{
     81	kref_put(&req->kref, media_request_release);
     82}
     83EXPORT_SYMBOL_GPL(media_request_put);
     84
     85static int media_request_close(struct inode *inode, struct file *filp)
     86{
     87	struct media_request *req = filp->private_data;
     88
     89	media_request_put(req);
     90	return 0;
     91}
     92
     93static __poll_t media_request_poll(struct file *filp,
     94				   struct poll_table_struct *wait)
     95{
     96	struct media_request *req = filp->private_data;
     97	unsigned long flags;
     98	__poll_t ret = 0;
     99
    100	if (!(poll_requested_events(wait) & EPOLLPRI))
    101		return 0;
    102
    103	poll_wait(filp, &req->poll_wait, wait);
    104	spin_lock_irqsave(&req->lock, flags);
    105	if (req->state == MEDIA_REQUEST_STATE_COMPLETE) {
    106		ret = EPOLLPRI;
    107		goto unlock;
    108	}
    109	if (req->state != MEDIA_REQUEST_STATE_QUEUED) {
    110		ret = EPOLLERR;
    111		goto unlock;
    112	}
    113
    114unlock:
    115	spin_unlock_irqrestore(&req->lock, flags);
    116	return ret;
    117}
    118
    119static long media_request_ioctl_queue(struct media_request *req)
    120{
    121	struct media_device *mdev = req->mdev;
    122	enum media_request_state state;
    123	unsigned long flags;
    124	int ret;
    125
    126	dev_dbg(mdev->dev, "request: queue %s\n", req->debug_str);
    127
    128	/*
    129	 * Ensure the request that is validated will be the one that gets queued
    130	 * next by serialising the queueing process. This mutex is also used
    131	 * to serialize with canceling a vb2 queue and with setting values such
    132	 * as controls in a request.
    133	 */
    134	mutex_lock(&mdev->req_queue_mutex);
    135
    136	media_request_get(req);
    137
    138	spin_lock_irqsave(&req->lock, flags);
    139	if (req->state == MEDIA_REQUEST_STATE_IDLE)
    140		req->state = MEDIA_REQUEST_STATE_VALIDATING;
    141	state = req->state;
    142	spin_unlock_irqrestore(&req->lock, flags);
    143	if (state != MEDIA_REQUEST_STATE_VALIDATING) {
    144		dev_dbg(mdev->dev,
    145			"request: unable to queue %s, request in state %s\n",
    146			req->debug_str, media_request_state_str(state));
    147		media_request_put(req);
    148		mutex_unlock(&mdev->req_queue_mutex);
    149		return -EBUSY;
    150	}
    151
    152	ret = mdev->ops->req_validate(req);
    153
    154	/*
    155	 * If the req_validate was successful, then we mark the state as QUEUED
    156	 * and call req_queue. The reason we set the state first is that this
    157	 * allows req_queue to unbind or complete the queued objects in case
    158	 * they are immediately 'consumed'. State changes from QUEUED to another
    159	 * state can only happen if either the driver changes the state or if
    160	 * the user cancels the vb2 queue. The driver can only change the state
    161	 * after each object is queued through the req_queue op (and note that
    162	 * that op cannot fail), so setting the state to QUEUED up front is
    163	 * safe.
    164	 *
    165	 * The other reason for changing the state is if the vb2 queue is
    166	 * canceled, and that uses the req_queue_mutex which is still locked
    167	 * while req_queue is called, so that's safe as well.
    168	 */
    169	spin_lock_irqsave(&req->lock, flags);
    170	req->state = ret ? MEDIA_REQUEST_STATE_IDLE
    171			 : MEDIA_REQUEST_STATE_QUEUED;
    172	spin_unlock_irqrestore(&req->lock, flags);
    173
    174	if (!ret)
    175		mdev->ops->req_queue(req);
    176
    177	mutex_unlock(&mdev->req_queue_mutex);
    178
    179	if (ret) {
    180		dev_dbg(mdev->dev, "request: can't queue %s (%d)\n",
    181			req->debug_str, ret);
    182		media_request_put(req);
    183	}
    184
    185	return ret;
    186}
    187
    188static long media_request_ioctl_reinit(struct media_request *req)
    189{
    190	struct media_device *mdev = req->mdev;
    191	unsigned long flags;
    192
    193	spin_lock_irqsave(&req->lock, flags);
    194	if (req->state != MEDIA_REQUEST_STATE_IDLE &&
    195	    req->state != MEDIA_REQUEST_STATE_COMPLETE) {
    196		dev_dbg(mdev->dev,
    197			"request: %s not in idle or complete state, cannot reinit\n",
    198			req->debug_str);
    199		spin_unlock_irqrestore(&req->lock, flags);
    200		return -EBUSY;
    201	}
    202	if (req->access_count) {
    203		dev_dbg(mdev->dev,
    204			"request: %s is being accessed, cannot reinit\n",
    205			req->debug_str);
    206		spin_unlock_irqrestore(&req->lock, flags);
    207		return -EBUSY;
    208	}
    209	req->state = MEDIA_REQUEST_STATE_CLEANING;
    210	spin_unlock_irqrestore(&req->lock, flags);
    211
    212	media_request_clean(req);
    213
    214	spin_lock_irqsave(&req->lock, flags);
    215	req->state = MEDIA_REQUEST_STATE_IDLE;
    216	spin_unlock_irqrestore(&req->lock, flags);
    217
    218	return 0;
    219}
    220
    221static long media_request_ioctl(struct file *filp, unsigned int cmd,
    222				unsigned long arg)
    223{
    224	struct media_request *req = filp->private_data;
    225
    226	switch (cmd) {
    227	case MEDIA_REQUEST_IOC_QUEUE:
    228		return media_request_ioctl_queue(req);
    229	case MEDIA_REQUEST_IOC_REINIT:
    230		return media_request_ioctl_reinit(req);
    231	default:
    232		return -ENOIOCTLCMD;
    233	}
    234}
    235
    236static const struct file_operations request_fops = {
    237	.owner = THIS_MODULE,
    238	.poll = media_request_poll,
    239	.unlocked_ioctl = media_request_ioctl,
    240#ifdef CONFIG_COMPAT
    241	.compat_ioctl = media_request_ioctl,
    242#endif /* CONFIG_COMPAT */
    243	.release = media_request_close,
    244};
    245
    246struct media_request *
    247media_request_get_by_fd(struct media_device *mdev, int request_fd)
    248{
    249	struct fd f;
    250	struct media_request *req;
    251
    252	if (!mdev || !mdev->ops ||
    253	    !mdev->ops->req_validate || !mdev->ops->req_queue)
    254		return ERR_PTR(-EBADR);
    255
    256	f = fdget(request_fd);
    257	if (!f.file)
    258		goto err_no_req_fd;
    259
    260	if (f.file->f_op != &request_fops)
    261		goto err_fput;
    262	req = f.file->private_data;
    263	if (req->mdev != mdev)
    264		goto err_fput;
    265
    266	/*
    267	 * Note: as long as someone has an open filehandle of the request,
    268	 * the request can never be released. The fdget() above ensures that
    269	 * even if userspace closes the request filehandle, the release()
    270	 * fop won't be called, so the media_request_get() always succeeds
    271	 * and there is no race condition where the request was released
    272	 * before media_request_get() is called.
    273	 */
    274	media_request_get(req);
    275	fdput(f);
    276
    277	return req;
    278
    279err_fput:
    280	fdput(f);
    281
    282err_no_req_fd:
    283	dev_dbg(mdev->dev, "cannot find request_fd %d\n", request_fd);
    284	return ERR_PTR(-EINVAL);
    285}
    286EXPORT_SYMBOL_GPL(media_request_get_by_fd);
    287
    288int media_request_alloc(struct media_device *mdev, int *alloc_fd)
    289{
    290	struct media_request *req;
    291	struct file *filp;
    292	int fd;
    293	int ret;
    294
    295	/* Either both are NULL or both are non-NULL */
    296	if (WARN_ON(!mdev->ops->req_alloc ^ !mdev->ops->req_free))
    297		return -ENOMEM;
    298
    299	if (mdev->ops->req_alloc)
    300		req = mdev->ops->req_alloc(mdev);
    301	else
    302		req = kzalloc(sizeof(*req), GFP_KERNEL);
    303	if (!req)
    304		return -ENOMEM;
    305
    306	fd = get_unused_fd_flags(O_CLOEXEC);
    307	if (fd < 0) {
    308		ret = fd;
    309		goto err_free_req;
    310	}
    311
    312	filp = anon_inode_getfile("request", &request_fops, NULL, O_CLOEXEC);
    313	if (IS_ERR(filp)) {
    314		ret = PTR_ERR(filp);
    315		goto err_put_fd;
    316	}
    317
    318	filp->private_data = req;
    319	req->mdev = mdev;
    320	req->state = MEDIA_REQUEST_STATE_IDLE;
    321	req->num_incomplete_objects = 0;
    322	kref_init(&req->kref);
    323	INIT_LIST_HEAD(&req->objects);
    324	spin_lock_init(&req->lock);
    325	init_waitqueue_head(&req->poll_wait);
    326	req->updating_count = 0;
    327	req->access_count = 0;
    328
    329	*alloc_fd = fd;
    330
    331	snprintf(req->debug_str, sizeof(req->debug_str), "%u:%d",
    332		 atomic_inc_return(&mdev->request_id), fd);
    333	dev_dbg(mdev->dev, "request: allocated %s\n", req->debug_str);
    334
    335	fd_install(fd, filp);
    336
    337	return 0;
    338
    339err_put_fd:
    340	put_unused_fd(fd);
    341
    342err_free_req:
    343	if (mdev->ops->req_free)
    344		mdev->ops->req_free(req);
    345	else
    346		kfree(req);
    347
    348	return ret;
    349}
    350
    351static void media_request_object_release(struct kref *kref)
    352{
    353	struct media_request_object *obj =
    354		container_of(kref, struct media_request_object, kref);
    355	struct media_request *req = obj->req;
    356
    357	if (WARN_ON(req))
    358		media_request_object_unbind(obj);
    359	obj->ops->release(obj);
    360}
    361
    362struct media_request_object *
    363media_request_object_find(struct media_request *req,
    364			  const struct media_request_object_ops *ops,
    365			  void *priv)
    366{
    367	struct media_request_object *obj;
    368	struct media_request_object *found = NULL;
    369	unsigned long flags;
    370
    371	if (WARN_ON(!ops || !priv))
    372		return NULL;
    373
    374	spin_lock_irqsave(&req->lock, flags);
    375	list_for_each_entry(obj, &req->objects, list) {
    376		if (obj->ops == ops && obj->priv == priv) {
    377			media_request_object_get(obj);
    378			found = obj;
    379			break;
    380		}
    381	}
    382	spin_unlock_irqrestore(&req->lock, flags);
    383	return found;
    384}
    385EXPORT_SYMBOL_GPL(media_request_object_find);
    386
    387void media_request_object_put(struct media_request_object *obj)
    388{
    389	kref_put(&obj->kref, media_request_object_release);
    390}
    391EXPORT_SYMBOL_GPL(media_request_object_put);
    392
    393void media_request_object_init(struct media_request_object *obj)
    394{
    395	obj->ops = NULL;
    396	obj->req = NULL;
    397	obj->priv = NULL;
    398	obj->completed = false;
    399	INIT_LIST_HEAD(&obj->list);
    400	kref_init(&obj->kref);
    401}
    402EXPORT_SYMBOL_GPL(media_request_object_init);
    403
    404int media_request_object_bind(struct media_request *req,
    405			      const struct media_request_object_ops *ops,
    406			      void *priv, bool is_buffer,
    407			      struct media_request_object *obj)
    408{
    409	unsigned long flags;
    410	int ret = -EBUSY;
    411
    412	if (WARN_ON(!ops->release))
    413		return -EBADR;
    414
    415	spin_lock_irqsave(&req->lock, flags);
    416
    417	if (WARN_ON(req->state != MEDIA_REQUEST_STATE_UPDATING &&
    418		    req->state != MEDIA_REQUEST_STATE_QUEUED))
    419		goto unlock;
    420
    421	obj->req = req;
    422	obj->ops = ops;
    423	obj->priv = priv;
    424
    425	if (is_buffer)
    426		list_add_tail(&obj->list, &req->objects);
    427	else
    428		list_add(&obj->list, &req->objects);
    429	req->num_incomplete_objects++;
    430	ret = 0;
    431
    432unlock:
    433	spin_unlock_irqrestore(&req->lock, flags);
    434	return ret;
    435}
    436EXPORT_SYMBOL_GPL(media_request_object_bind);
    437
    438void media_request_object_unbind(struct media_request_object *obj)
    439{
    440	struct media_request *req = obj->req;
    441	unsigned long flags;
    442	bool completed = false;
    443
    444	if (WARN_ON(!req))
    445		return;
    446
    447	spin_lock_irqsave(&req->lock, flags);
    448	list_del(&obj->list);
    449	obj->req = NULL;
    450
    451	if (req->state == MEDIA_REQUEST_STATE_COMPLETE)
    452		goto unlock;
    453
    454	if (WARN_ON(req->state == MEDIA_REQUEST_STATE_VALIDATING))
    455		goto unlock;
    456
    457	if (req->state == MEDIA_REQUEST_STATE_CLEANING) {
    458		if (!obj->completed)
    459			req->num_incomplete_objects--;
    460		goto unlock;
    461	}
    462
    463	if (WARN_ON(!req->num_incomplete_objects))
    464		goto unlock;
    465
    466	req->num_incomplete_objects--;
    467	if (req->state == MEDIA_REQUEST_STATE_QUEUED &&
    468	    !req->num_incomplete_objects) {
    469		req->state = MEDIA_REQUEST_STATE_COMPLETE;
    470		completed = true;
    471		wake_up_interruptible_all(&req->poll_wait);
    472	}
    473
    474unlock:
    475	spin_unlock_irqrestore(&req->lock, flags);
    476	if (obj->ops->unbind)
    477		obj->ops->unbind(obj);
    478	if (completed)
    479		media_request_put(req);
    480}
    481EXPORT_SYMBOL_GPL(media_request_object_unbind);
    482
    483void media_request_object_complete(struct media_request_object *obj)
    484{
    485	struct media_request *req = obj->req;
    486	unsigned long flags;
    487	bool completed = false;
    488
    489	spin_lock_irqsave(&req->lock, flags);
    490	if (obj->completed)
    491		goto unlock;
    492	obj->completed = true;
    493	if (WARN_ON(!req->num_incomplete_objects) ||
    494	    WARN_ON(req->state != MEDIA_REQUEST_STATE_QUEUED))
    495		goto unlock;
    496
    497	if (!--req->num_incomplete_objects) {
    498		req->state = MEDIA_REQUEST_STATE_COMPLETE;
    499		wake_up_interruptible_all(&req->poll_wait);
    500		completed = true;
    501	}
    502unlock:
    503	spin_unlock_irqrestore(&req->lock, flags);
    504	if (completed)
    505		media_request_put(req);
    506}
    507EXPORT_SYMBOL_GPL(media_request_object_complete);