brintos

brintos / linux-shallow public Read only

0
0
Text · 8.0 KiB · 2fc9761 Raw
295 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2023, STMicroelectronics - All Rights Reserved4 */5 6#include <linux/bitfield.h>7#include <linux/bits.h>8#include <linux/bus/stm32_firewall_device.h>9#include <linux/device.h>10#include <linux/err.h>11#include <linux/init.h>12#include <linux/io.h>13#include <linux/kernel.h>14#include <linux/module.h>15#include <linux/of.h>16#include <linux/of_platform.h>17#include <linux/platform_device.h>18#include <linux/types.h>19#include <linux/slab.h>20 21#include "stm32_firewall.h"22 23/* Corresponds to STM32_FIREWALL_MAX_EXTRA_ARGS + firewall ID */24#define STM32_FIREWALL_MAX_ARGS		(STM32_FIREWALL_MAX_EXTRA_ARGS + 1)25 26static LIST_HEAD(firewall_controller_list);27static DEFINE_MUTEX(firewall_controller_list_lock);28 29/* Firewall device API */30 31int stm32_firewall_get_firewall(struct device_node *np, struct stm32_firewall *firewall,32				unsigned int nb_firewall)33{34	struct stm32_firewall_controller *ctrl;35	struct of_phandle_iterator it;36	unsigned int i, j = 0;37	int err;38 39	if (!firewall || !nb_firewall)40		return -EINVAL;41 42	/* Parse property with phandle parsed out */43	of_for_each_phandle(&it, err, np, "access-controllers", "#access-controller-cells", 0) {44		struct of_phandle_args provider_args;45		struct device_node *provider = it.node;46		const char *fw_entry;47		bool match = false;48 49		if (err) {50			pr_err("Unable to get access-controllers property for node %s\n, err: %d",51			       np->full_name, err);52			of_node_put(provider);53			return err;54		}55 56		if (j >= nb_firewall) {57			pr_err("Too many firewall controllers");58			of_node_put(provider);59			return -EINVAL;60		}61 62		provider_args.args_count = of_phandle_iterator_args(&it, provider_args.args,63								    STM32_FIREWALL_MAX_ARGS);64 65		/* Check if the parsed phandle corresponds to a registered firewall controller */66		mutex_lock(&firewall_controller_list_lock);67		list_for_each_entry(ctrl, &firewall_controller_list, entry) {68			if (ctrl->dev->of_node->phandle == it.phandle) {69				match = true;70				firewall[j].firewall_ctrl = ctrl;71				break;72			}73		}74		mutex_unlock(&firewall_controller_list_lock);75 76		if (!match) {77			firewall[j].firewall_ctrl = NULL;78			pr_err("No firewall controller registered for %s\n", np->full_name);79			of_node_put(provider);80			return -ENODEV;81		}82 83		err = of_property_read_string_index(np, "access-controller-names", j, &fw_entry);84		if (err == 0)85			firewall[j].entry = fw_entry;86 87		/* Handle the case when there are no arguments given along with the phandle */88		if (provider_args.args_count < 0 ||89		    provider_args.args_count > STM32_FIREWALL_MAX_ARGS) {90			of_node_put(provider);91			return -EINVAL;92		} else if (provider_args.args_count == 0) {93			firewall[j].extra_args_size = 0;94			firewall[j].firewall_id = U32_MAX;95			j++;96			continue;97		}98 99		/* The firewall ID is always the first argument */100		firewall[j].firewall_id = provider_args.args[0];101 102		/* Extra args start at the second argument */103		for (i = 0; i < provider_args.args_count - 1; i++)104			firewall[j].extra_args[i] = provider_args.args[i + 1];105 106		/* Remove the firewall ID arg that is not an extra argument */107		firewall[j].extra_args_size = provider_args.args_count - 1;108 109		j++;110	}111 112	return 0;113}114EXPORT_SYMBOL_GPL(stm32_firewall_get_firewall);115 116int stm32_firewall_grant_access(struct stm32_firewall *firewall)117{118	struct stm32_firewall_controller *firewall_controller;119 120	if (!firewall || firewall->firewall_id == U32_MAX)121		return -EINVAL;122 123	firewall_controller = firewall->firewall_ctrl;124 125	if (!firewall_controller)126		return -ENODEV;127 128	return firewall_controller->grant_access(firewall_controller, firewall->firewall_id);129}130EXPORT_SYMBOL_GPL(stm32_firewall_grant_access);131 132int stm32_firewall_grant_access_by_id(struct stm32_firewall *firewall, u32 subsystem_id)133{134	struct stm32_firewall_controller *firewall_controller;135 136	if (!firewall || subsystem_id == U32_MAX || firewall->firewall_id == U32_MAX)137		return -EINVAL;138 139	firewall_controller = firewall->firewall_ctrl;140 141	if (!firewall_controller)142		return -ENODEV;143 144	return firewall_controller->grant_access(firewall_controller, subsystem_id);145}146EXPORT_SYMBOL_GPL(stm32_firewall_grant_access_by_id);147 148void stm32_firewall_release_access(struct stm32_firewall *firewall)149{150	struct stm32_firewall_controller *firewall_controller;151 152	if (!firewall || firewall->firewall_id == U32_MAX) {153		pr_debug("Incorrect arguments when releasing a firewall access\n");154		return;155	}156 157	firewall_controller = firewall->firewall_ctrl;158 159	if (!firewall_controller) {160		pr_debug("No firewall controller to release\n");161		return;162	}163 164	firewall_controller->release_access(firewall_controller, firewall->firewall_id);165}166EXPORT_SYMBOL_GPL(stm32_firewall_release_access);167 168void stm32_firewall_release_access_by_id(struct stm32_firewall *firewall, u32 subsystem_id)169{170	struct stm32_firewall_controller *firewall_controller;171 172	if (!firewall || subsystem_id == U32_MAX || firewall->firewall_id == U32_MAX) {173		pr_debug("Incorrect arguments when releasing a firewall access");174		return;175	}176 177	firewall_controller = firewall->firewall_ctrl;178 179	if (!firewall_controller) {180		pr_debug("No firewall controller to release");181		return;182	}183 184	firewall_controller->release_access(firewall_controller, subsystem_id);185}186EXPORT_SYMBOL_GPL(stm32_firewall_release_access_by_id);187 188/* Firewall controller API */189 190int stm32_firewall_controller_register(struct stm32_firewall_controller *firewall_controller)191{192	struct stm32_firewall_controller *ctrl;193 194	if (!firewall_controller)195		return -ENODEV;196 197	pr_info("Registering %s firewall controller\n", firewall_controller->name);198 199	mutex_lock(&firewall_controller_list_lock);200	list_for_each_entry(ctrl, &firewall_controller_list, entry) {201		if (ctrl == firewall_controller) {202			pr_debug("%s firewall controller already registered\n",203				 firewall_controller->name);204			mutex_unlock(&firewall_controller_list_lock);205			return 0;206		}207	}208	list_add_tail(&firewall_controller->entry, &firewall_controller_list);209	mutex_unlock(&firewall_controller_list_lock);210 211	return 0;212}213EXPORT_SYMBOL_GPL(stm32_firewall_controller_register);214 215void stm32_firewall_controller_unregister(struct stm32_firewall_controller *firewall_controller)216{217	struct stm32_firewall_controller *ctrl;218	bool controller_removed = false;219 220	if (!firewall_controller) {221		pr_debug("Null reference while unregistering firewall controller\n");222		return;223	}224 225	mutex_lock(&firewall_controller_list_lock);226	list_for_each_entry(ctrl, &firewall_controller_list, entry) {227		if (ctrl == firewall_controller) {228			controller_removed = true;229			list_del_init(&ctrl->entry);230			break;231		}232	}233	mutex_unlock(&firewall_controller_list_lock);234 235	if (!controller_removed)236		pr_debug("There was no firewall controller named %s to unregister\n",237			 firewall_controller->name);238}239EXPORT_SYMBOL_GPL(stm32_firewall_controller_unregister);240 241int stm32_firewall_populate_bus(struct stm32_firewall_controller *firewall_controller)242{243	struct stm32_firewall *firewalls;244	struct device_node *child;245	struct device *parent;246	unsigned int i;247	int len;248	int err;249 250	parent = firewall_controller->dev;251 252	dev_dbg(parent, "Populating %s system bus\n", dev_name(firewall_controller->dev));253 254	for_each_available_child_of_node(dev_of_node(parent), child) {255		/* The access-controllers property is mandatory for firewall bus devices */256		len = of_count_phandle_with_args(child, "access-controllers",257						 "#access-controller-cells");258		if (len <= 0) {259			of_node_put(child);260			return -EINVAL;261		}262 263		firewalls = kcalloc(len, sizeof(*firewalls), GFP_KERNEL);264		if (!firewalls) {265			of_node_put(child);266			return -ENOMEM;267		}268 269		err = stm32_firewall_get_firewall(child, firewalls, (unsigned int)len);270		if (err) {271			kfree(firewalls);272			of_node_put(child);273			return err;274		}275 276		for (i = 0; i < len; i++) {277			if (firewall_controller->grant_access(firewall_controller,278							      firewalls[i].firewall_id)) {279				/*280				 * Peripheral access not allowed or not defined.281				 * Mark the node as populated so platform bus won't probe it282				 */283				of_detach_node(child);284				dev_err(parent, "%s: Device driver will not be probed\n",285					child->full_name);286			}287		}288 289		kfree(firewalls);290	}291 292	return 0;293}294EXPORT_SYMBOL_GPL(stm32_firewall_populate_bus);295