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-dev-allocator.c (3569B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * media-dev-allocator.c - Media Controller Device Allocator API
      4 *
      5 * Copyright (c) 2019 Shuah Khan <shuah@kernel.org>
      6 *
      7 * Credits: Suggested by Laurent Pinchart <laurent.pinchart@ideasonboard.com>
      8 */
      9
     10/*
     11 * This file adds a global refcounted Media Controller Device Instance API.
     12 * A system wide global media device list is managed and each media device
     13 * includes a kref count. The last put on the media device releases the media
     14 * device instance.
     15 *
     16 */
     17
     18#include <linux/kref.h>
     19#include <linux/module.h>
     20#include <linux/slab.h>
     21#include <linux/usb.h>
     22
     23#include <media/media-device.h>
     24#include <media/media-dev-allocator.h>
     25
     26static LIST_HEAD(media_device_list);
     27static DEFINE_MUTEX(media_device_lock);
     28
     29struct media_device_instance {
     30	struct media_device mdev;
     31	struct module *owner;
     32	struct list_head list;
     33	struct kref refcount;
     34};
     35
     36static inline struct media_device_instance *
     37to_media_device_instance(struct media_device *mdev)
     38{
     39	return container_of(mdev, struct media_device_instance, mdev);
     40}
     41
     42static void media_device_instance_release(struct kref *kref)
     43{
     44	struct media_device_instance *mdi =
     45		container_of(kref, struct media_device_instance, refcount);
     46
     47	dev_dbg(mdi->mdev.dev, "%s: releasing Media Device\n", __func__);
     48
     49	mutex_lock(&media_device_lock);
     50
     51	media_device_unregister(&mdi->mdev);
     52	media_device_cleanup(&mdi->mdev);
     53
     54	list_del(&mdi->list);
     55	mutex_unlock(&media_device_lock);
     56
     57	kfree(mdi);
     58}
     59
     60/* Callers should hold media_device_lock when calling this function */
     61static struct media_device *__media_device_get(struct device *dev,
     62						const char *module_name,
     63						struct module *owner)
     64{
     65	struct media_device_instance *mdi;
     66
     67	list_for_each_entry(mdi, &media_device_list, list) {
     68		if (mdi->mdev.dev != dev)
     69			continue;
     70
     71		kref_get(&mdi->refcount);
     72
     73		/* get module reference for the media_device owner */
     74		if (owner != mdi->owner && !try_module_get(mdi->owner))
     75			dev_err(dev,
     76				"%s: module %s get owner reference error\n",
     77					__func__, module_name);
     78		else
     79			dev_dbg(dev, "%s: module %s got owner reference\n",
     80					__func__, module_name);
     81		return &mdi->mdev;
     82	}
     83
     84	mdi = kzalloc(sizeof(*mdi), GFP_KERNEL);
     85	if (!mdi)
     86		return NULL;
     87
     88	mdi->owner = owner;
     89	kref_init(&mdi->refcount);
     90	list_add_tail(&mdi->list, &media_device_list);
     91
     92	dev_dbg(dev, "%s: Allocated media device for owner %s\n",
     93			__func__, module_name);
     94	return &mdi->mdev;
     95}
     96
     97struct media_device *media_device_usb_allocate(struct usb_device *udev,
     98					       const char *module_name,
     99					       struct module *owner)
    100{
    101	struct media_device *mdev;
    102
    103	mutex_lock(&media_device_lock);
    104	mdev = __media_device_get(&udev->dev, module_name, owner);
    105	if (!mdev) {
    106		mutex_unlock(&media_device_lock);
    107		return ERR_PTR(-ENOMEM);
    108	}
    109
    110	/* check if media device is already initialized */
    111	if (!mdev->dev)
    112		__media_device_usb_init(mdev, udev, udev->product,
    113					module_name);
    114	mutex_unlock(&media_device_lock);
    115	return mdev;
    116}
    117EXPORT_SYMBOL_GPL(media_device_usb_allocate);
    118
    119void media_device_delete(struct media_device *mdev, const char *module_name,
    120			 struct module *owner)
    121{
    122	struct media_device_instance *mdi = to_media_device_instance(mdev);
    123
    124	mutex_lock(&media_device_lock);
    125	/* put module reference for the media_device owner */
    126	if (mdi->owner != owner) {
    127		module_put(mdi->owner);
    128		dev_dbg(mdi->mdev.dev,
    129			"%s: module %s put owner module reference\n",
    130			__func__, module_name);
    131	}
    132	mutex_unlock(&media_device_lock);
    133	kref_put(&mdi->refcount, media_device_instance_release);
    134}
    135EXPORT_SYMBOL_GPL(media_device_delete);