| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294 |
- // SPDX-License-Identifier: GPL-2.0-only
- /*
- * Copyright (C) 2023, STMicroelectronics - All Rights Reserved
- */
- #include <linux/bitfield.h>
- #include <linux/bits.h>
- #include <linux/bus/stm32_firewall_device.h>
- #include <linux/device.h>
- #include <linux/err.h>
- #include <linux/init.h>
- #include <linux/io.h>
- #include <linux/kernel.h>
- #include <linux/module.h>
- #include <linux/of.h>
- #include <linux/of_platform.h>
- #include <linux/platform_device.h>
- #include <linux/types.h>
- #include <linux/slab.h>
- #include "stm32_firewall.h"
- /* Corresponds to STM32_FIREWALL_MAX_EXTRA_ARGS + firewall ID */
- #define STM32_FIREWALL_MAX_ARGS (STM32_FIREWALL_MAX_EXTRA_ARGS + 1)
- static LIST_HEAD(firewall_controller_list);
- static DEFINE_MUTEX(firewall_controller_list_lock);
- /* Firewall device API */
- int stm32_firewall_get_firewall(struct device_node *np, struct stm32_firewall *firewall,
- unsigned int nb_firewall)
- {
- struct stm32_firewall_controller *ctrl;
- struct of_phandle_iterator it;
- unsigned int i, j = 0;
- int err;
- if (!firewall || !nb_firewall)
- return -EINVAL;
- /* Parse property with phandle parsed out */
- of_for_each_phandle(&it, err, np, "access-controllers", "#access-controller-cells", 0) {
- struct of_phandle_args provider_args;
- struct device_node *provider = it.node;
- const char *fw_entry;
- bool match = false;
- if (err) {
- pr_err("Unable to get access-controllers property for node %s\n, err: %d",
- np->full_name, err);
- of_node_put(provider);
- return err;
- }
- if (j >= nb_firewall) {
- pr_err("Too many firewall controllers");
- of_node_put(provider);
- return -EINVAL;
- }
- provider_args.args_count = of_phandle_iterator_args(&it, provider_args.args,
- STM32_FIREWALL_MAX_ARGS);
- /* Check if the parsed phandle corresponds to a registered firewall controller */
- mutex_lock(&firewall_controller_list_lock);
- list_for_each_entry(ctrl, &firewall_controller_list, entry) {
- if (ctrl->dev->of_node->phandle == it.phandle) {
- match = true;
- firewall[j].firewall_ctrl = ctrl;
- break;
- }
- }
- mutex_unlock(&firewall_controller_list_lock);
- if (!match) {
- firewall[j].firewall_ctrl = NULL;
- pr_err("No firewall controller registered for %s\n", np->full_name);
- of_node_put(provider);
- return -ENODEV;
- }
- err = of_property_read_string_index(np, "access-controller-names", j, &fw_entry);
- if (err == 0)
- firewall[j].entry = fw_entry;
- /* Handle the case when there are no arguments given along with the phandle */
- if (provider_args.args_count < 0 ||
- provider_args.args_count > STM32_FIREWALL_MAX_ARGS) {
- of_node_put(provider);
- return -EINVAL;
- } else if (provider_args.args_count == 0) {
- firewall[j].extra_args_size = 0;
- firewall[j].firewall_id = U32_MAX;
- j++;
- continue;
- }
- /* The firewall ID is always the first argument */
- firewall[j].firewall_id = provider_args.args[0];
- /* Extra args start at the second argument */
- for (i = 0; i < provider_args.args_count - 1; i++)
- firewall[j].extra_args[i] = provider_args.args[i + 1];
- /* Remove the firewall ID arg that is not an extra argument */
- firewall[j].extra_args_size = provider_args.args_count - 1;
- j++;
- }
- return 0;
- }
- EXPORT_SYMBOL_GPL(stm32_firewall_get_firewall);
- int stm32_firewall_grant_access(struct stm32_firewall *firewall)
- {
- struct stm32_firewall_controller *firewall_controller;
- if (!firewall || firewall->firewall_id == U32_MAX)
- return -EINVAL;
- firewall_controller = firewall->firewall_ctrl;
- if (!firewall_controller)
- return -ENODEV;
- return firewall_controller->grant_access(firewall_controller, firewall->firewall_id);
- }
- EXPORT_SYMBOL_GPL(stm32_firewall_grant_access);
- int stm32_firewall_grant_access_by_id(struct stm32_firewall *firewall, u32 subsystem_id)
- {
- struct stm32_firewall_controller *firewall_controller;
- if (!firewall || subsystem_id == U32_MAX || firewall->firewall_id == U32_MAX)
- return -EINVAL;
- firewall_controller = firewall->firewall_ctrl;
- if (!firewall_controller)
- return -ENODEV;
- return firewall_controller->grant_access(firewall_controller, subsystem_id);
- }
- EXPORT_SYMBOL_GPL(stm32_firewall_grant_access_by_id);
- void stm32_firewall_release_access(struct stm32_firewall *firewall)
- {
- struct stm32_firewall_controller *firewall_controller;
- if (!firewall || firewall->firewall_id == U32_MAX) {
- pr_debug("Incorrect arguments when releasing a firewall access\n");
- return;
- }
- firewall_controller = firewall->firewall_ctrl;
- if (!firewall_controller) {
- pr_debug("No firewall controller to release\n");
- return;
- }
- firewall_controller->release_access(firewall_controller, firewall->firewall_id);
- }
- EXPORT_SYMBOL_GPL(stm32_firewall_release_access);
- void stm32_firewall_release_access_by_id(struct stm32_firewall *firewall, u32 subsystem_id)
- {
- struct stm32_firewall_controller *firewall_controller;
- if (!firewall || subsystem_id == U32_MAX || firewall->firewall_id == U32_MAX) {
- pr_debug("Incorrect arguments when releasing a firewall access");
- return;
- }
- firewall_controller = firewall->firewall_ctrl;
- if (!firewall_controller) {
- pr_debug("No firewall controller to release");
- return;
- }
- firewall_controller->release_access(firewall_controller, subsystem_id);
- }
- EXPORT_SYMBOL_GPL(stm32_firewall_release_access_by_id);
- /* Firewall controller API */
- int stm32_firewall_controller_register(struct stm32_firewall_controller *firewall_controller)
- {
- struct stm32_firewall_controller *ctrl;
- if (!firewall_controller)
- return -ENODEV;
- pr_info("Registering %s firewall controller\n", firewall_controller->name);
- mutex_lock(&firewall_controller_list_lock);
- list_for_each_entry(ctrl, &firewall_controller_list, entry) {
- if (ctrl == firewall_controller) {
- pr_debug("%s firewall controller already registered\n",
- firewall_controller->name);
- mutex_unlock(&firewall_controller_list_lock);
- return 0;
- }
- }
- list_add_tail(&firewall_controller->entry, &firewall_controller_list);
- mutex_unlock(&firewall_controller_list_lock);
- return 0;
- }
- EXPORT_SYMBOL_GPL(stm32_firewall_controller_register);
- void stm32_firewall_controller_unregister(struct stm32_firewall_controller *firewall_controller)
- {
- struct stm32_firewall_controller *ctrl;
- bool controller_removed = false;
- if (!firewall_controller) {
- pr_debug("Null reference while unregistering firewall controller\n");
- return;
- }
- mutex_lock(&firewall_controller_list_lock);
- list_for_each_entry(ctrl, &firewall_controller_list, entry) {
- if (ctrl == firewall_controller) {
- controller_removed = true;
- list_del_init(&ctrl->entry);
- break;
- }
- }
- mutex_unlock(&firewall_controller_list_lock);
- if (!controller_removed)
- pr_debug("There was no firewall controller named %s to unregister\n",
- firewall_controller->name);
- }
- EXPORT_SYMBOL_GPL(stm32_firewall_controller_unregister);
- int stm32_firewall_populate_bus(struct stm32_firewall_controller *firewall_controller)
- {
- struct stm32_firewall *firewalls;
- struct device_node *child;
- struct device *parent;
- unsigned int i;
- int len;
- int err;
- parent = firewall_controller->dev;
- dev_dbg(parent, "Populating %s system bus\n", dev_name(firewall_controller->dev));
- for_each_available_child_of_node(dev_of_node(parent), child) {
- /* The access-controllers property is mandatory for firewall bus devices */
- len = of_count_phandle_with_args(child, "access-controllers",
- "#access-controller-cells");
- if (len <= 0) {
- of_node_put(child);
- return -EINVAL;
- }
- firewalls = kcalloc(len, sizeof(*firewalls), GFP_KERNEL);
- if (!firewalls) {
- of_node_put(child);
- return -ENOMEM;
- }
- err = stm32_firewall_get_firewall(child, firewalls, (unsigned int)len);
- if (err) {
- kfree(firewalls);
- of_node_put(child);
- return err;
- }
- for (i = 0; i < len; i++) {
- if (firewall_controller->grant_access(firewall_controller,
- firewalls[i].firewall_id)) {
- /*
- * Peripheral access not allowed or not defined.
- * Mark the node as populated so platform bus won't probe it
- */
- of_detach_node(child);
- dev_err(parent, "%s: Device driver will not be probed\n",
- child->full_name);
- }
- }
- kfree(firewalls);
- }
- return 0;
- }
- EXPORT_SYMBOL_GPL(stm32_firewall_populate_bus);
|