1 /*
2 * xen/drivers/passthrough/arm/iommu_fwspec.c
3 *
4 * Contains functions to maintain per-device firmware data
5 *
6 * Based on Linux's iommu_fwspec support you can find at:
7 * drivers/iommu/iommu.c
8 *
9 * Copyright (C) 2007-2008 Advanced Micro Devices, Inc.
10 *
11 * Copyright (C) 2019 EPAM Systems Inc.
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms and conditions of the GNU General Public
15 * License, version 2, as published by the Free Software Foundation.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public
23 * License along with this program; If not, see <http://www.gnu.org/licenses/>.
24 */
25
26 #include <xen/iommu.h>
27 #include <xen/lib.h>
28
29 #include <asm/device.h>
30 #include <asm/iommu_fwspec.h>
31
iommu_fwspec_init(struct device * dev,struct device * iommu_dev)32 int iommu_fwspec_init(struct device *dev, struct device *iommu_dev)
33 {
34 struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
35
36 if ( fwspec )
37 {
38 /* We expect the device to be protected by only one IOMMU. */
39 if ( fwspec->iommu_dev != iommu_dev )
40 return -EINVAL;
41
42 return 0;
43 }
44
45 /*
46 * Allocate with ids[1] to avoid the re-allocation in the common case
47 * where a device has a single device ID.
48 */
49 fwspec = xzalloc_flex_struct(struct iommu_fwspec, ids, 1);
50 if ( !fwspec )
51 return -ENOMEM;
52
53 fwspec->iommu_dev = iommu_dev;
54 dev_iommu_fwspec_set(dev, fwspec);
55
56 return 0;
57 }
58
iommu_fwspec_free(struct device * dev)59 void iommu_fwspec_free(struct device *dev)
60 {
61 struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
62
63 xfree(fwspec);
64 dev_iommu_fwspec_set(dev, NULL);
65 }
66
iommu_fwspec_add_ids(struct device * dev,const uint32_t * ids,unsigned int num_ids)67 int iommu_fwspec_add_ids(struct device *dev, const uint32_t *ids,
68 unsigned int num_ids)
69 {
70 struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
71 unsigned int i;
72
73 if ( !fwspec )
74 return -EINVAL;
75
76 fwspec = xrealloc_flex_struct(fwspec, ids, fwspec->num_ids + num_ids);
77 if ( !fwspec )
78 return -ENOMEM;
79
80 dev_iommu_fwspec_set(dev, fwspec);
81
82 for ( i = 0; i < num_ids; i++ )
83 fwspec->ids[fwspec->num_ids + i] = ids[i];
84
85 fwspec->num_ids += num_ids;
86
87 return 0;
88 }
89
90 /*
91 * Local variables:
92 * mode: C
93 * c-file-style: "BSD"
94 * c-basic-offset: 4
95 * indent-tabs-mode: nil
96 * End:
97 */
98