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