| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 3 | | - * it under the terms of the GNU General Public License, version 2, as |
|---|
| 4 | | - * published by the Free Software Foundation. |
|---|
| 5 | | - * |
|---|
| 6 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 7 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 8 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 9 | | - * GNU General Public License for more details. |
|---|
| 10 | | - * |
|---|
| 11 | | - * You should have received a copy of the GNU General Public License |
|---|
| 12 | | - * along with this program; if not, write to the Free Software |
|---|
| 13 | | - * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|---|
| 14 | 3 | * |
|---|
| 15 | 4 | * Copyright (C) 2013 Freescale Semiconductor, Inc. |
|---|
| 16 | 5 | * Author: Varun Sethi <varun.sethi@freescale.com> |
|---|
| 17 | | - * |
|---|
| 18 | 6 | */ |
|---|
| 19 | 7 | |
|---|
| 20 | 8 | #define pr_fmt(fmt) "fsl-pamu-domain: %s: " fmt, __func__ |
|---|
| .. | .. |
|---|
| 335 | 323 | pamu_disable_liodn(info->liodn); |
|---|
| 336 | 324 | spin_unlock_irqrestore(&iommu_lock, flags); |
|---|
| 337 | 325 | spin_lock_irqsave(&device_domain_lock, flags); |
|---|
| 338 | | - info->dev->archdata.iommu_domain = NULL; |
|---|
| 326 | + dev_iommu_priv_set(info->dev, NULL); |
|---|
| 339 | 327 | kmem_cache_free(iommu_devinfo_cache, info); |
|---|
| 340 | 328 | spin_unlock_irqrestore(&device_domain_lock, flags); |
|---|
| 341 | 329 | } |
|---|
| .. | .. |
|---|
| 364 | 352 | * Check here if the device is already attached to domain or not. |
|---|
| 365 | 353 | * If the device is already attached to a domain detach it. |
|---|
| 366 | 354 | */ |
|---|
| 367 | | - old_domain_info = dev->archdata.iommu_domain; |
|---|
| 355 | + old_domain_info = dev_iommu_priv_get(dev); |
|---|
| 368 | 356 | if (old_domain_info && old_domain_info->domain != dma_domain) { |
|---|
| 369 | 357 | spin_unlock_irqrestore(&device_domain_lock, flags); |
|---|
| 370 | 358 | detach_device(dev, old_domain_info->domain); |
|---|
| .. | .. |
|---|
| 383 | 371 | * the info for the first LIODN as all |
|---|
| 384 | 372 | * LIODNs share the same domain |
|---|
| 385 | 373 | */ |
|---|
| 386 | | - if (!dev->archdata.iommu_domain) |
|---|
| 387 | | - dev->archdata.iommu_domain = info; |
|---|
| 374 | + if (!dev_iommu_priv_get(dev)) |
|---|
| 375 | + dev_iommu_priv_set(dev, info); |
|---|
| 388 | 376 | spin_unlock_irqrestore(&device_domain_lock, flags); |
|---|
| 389 | 377 | } |
|---|
| 390 | 378 | |
|---|
| .. | .. |
|---|
| 814 | 802 | return 0; |
|---|
| 815 | 803 | } |
|---|
| 816 | 804 | |
|---|
| 805 | +static int fsl_pamu_set_windows(struct iommu_domain *domain, u32 w_count) |
|---|
| 806 | +{ |
|---|
| 807 | + struct fsl_dma_domain *dma_domain = to_fsl_dma_domain(domain); |
|---|
| 808 | + unsigned long flags; |
|---|
| 809 | + int ret; |
|---|
| 810 | + |
|---|
| 811 | + spin_lock_irqsave(&dma_domain->domain_lock, flags); |
|---|
| 812 | + /* Ensure domain is inactive i.e. DMA should be disabled for the domain */ |
|---|
| 813 | + if (dma_domain->enabled) { |
|---|
| 814 | + pr_debug("Can't set geometry attributes as domain is active\n"); |
|---|
| 815 | + spin_unlock_irqrestore(&dma_domain->domain_lock, flags); |
|---|
| 816 | + return -EBUSY; |
|---|
| 817 | + } |
|---|
| 818 | + |
|---|
| 819 | + /* Ensure that the geometry has been set for the domain */ |
|---|
| 820 | + if (!dma_domain->geom_size) { |
|---|
| 821 | + pr_debug("Please configure geometry before setting the number of windows\n"); |
|---|
| 822 | + spin_unlock_irqrestore(&dma_domain->domain_lock, flags); |
|---|
| 823 | + return -EINVAL; |
|---|
| 824 | + } |
|---|
| 825 | + |
|---|
| 826 | + /* |
|---|
| 827 | + * Ensure we have valid window count i.e. it should be less than |
|---|
| 828 | + * maximum permissible limit and should be a power of two. |
|---|
| 829 | + */ |
|---|
| 830 | + if (w_count > pamu_get_max_subwin_cnt() || !is_power_of_2(w_count)) { |
|---|
| 831 | + pr_debug("Invalid window count\n"); |
|---|
| 832 | + spin_unlock_irqrestore(&dma_domain->domain_lock, flags); |
|---|
| 833 | + return -EINVAL; |
|---|
| 834 | + } |
|---|
| 835 | + |
|---|
| 836 | + ret = pamu_set_domain_geometry(dma_domain, &domain->geometry, |
|---|
| 837 | + w_count > 1 ? w_count : 0); |
|---|
| 838 | + if (!ret) { |
|---|
| 839 | + kfree(dma_domain->win_arr); |
|---|
| 840 | + dma_domain->win_arr = kcalloc(w_count, |
|---|
| 841 | + sizeof(*dma_domain->win_arr), |
|---|
| 842 | + GFP_ATOMIC); |
|---|
| 843 | + if (!dma_domain->win_arr) { |
|---|
| 844 | + spin_unlock_irqrestore(&dma_domain->domain_lock, flags); |
|---|
| 845 | + return -ENOMEM; |
|---|
| 846 | + } |
|---|
| 847 | + dma_domain->win_cnt = w_count; |
|---|
| 848 | + } |
|---|
| 849 | + spin_unlock_irqrestore(&dma_domain->domain_lock, flags); |
|---|
| 850 | + |
|---|
| 851 | + return ret; |
|---|
| 852 | +} |
|---|
| 853 | + |
|---|
| 817 | 854 | static int fsl_pamu_set_domain_attr(struct iommu_domain *domain, |
|---|
| 818 | 855 | enum iommu_attr attr_type, void *data) |
|---|
| 819 | 856 | { |
|---|
| .. | .. |
|---|
| 829 | 866 | break; |
|---|
| 830 | 867 | case DOMAIN_ATTR_FSL_PAMU_ENABLE: |
|---|
| 831 | 868 | ret = configure_domain_dma_state(dma_domain, *(int *)data); |
|---|
| 869 | + break; |
|---|
| 870 | + case DOMAIN_ATTR_WINDOWS: |
|---|
| 871 | + ret = fsl_pamu_set_windows(domain, *(u32 *)data); |
|---|
| 832 | 872 | break; |
|---|
| 833 | 873 | default: |
|---|
| 834 | 874 | pr_debug("Unsupported attribute type\n"); |
|---|
| .. | .. |
|---|
| 855 | 895 | break; |
|---|
| 856 | 896 | case DOMAIN_ATTR_FSL_PAMUV1: |
|---|
| 857 | 897 | *(int *)data = DOMAIN_ATTR_FSL_PAMUV1; |
|---|
| 898 | + break; |
|---|
| 899 | + case DOMAIN_ATTR_WINDOWS: |
|---|
| 900 | + *(u32 *)data = dma_domain->win_cnt; |
|---|
| 858 | 901 | break; |
|---|
| 859 | 902 | default: |
|---|
| 860 | 903 | pr_debug("Unsupported attribute type\n"); |
|---|
| .. | .. |
|---|
| 916 | 959 | static struct iommu_group *get_pci_device_group(struct pci_dev *pdev) |
|---|
| 917 | 960 | { |
|---|
| 918 | 961 | struct pci_controller *pci_ctl; |
|---|
| 919 | | - bool pci_endpt_partioning; |
|---|
| 962 | + bool pci_endpt_partitioning; |
|---|
| 920 | 963 | struct iommu_group *group = NULL; |
|---|
| 921 | 964 | |
|---|
| 922 | 965 | pci_ctl = pci_bus_to_host(pdev->bus); |
|---|
| 923 | | - pci_endpt_partioning = check_pci_ctl_endpt_part(pci_ctl); |
|---|
| 966 | + pci_endpt_partitioning = check_pci_ctl_endpt_part(pci_ctl); |
|---|
| 924 | 967 | /* We can partition PCIe devices so assign device group to the device */ |
|---|
| 925 | | - if (pci_endpt_partioning) { |
|---|
| 968 | + if (pci_endpt_partitioning) { |
|---|
| 926 | 969 | group = pci_device_group(&pdev->dev); |
|---|
| 927 | 970 | |
|---|
| 928 | 971 | /* |
|---|
| .. | .. |
|---|
| 973 | 1016 | return group; |
|---|
| 974 | 1017 | } |
|---|
| 975 | 1018 | |
|---|
| 976 | | -static int fsl_pamu_add_device(struct device *dev) |
|---|
| 1019 | +static struct iommu_device *fsl_pamu_probe_device(struct device *dev) |
|---|
| 977 | 1020 | { |
|---|
| 978 | | - struct iommu_group *group; |
|---|
| 979 | | - |
|---|
| 980 | | - group = iommu_group_get_for_dev(dev); |
|---|
| 981 | | - if (IS_ERR(group)) |
|---|
| 982 | | - return PTR_ERR(group); |
|---|
| 983 | | - |
|---|
| 984 | | - iommu_group_put(group); |
|---|
| 985 | | - |
|---|
| 986 | | - iommu_device_link(&pamu_iommu, dev); |
|---|
| 987 | | - |
|---|
| 988 | | - return 0; |
|---|
| 1021 | + return &pamu_iommu; |
|---|
| 989 | 1022 | } |
|---|
| 990 | 1023 | |
|---|
| 991 | | -static void fsl_pamu_remove_device(struct device *dev) |
|---|
| 1024 | +static void fsl_pamu_release_device(struct device *dev) |
|---|
| 992 | 1025 | { |
|---|
| 993 | | - iommu_device_unlink(&pamu_iommu, dev); |
|---|
| 994 | | - iommu_group_remove_device(dev); |
|---|
| 995 | | -} |
|---|
| 996 | | - |
|---|
| 997 | | -static int fsl_pamu_set_windows(struct iommu_domain *domain, u32 w_count) |
|---|
| 998 | | -{ |
|---|
| 999 | | - struct fsl_dma_domain *dma_domain = to_fsl_dma_domain(domain); |
|---|
| 1000 | | - unsigned long flags; |
|---|
| 1001 | | - int ret; |
|---|
| 1002 | | - |
|---|
| 1003 | | - spin_lock_irqsave(&dma_domain->domain_lock, flags); |
|---|
| 1004 | | - /* Ensure domain is inactive i.e. DMA should be disabled for the domain */ |
|---|
| 1005 | | - if (dma_domain->enabled) { |
|---|
| 1006 | | - pr_debug("Can't set geometry attributes as domain is active\n"); |
|---|
| 1007 | | - spin_unlock_irqrestore(&dma_domain->domain_lock, flags); |
|---|
| 1008 | | - return -EBUSY; |
|---|
| 1009 | | - } |
|---|
| 1010 | | - |
|---|
| 1011 | | - /* Ensure that the geometry has been set for the domain */ |
|---|
| 1012 | | - if (!dma_domain->geom_size) { |
|---|
| 1013 | | - pr_debug("Please configure geometry before setting the number of windows\n"); |
|---|
| 1014 | | - spin_unlock_irqrestore(&dma_domain->domain_lock, flags); |
|---|
| 1015 | | - return -EINVAL; |
|---|
| 1016 | | - } |
|---|
| 1017 | | - |
|---|
| 1018 | | - /* |
|---|
| 1019 | | - * Ensure we have valid window count i.e. it should be less than |
|---|
| 1020 | | - * maximum permissible limit and should be a power of two. |
|---|
| 1021 | | - */ |
|---|
| 1022 | | - if (w_count > pamu_get_max_subwin_cnt() || !is_power_of_2(w_count)) { |
|---|
| 1023 | | - pr_debug("Invalid window count\n"); |
|---|
| 1024 | | - spin_unlock_irqrestore(&dma_domain->domain_lock, flags); |
|---|
| 1025 | | - return -EINVAL; |
|---|
| 1026 | | - } |
|---|
| 1027 | | - |
|---|
| 1028 | | - ret = pamu_set_domain_geometry(dma_domain, &domain->geometry, |
|---|
| 1029 | | - w_count > 1 ? w_count : 0); |
|---|
| 1030 | | - if (!ret) { |
|---|
| 1031 | | - kfree(dma_domain->win_arr); |
|---|
| 1032 | | - dma_domain->win_arr = kcalloc(w_count, |
|---|
| 1033 | | - sizeof(*dma_domain->win_arr), |
|---|
| 1034 | | - GFP_ATOMIC); |
|---|
| 1035 | | - if (!dma_domain->win_arr) { |
|---|
| 1036 | | - spin_unlock_irqrestore(&dma_domain->domain_lock, flags); |
|---|
| 1037 | | - return -ENOMEM; |
|---|
| 1038 | | - } |
|---|
| 1039 | | - dma_domain->win_cnt = w_count; |
|---|
| 1040 | | - } |
|---|
| 1041 | | - spin_unlock_irqrestore(&dma_domain->domain_lock, flags); |
|---|
| 1042 | | - |
|---|
| 1043 | | - return ret; |
|---|
| 1044 | | -} |
|---|
| 1045 | | - |
|---|
| 1046 | | -static u32 fsl_pamu_get_windows(struct iommu_domain *domain) |
|---|
| 1047 | | -{ |
|---|
| 1048 | | - struct fsl_dma_domain *dma_domain = to_fsl_dma_domain(domain); |
|---|
| 1049 | | - |
|---|
| 1050 | | - return dma_domain->win_cnt; |
|---|
| 1051 | 1026 | } |
|---|
| 1052 | 1027 | |
|---|
| 1053 | 1028 | static const struct iommu_ops fsl_pamu_ops = { |
|---|
| .. | .. |
|---|
| 1058 | 1033 | .detach_dev = fsl_pamu_detach_device, |
|---|
| 1059 | 1034 | .domain_window_enable = fsl_pamu_window_enable, |
|---|
| 1060 | 1035 | .domain_window_disable = fsl_pamu_window_disable, |
|---|
| 1061 | | - .domain_get_windows = fsl_pamu_get_windows, |
|---|
| 1062 | | - .domain_set_windows = fsl_pamu_set_windows, |
|---|
| 1063 | 1036 | .iova_to_phys = fsl_pamu_iova_to_phys, |
|---|
| 1064 | 1037 | .domain_set_attr = fsl_pamu_set_domain_attr, |
|---|
| 1065 | 1038 | .domain_get_attr = fsl_pamu_get_domain_attr, |
|---|
| 1066 | | - .add_device = fsl_pamu_add_device, |
|---|
| 1067 | | - .remove_device = fsl_pamu_remove_device, |
|---|
| 1039 | + .probe_device = fsl_pamu_probe_device, |
|---|
| 1040 | + .release_device = fsl_pamu_release_device, |
|---|
| 1068 | 1041 | .device_group = fsl_pamu_device_group, |
|---|
| 1069 | 1042 | }; |
|---|
| 1070 | 1043 | |
|---|