.. | .. |
---|
| 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 | |
---|