brintos

brintos / linux-shallow public Read only

0
0
Text · 5.3 KiB · bc68cde Raw
232 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright(c) 2015 - 2019 Intel Corporation. All rights reserved.4 * Copyright(c) 2021 - 2024 Linaro Ltd.5 */6#include <linux/device.h>7#include <linux/init.h>8#include <linux/kernel.h>9#include <linux/list.h>10#include <linux/module.h>11#include <linux/mutex.h>12#include <linux/rpmb.h>13#include <linux/slab.h>14 15static DEFINE_IDA(rpmb_ida);16static DEFINE_MUTEX(rpmb_mutex);17 18/**19 * rpmb_dev_get() - increase rpmb device ref counter20 * @rdev: rpmb device21 */22struct rpmb_dev *rpmb_dev_get(struct rpmb_dev *rdev)23{24	if (rdev)25		get_device(&rdev->dev);26	return rdev;27}28EXPORT_SYMBOL_GPL(rpmb_dev_get);29 30/**31 * rpmb_dev_put() - decrease rpmb device ref counter32 * @rdev: rpmb device33 */34void rpmb_dev_put(struct rpmb_dev *rdev)35{36	if (rdev)37		put_device(&rdev->dev);38}39EXPORT_SYMBOL_GPL(rpmb_dev_put);40 41/**42 * rpmb_route_frames() - route rpmb frames to rpmb device43 * @rdev:	rpmb device44 * @req:	rpmb request frames45 * @req_len:	length of rpmb request frames in bytes46 * @rsp:	rpmb response frames47 * @rsp_len:	length of rpmb response frames in bytes48 *49 * Returns: < 0 on failure50 */51int rpmb_route_frames(struct rpmb_dev *rdev, u8 *req,52		      unsigned int req_len, u8 *rsp, unsigned int rsp_len)53{54	if (!req || !req_len || !rsp || !rsp_len)55		return -EINVAL;56 57	return rdev->descr.route_frames(rdev->dev.parent, req, req_len,58					rsp, rsp_len);59}60EXPORT_SYMBOL_GPL(rpmb_route_frames);61 62static void rpmb_dev_release(struct device *dev)63{64	struct rpmb_dev *rdev = to_rpmb_dev(dev);65 66	mutex_lock(&rpmb_mutex);67	ida_simple_remove(&rpmb_ida, rdev->id);68	mutex_unlock(&rpmb_mutex);69	kfree(rdev->descr.dev_id);70	kfree(rdev);71}72 73static struct class rpmb_class = {74	.name = "rpmb",75	.dev_release = rpmb_dev_release,76};77 78/**79 * rpmb_dev_find_device() - return first matching rpmb device80 * @start: rpmb device to begin with81 * @data: data for the match function82 * @match: the matching function83 *84 * Iterate over registered RPMB devices, and call @match() for each passing85 * it the RPMB device and @data.86 *87 * The return value of @match() is checked for each call. If it returns88 * anything other 0, break and return the found RPMB device.89 *90 * It's the callers responsibility to call rpmb_dev_put() on the returned91 * device, when it's done with it.92 *93 * Returns: a matching rpmb device or NULL on failure94 */95struct rpmb_dev *rpmb_dev_find_device(const void *data,96				      const struct rpmb_dev *start,97				      int (*match)(struct device *dev,98						   const void *data))99{100	struct device *dev;101	const struct device *start_dev = NULL;102 103	if (start)104		start_dev = &start->dev;105	dev = class_find_device(&rpmb_class, start_dev, data, match);106 107	return dev ? to_rpmb_dev(dev) : NULL;108}109EXPORT_SYMBOL_GPL(rpmb_dev_find_device);110 111int rpmb_interface_register(struct class_interface *intf)112{113	intf->class = &rpmb_class;114 115	return class_interface_register(intf);116}117EXPORT_SYMBOL_GPL(rpmb_interface_register);118 119void rpmb_interface_unregister(struct class_interface *intf)120{121	class_interface_unregister(intf);122}123EXPORT_SYMBOL_GPL(rpmb_interface_unregister);124 125/**126 * rpmb_dev_unregister() - unregister RPMB partition from the RPMB subsystem127 * @rdev: the rpmb device to unregister128 *129 * This function should be called from the release function of the130 * underlying device used when the RPMB device was registered.131 *132 * Returns: < 0 on failure133 */134int rpmb_dev_unregister(struct rpmb_dev *rdev)135{136	if (!rdev)137		return -EINVAL;138 139	device_del(&rdev->dev);140 141	rpmb_dev_put(rdev);142 143	return 0;144}145EXPORT_SYMBOL_GPL(rpmb_dev_unregister);146 147/**148 * rpmb_dev_register - register RPMB partition with the RPMB subsystem149 * @dev: storage device of the rpmb device150 * @descr: RPMB device description151 *152 * While registering the RPMB partition extract needed device information153 * while needed resources are available.154 *155 * Returns: a pointer to a 'struct rpmb_dev' or an ERR_PTR on failure156 */157struct rpmb_dev *rpmb_dev_register(struct device *dev,158				   struct rpmb_descr *descr)159{160	struct rpmb_dev *rdev;161	int ret;162 163	if (!dev || !descr || !descr->route_frames || !descr->dev_id ||164	    !descr->dev_id_len)165		return ERR_PTR(-EINVAL);166 167	rdev = kzalloc(sizeof(*rdev), GFP_KERNEL);168	if (!rdev)169		return ERR_PTR(-ENOMEM);170	rdev->descr = *descr;171	rdev->descr.dev_id = kmemdup(descr->dev_id, descr->dev_id_len,172				     GFP_KERNEL);173	if (!rdev->descr.dev_id) {174		ret = -ENOMEM;175		goto err_free_rdev;176	}177 178	mutex_lock(&rpmb_mutex);179	ret = ida_simple_get(&rpmb_ida, 0, 0, GFP_KERNEL);180	mutex_unlock(&rpmb_mutex);181	if (ret < 0)182		goto err_free_dev_id;183	rdev->id = ret;184 185	dev_set_name(&rdev->dev, "rpmb%d", rdev->id);186	rdev->dev.class = &rpmb_class;187	rdev->dev.parent = dev;188 189	ret = device_register(&rdev->dev);190	if (ret) {191		put_device(&rdev->dev);192		return ERR_PTR(ret);193	}194 195	dev_dbg(&rdev->dev, "registered device\n");196 197	return rdev;198 199err_free_dev_id:200	kfree(rdev->descr.dev_id);201err_free_rdev:202	kfree(rdev);203	return ERR_PTR(ret);204}205EXPORT_SYMBOL_GPL(rpmb_dev_register);206 207static int __init rpmb_init(void)208{209	int ret;210 211	ret = class_register(&rpmb_class);212	if (ret) {213		pr_err("couldn't create class\n");214		return ret;215	}216	ida_init(&rpmb_ida);217	return 0;218}219 220static void __exit rpmb_exit(void)221{222	ida_destroy(&rpmb_ida);223	class_unregister(&rpmb_class);224}225 226subsys_initcall(rpmb_init);227module_exit(rpmb_exit);228 229MODULE_AUTHOR("Jens Wiklander <jens.wiklander@linaro.org>");230MODULE_DESCRIPTION("RPMB class");231MODULE_LICENSE("GPL");232