/* * Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include #include "of-tegra-smmu.h" #include struct tegra_iommu_group { int group_id; struct iommu_group *group; struct list_head list; }; static LIST_HEAD(tegra_iommu_groups); static struct tegra_iommu_group *tegra_create_iommu_group(struct device *dev, int group_id) { struct tegra_iommu_group *group = NULL; group = kcalloc(1, sizeof(struct tegra_iommu_group), GFP_KERNEL); if (!group) return NULL; if (dev_is_pci(dev)) group->group = pci_device_group(dev); else group->group = generic_device_group(dev); group->group_id = group_id; list_add_tail(&group->list, &tegra_iommu_groups); return group; } void tegra_smmu_remove_iommu_groups(void) { struct tegra_iommu_group *group; struct tegra_iommu_group *tmp; list_for_each_entry_safe(group, tmp, &tegra_iommu_groups, list) { list_del(&group->list); kfree(group); } } struct iommu_group *tegra_smmu_of_get_group(struct device *dev) { u32 group_id; int ret; struct tegra_iommu_group *group; ret = of_property_read_u32_index(dev->of_node, "iommu-group-id", 0, &group_id); if (ret) return NULL; list_for_each_entry(group, &tegra_iommu_groups, list) { if (group->group_id == group_id) { dev_info(dev, "Adding to tegra-iommu group %d\n", group_id); return group->group; } } dev_info(dev, "Creating tegra-iommu group %d\n", group_id); group = tegra_create_iommu_group(dev, group_id); if (!group) return NULL; return group->group; }