1
This series introduces SMMU handling for PCIe passthrough on ARM. These patches
1
This series introduces SMMU handling for PCIe passthrough on ARM. These patches
2
are independent from (and don't depend on) the vPCI reference counting/locking
2
should be able to be upstreamed independently from the vPCI series [1]. See [2]
3
work in progress, and should be able to be upstreamed independently.
3
for notes about test cases.
4
5
[1] https://lists.xenproject.org/archives/html/xen-devel/2023-10/msg00660.html
6
[2] https://lists.xenproject.org/archives/html/xen-devel/2023-06/msg01135.html
7
8
v6->v7:
9
* drop ("xen/arm: don't pass iommu properties to hwdom for iommu-map")
10
11
v5->v6:
12
* don't revert ("xen/arm: Add cmdline boot option "pci-passthrough = <boolean>"")
13
* add ("xen/arm: enable dom0 to use PCI devices with pci-passthrough=no")
14
15
v4->v5:
16
* drop ("xen/arm: Improve readability of check for registered devices")
17
* drop ("xen/arm: Move is_protected flag to struct device")
18
* add ("xen/arm: don't pass iommu properties to hwdom for iommu-map")
19
* add ("xen/arm: Fix mapping for PCI bridge mmio region")
20
* revert ("xen/arm: Add cmdline boot option "pci-passthrough = <boolean>"")
21
* add ("xen/arm: Map ITS doorbell register to IOMMU page tables.")
22
* fix test case #1 with PCI device in dom0
4
23
5
v3->v4:
24
v3->v4:
6
* split a change from ("xen/arm: Move is_protected flag to struct device") into
25
* split a change from ("xen/arm: Move is_protected flag to struct device") into
7
a new separate patch
26
a new separate patch
8
* see individual patches for further details
27
* see individual patches for further details
...
...
11
* drop "pci/arm: Use iommu_add_dt_pci_device()"
30
* drop "pci/arm: Use iommu_add_dt_pci_device()"
12
* drop "RFC: pci/arm: don't do iommu call for phantom functions"
31
* drop "RFC: pci/arm: don't do iommu call for phantom functions"
13
* move invocation of sideband ID mapping function to add_device()
32
* move invocation of sideband ID mapping function to add_device()
14
platform_ops/iommu_ops hook
33
platform_ops/iommu_ops hook
15
34
16
v1->v2:
17
* phantom device handling
18
* shuffle around iommu_add_dt_pci_device()
19
35
20
Oleksandr Andrushchenko (1):
36
Oleksandr Andrushchenko (1):
21
xen/arm: smmuv2: Add PCI devices support for SMMUv2
37
xen/arm: smmuv2: Add PCI devices support for SMMUv2
22
38
23
Oleksandr Tyshchenko (4):
39
Oleksandr Tyshchenko (2):
24
xen/arm: Improve readability of check for registered devices
25
xen/arm: Move is_protected flag to struct device
26
iommu/arm: Add iommu_dt_xlate()
40
iommu/arm: Add iommu_dt_xlate()
27
iommu/arm: Introduce iommu_add_dt_pci_sideband_ids API
41
iommu/arm: Introduce iommu_add_dt_pci_sideband_ids API
28
42
29
Rahul Singh (1):
43
Rahul Singh (3):
30
xen/arm: smmuv3: Add PCI devices support for SMMUv3
44
xen/arm: smmuv3: Add PCI devices support for SMMUv3
45
xen/arm: Fix mapping for PCI bridge mmio region
46
xen/arm: Map ITS doorbell register to IOMMU page tables
31
47
32
Stewart Hildebrand (1):
48
Stewart Hildebrand (2):
33
iommu/arm: iommu_add_dt_pci_sideband_ids phantom handling
49
iommu/arm: iommu_add_dt_pci_sideband_ids phantom handling
50
xen/arm: enable dom0 to use PCI devices with pci-passthrough=no
34
51
35
xen/arch/arm/domain_build.c | 4 +-
52
xen/arch/arm/device.c | 2 +-
36
xen/arch/arm/include/asm/device.h | 14 ++
53
xen/arch/arm/pci/pci.c | 5 +-
37
xen/common/device_tree.c | 2 +-
54
xen/arch/arm/vgic-v3-its.c | 20 +++
38
xen/drivers/passthrough/arm/ipmmu-vmsa.c | 4 +-
55
xen/arch/x86/include/asm/pci.h | 6 -
39
xen/drivers/passthrough/arm/smmu-v3.c | 81 ++++++++-
56
xen/common/device-tree/device-tree.c | 91 ++++++++++++
40
xen/drivers/passthrough/arm/smmu.c | 122 +++++++++++---
57
xen/drivers/passthrough/arm/smmu-v3.c | 117 ++++++++++++++--
41
xen/drivers/passthrough/device_tree.c | 205 ++++++++++++++++++++---
58
xen/drivers/passthrough/arm/smmu.c | 190 ++++++++++++++++++++------
42
xen/include/xen/device_tree.h | 38 +++--
59
xen/drivers/passthrough/device_tree.c | 97 ++++++++++---
43
xen/include/xen/iommu.h | 22 ++-
60
xen/drivers/pci/physdev.c | 4 +-
44
9 files changed, 423 insertions(+), 69 deletions(-)
61
xen/include/xen/device_tree.h | 23 ++++
62
xen/include/xen/iommu.h | 31 ++++-
63
11 files changed, 502 insertions(+), 84 deletions(-)
45
64
46
--
65
--
47
2.40.1
66
2.34.1
diff view generated by jsdifflib
...
...
7
7
8
While at it introduce NO_IOMMU to avoid magic "1".
8
While at it introduce NO_IOMMU to avoid magic "1".
9
9
10
Signed-off-by: Oleksandr Tyshchenko <oleksandr_tyshchenko@epam.com>
10
Signed-off-by: Oleksandr Tyshchenko <oleksandr_tyshchenko@epam.com>
11
Signed-off-by: Stewart Hildebrand <stewart.hildebrand@amd.com>
11
Signed-off-by: Stewart Hildebrand <stewart.hildebrand@amd.com>
12
Signed-off-by: Mykyta Poturai <mykyta_poturai@epam.com>
13
Reviewed-by: Julien Grall <jgrall@amazon.com>
12
---
14
---
15
v6->v7:
16
* explained NO_IOMMU in comments
17
18
v5->v6:
19
* pass ops parameter to iommu_dt_xlate()
20
* add Julien's R-b
21
22
v4->v5:
23
* rebase on top of "dynamic node programming using overlay dtbo" series
24
* move #define NO_IOMMU 1 to header
25
* s/these/this/ inside comment
26
13
v3->v4:
27
v3->v4:
14
* make dt_phandle_args *iommu_spec const
28
* make dt_phandle_args *iommu_spec const
15
* move !ops->add_device check to helper
29
* move !ops->add_device check to helper
16
30
17
v2->v3:
31
v2->v3:
...
...
26
40
27
(cherry picked from commit c26bab0415ca303df86aba1d06ef8edc713734d3 from
41
(cherry picked from commit c26bab0415ca303df86aba1d06ef8edc713734d3 from
28
the downstream branch poc/pci-passthrough from
42
the downstream branch poc/pci-passthrough from
29
https://gitlab.com/xen-project/people/bmarquis/xen-arm-poc.git)
43
https://gitlab.com/xen-project/people/bmarquis/xen-arm-poc.git)
30
---
44
---
31
xen/drivers/passthrough/device_tree.c | 47 ++++++++++++++++++---------
45
xen/drivers/passthrough/device_tree.c | 48 +++++++++++++++++----------
32
1 file changed, 31 insertions(+), 16 deletions(-)
46
xen/include/xen/iommu.h | 3 ++
47
2 files changed, 33 insertions(+), 18 deletions(-)
33
48
34
diff --git a/xen/drivers/passthrough/device_tree.c b/xen/drivers/passthrough/device_tree.c
49
diff --git a/xen/drivers/passthrough/device_tree.c b/xen/drivers/passthrough/device_tree.c
35
index XXXXXXX..XXXXXXX 100644
50
index XXXXXXX..XXXXXXX 100644
36
--- a/xen/drivers/passthrough/device_tree.c
51
--- a/xen/drivers/passthrough/device_tree.c
37
+++ b/xen/drivers/passthrough/device_tree.c
52
+++ b/xen/drivers/passthrough/device_tree.c
38
@@ -XXX,XX +XXX,XX @@ int iommu_release_dt_devices(struct domain *d)
53
@@ -XXX,XX +XXX,XX @@ int iommu_release_dt_devices(struct domain *d)
39
return 0;
54
return 0;
40
}
55
}
41
56
42
+/* This correlation must not be altered */
43
+#define NO_IOMMU 1
44
+
45
+static int iommu_dt_xlate(struct device *dev,
57
+static int iommu_dt_xlate(struct device *dev,
46
+ const struct dt_phandle_args *iommu_spec)
58
+ const struct dt_phandle_args *iommu_spec,
59
+ const struct iommu_ops *ops)
47
+{
60
+{
48
+ const struct iommu_ops *ops = iommu_get_ops();
49
+ int rc;
61
+ int rc;
50
+
62
+
51
+ if ( !ops->dt_xlate )
63
+ if ( !ops->dt_xlate )
52
+ return -EINVAL;
64
+ return -EINVAL;
53
+
65
+
...
...
64
+ * The driver is responsible to decide how to interpret them.
76
+ * The driver is responsible to decide how to interpret them.
65
+ */
77
+ */
66
+ return ops->dt_xlate(dev, iommu_spec);
78
+ return ops->dt_xlate(dev, iommu_spec);
67
+}
79
+}
68
+
80
+
69
int iommu_add_dt_device(struct dt_device_node *np)
81
int iommu_remove_dt_device(struct dt_device_node *np)
70
{
82
{
83
const struct iommu_ops *ops = iommu_get_ops();
84
@@ -XXX,XX +XXX,XX @@ int iommu_remove_dt_device(struct dt_device_node *np)
85
ASSERT(rw_is_locked(&dt_host_lock));
86
87
if ( !iommu_enabled )
88
- return 1;
89
+ return NO_IOMMU;
90
91
if ( !ops )
92
return -EOPNOTSUPP;
93
@@ -XXX,XX +XXX,XX @@ int iommu_add_dt_device(struct dt_device_node *np)
71
const struct iommu_ops *ops = iommu_get_ops();
94
const struct iommu_ops *ops = iommu_get_ops();
72
struct dt_phandle_args iommu_spec;
95
struct dt_phandle_args iommu_spec;
73
struct device *dev = dt_to_dev(np);
96
struct device *dev = dt_to_dev(np);
74
- int rc = 1, index = 0;
97
- int rc = 1, index = 0;
75
+ int rc = NO_IOMMU, index = 0;
98
+ int rc = NO_IOMMU, index = 0;
76
99
100
ASSERT(system_state < SYS_STATE_active || rw_is_locked(&dt_host_lock));
101
77
if ( !iommu_enabled )
102
if ( !iommu_enabled )
78
- return 1;
103
- return 1;
79
+ return NO_IOMMU;
104
+ return NO_IOMMU;
80
105
81
if ( !ops )
106
if ( !ops )
82
return -EINVAL;
107
return -EINVAL;
83
@@ -XXX,XX +XXX,XX @@ int iommu_add_dt_device(struct dt_device_node *np)
108
@@ -XXX,XX +XXX,XX @@ int iommu_add_dt_device(struct dt_device_node *np)
109
{
110
/*
84
* The driver which supports generic IOMMU DT bindings must have
111
* The driver which supports generic IOMMU DT bindings must have
85
* these callback implemented.
112
- * these callback implemented.
113
+ * this callback implemented.
86
*/
114
*/
87
- if ( !ops->add_device || !ops->dt_xlate )
115
- if ( !ops->add_device || !ops->dt_xlate )
88
+ if ( !ops->add_device )
116
+ if ( !ops->add_device )
89
return -EINVAL;
117
{
118
rc = -EINVAL;
119
goto fail;
120
}
90
121
91
- if ( !dt_device_is_available(iommu_spec.np) )
122
- if ( !dt_device_is_available(iommu_spec.np) )
92
- break;
123
- break;
93
-
124
-
94
- rc = iommu_fwspec_init(dev, &iommu_spec.np->dev);
125
- rc = iommu_fwspec_init(dev, &iommu_spec.np->dev);
...
...
99
- * Provide DT IOMMU specifier which describes the IOMMU master
130
- * Provide DT IOMMU specifier which describes the IOMMU master
100
- * interfaces of that device (device IDs, etc) to the driver.
131
- * interfaces of that device (device IDs, etc) to the driver.
101
- * The driver is responsible to decide how to interpret them.
132
- * The driver is responsible to decide how to interpret them.
102
- */
133
- */
103
- rc = ops->dt_xlate(dev, &iommu_spec);
134
- rc = ops->dt_xlate(dev, &iommu_spec);
104
+ rc = iommu_dt_xlate(dev, &iommu_spec);
135
+ rc = iommu_dt_xlate(dev, &iommu_spec, ops);
105
if ( rc )
136
if ( rc )
106
break;
137
break;
107
138
139
diff --git a/xen/include/xen/iommu.h b/xen/include/xen/iommu.h
140
index XXXXXXX..XXXXXXX 100644
141
--- a/xen/include/xen/iommu.h
142
+++ b/xen/include/xen/iommu.h
143
@@ -XXX,XX +XXX,XX @@ int iommu_do_dt_domctl(struct xen_domctl *domctl, struct domain *d,
144
*/
145
int iommu_remove_dt_device(struct dt_device_node *np);
146
147
+/* Error code for reporting no IOMMU is present */
148
+#define NO_IOMMU 1
149
+
150
#endif /* HAS_DEVICE_TREE */
151
152
struct page_info;
108
--
153
--
109
2.40.1
154
2.34.1
diff view generated by jsdifflib
...
...
6
6
7
This behaves similarly to the existing iommu_add_dt_device API, except it
7
This behaves similarly to the existing iommu_add_dt_device API, except it
8
handles PCI devices, and it is to be invoked from the add_device hook in the
8
handles PCI devices, and it is to be invoked from the add_device hook in the
9
SMMU driver.
9
SMMU driver.
10
10
11
The function of_map_id to translate an ID through a downstream mapping
11
The function dt_map_id to translate an ID through a downstream mapping
12
(which is also suitable for mapping Requester ID) was borrowed from Linux
12
(which is also suitable for mapping Requester ID) was borrowed from Linux
13
(v5.10-rc6) and updated according to the Xen code base.
13
(v5.10-rc6) and updated according to the Xen code base.
14
14
15
[1] https://www.kernel.org/doc/Documentation/devicetree/bindings/pci/pci-iommu.txt
15
[1] https://www.kernel.org/doc/Documentation/devicetree/bindings/pci/pci-iommu.txt
16
16
17
Signed-off-by: Oleksandr Tyshchenko <oleksandr_tyshchenko@epam.com>
17
Signed-off-by: Oleksandr Tyshchenko <oleksandr_tyshchenko@epam.com>
18
Signed-off-by: Stewart Hildebrand <stewart.hildebrand@amd.com>
18
Signed-off-by: Stewart Hildebrand <stewart.hildebrand@amd.com>
19
Signed-off-by: Mykyta Poturai <mykyta_poturai@epam.com>
19
---
20
---
21
Regarding pci_for_each_dma_alias question: getting host bridge node
22
directly seems like a simpler solution with the same result. AFAIU
23
with pci_for_each_dma_alias in linux we would arrive to the host brige
24
node anyway, but also try to call dt_map_id for each device along the
25
way. I am not sure why exactly it is done this way in linux, as
26
according to the pci-iommu.txt, iommu-map node can only be present in
27
the PCI root.
28
29
v6->v7:
30
* put iommu_add_pci_sideband_ids under ifdef
31
* remove ifdef CONFIG_APCI
32
* style: add newline for symmetry
33
34
v5->v6:
35
* pass ops to iommu_dt_xlate()
36
37
v4->v5:
38
* style: add newlines after variable declarations and before return in iommu.h
39
* drop device_is_protected() check in iommu_add_dt_pci_sideband_ids()
40
* rebase on top of ("dynamic node programming using overlay dtbo") series
41
* fix typo in commit message
42
* remove #ifdef around dt_map_id() prototype
43
* move dt_map_id() to xen/common/device_tree.c
44
* add function name in error prints
45
* use dprintk for debug prints
46
* use GENMASK and #include <xen/bitops.h>
47
* fix typo in comment
48
* remove unnecessary (int) cast in loop condition
49
* assign *id_out and return success in case of no translation in dt_map_id()
50
* don't initialize local variable unnecessarily
51
* return error in case of ACPI/no DT in iommu_add_{dt_}pci_sideband_ids()
52
20
v3->v4:
53
v3->v4:
21
* wrap #include <asm/acpi.h> and if ( acpi_disabled ) in #ifdef CONFIG_ACPI
54
* wrap #include <asm/acpi.h> and if ( acpi_disabled ) in #ifdef CONFIG_ACPI
22
* fix Michal's remarks about style, parenthesis, and print formats
55
* fix Michal's remarks about style, parenthesis, and print formats
23
* remove !ops->dt_xlate check since it is already in iommu_dt_xlate helper
56
* remove !ops->dt_xlate check since it is already in iommu_dt_xlate helper
24
* rename s/iommu_dt_pci_map_id/dt_map_id/ because it is generic, not specific
57
* rename s/iommu_dt_pci_map_id/dt_map_id/ because it is generic, not specific
...
...
56
89
57
(cherry picked from commit 734e3bf6ee77e7947667ab8fa96c25b349c2e1da from
90
(cherry picked from commit 734e3bf6ee77e7947667ab8fa96c25b349c2e1da from
58
the downstream branch poc/pci-passthrough from
91
the downstream branch poc/pci-passthrough from
59
https://gitlab.com/xen-project/people/bmarquis/xen-arm-poc.git)
92
https://gitlab.com/xen-project/people/bmarquis/xen-arm-poc.git)
60
---
93
---
61
xen/drivers/passthrough/device_tree.c | 134 ++++++++++++++++++++++++++
94
xen/common/device-tree/device-tree.c | 91 +++++++++++++++++++++++++++
62
xen/include/xen/device_tree.h | 25 +++++
95
xen/drivers/passthrough/device_tree.c | 42 +++++++++++++
63
xen/include/xen/iommu.h | 22 ++++-
96
xen/include/xen/device_tree.h | 23 +++++++
64
3 files changed, 180 insertions(+), 1 deletion(-)
97
xen/include/xen/iommu.h | 28 ++++++++-
65
98
4 files changed, 183 insertions(+), 1 deletion(-)
99
100
diff --git a/xen/common/device-tree/device-tree.c b/xen/common/device-tree/device-tree.c
101
index XXXXXXX..XXXXXXX 100644
102
--- a/xen/common/device-tree/device-tree.c
103
+++ b/xen/common/device-tree/device-tree.c
104
@@ -XXX,XX +XXX,XX @@
105
* published by the Free Software Foundation.
106
*/
107
108
+#include <xen/bitops.h>
109
#include <xen/types.h>
110
#include <xen/init.h>
111
#include <xen/guest_access.h>
112
@@ -XXX,XX +XXX,XX @@ int dt_get_pci_domain_nr(struct dt_device_node *node)
113
return (u16)domain;
114
}
115
116
+int dt_map_id(const struct dt_device_node *np, uint32_t id,
117
+ const char *map_name, const char *map_mask_name,
118
+ struct dt_device_node **target, uint32_t *id_out)
119
+{
120
+ uint32_t map_mask, masked_id, map_len;
121
+ const __be32 *map = NULL;
122
+
123
+ if ( !np || !map_name || (!target && !id_out) )
124
+ return -EINVAL;
125
+
126
+ map = dt_get_property(np, map_name, &map_len);
127
+ if ( !map )
128
+ {
129
+ if ( target )
130
+ return -ENODEV;
131
+
132
+ /* Otherwise, no map implies no translation */
133
+ *id_out = id;
134
+ return 0;
135
+ }
136
+
137
+ if ( !map_len || (map_len % (4 * sizeof(*map))) )
138
+ {
139
+ printk(XENLOG_ERR "%s(): %s: Error: Bad %s length: %u\n", __func__,
140
+ np->full_name, map_name, map_len);
141
+ return -EINVAL;
142
+ }
143
+
144
+ /* The default is to select all bits. */
145
+ map_mask = GENMASK(31, 0);
146
+
147
+ /*
148
+ * Can be overridden by "{iommu,msi}-map-mask" property.
149
+ * If dt_property_read_u32() fails, the default is used.
150
+ */
151
+ if ( map_mask_name )
152
+ dt_property_read_u32(np, map_mask_name, &map_mask);
153
+
154
+ masked_id = map_mask & id;
155
+ for ( ; map_len > 0; map_len -= 4 * sizeof(*map), map += 4 )
156
+ {
157
+ struct dt_device_node *phandle_node;
158
+ uint32_t id_base = be32_to_cpup(map + 0);
159
+ uint32_t phandle = be32_to_cpup(map + 1);
160
+ uint32_t out_base = be32_to_cpup(map + 2);
161
+ uint32_t id_len = be32_to_cpup(map + 3);
162
+
163
+ if ( id_base & ~map_mask )
164
+ {
165
+ printk(XENLOG_ERR "%s(): %s: Invalid %s translation - %s-mask (0x%"PRIx32") ignores id-base (0x%"PRIx32")\n",
166
+ __func__, np->full_name, map_name, map_name, map_mask,
167
+ id_base);
168
+ return -EFAULT;
169
+ }
170
+
171
+ if ( (masked_id < id_base) || (masked_id >= (id_base + id_len)) )
172
+ continue;
173
+
174
+ phandle_node = dt_find_node_by_phandle(phandle);
175
+ if ( !phandle_node )
176
+ return -ENODEV;
177
+
178
+ if ( target )
179
+ {
180
+ if ( !*target )
181
+ *target = phandle_node;
182
+
183
+ if ( *target != phandle_node )
184
+ continue;
185
+ }
186
+
187
+ if ( id_out )
188
+ *id_out = masked_id - id_base + out_base;
189
+
190
+ dprintk(XENLOG_DEBUG, "%s: %s, using mask %08"PRIx32", id-base: %08"PRIx32", out-base: %08"PRIx32", length: %08"PRIx32", id: %08"PRIx32" -> %08"PRIx32"\n",
191
+ np->full_name, map_name, map_mask, id_base, out_base, id_len, id,
192
+ masked_id - id_base + out_base);
193
+ return 0;
194
+ }
195
+
196
+ dprintk(XENLOG_DEBUG, "%s: no %s translation for id 0x%"PRIx32" on %s\n",
197
+ np->full_name, map_name, id,
198
+ (target && *target) ? (*target)->full_name : NULL);
199
+
200
+ if ( id_out )
201
+ *id_out = id;
202
+
203
+ return 0;
204
+}
205
+
206
/*
207
* Local variables:
208
* mode: C
66
diff --git a/xen/drivers/passthrough/device_tree.c b/xen/drivers/passthrough/device_tree.c
209
diff --git a/xen/drivers/passthrough/device_tree.c b/xen/drivers/passthrough/device_tree.c
67
index XXXXXXX..XXXXXXX 100644
210
index XXXXXXX..XXXXXXX 100644
68
--- a/xen/drivers/passthrough/device_tree.c
211
--- a/xen/drivers/passthrough/device_tree.c
69
+++ b/xen/drivers/passthrough/device_tree.c
212
+++ b/xen/drivers/passthrough/device_tree.c
70
@@ -XXX,XX +XXX,XX @@ static int iommu_dt_xlate(struct device *dev,
213
@@ -XXX,XX +XXX,XX @@ static int iommu_dt_xlate(struct device *dev,
71
return ops->dt_xlate(dev, iommu_spec);
214
return ops->dt_xlate(dev, iommu_spec);
72
}
215
}
73
216
74
+#ifdef CONFIG_HAS_PCI
217
+#ifdef CONFIG_HAS_PCI
75
+int dt_map_id(const struct dt_device_node *np, uint32_t id,
76
+ const char *map_name, const char *map_mask_name,
77
+ struct dt_device_node **target, uint32_t *id_out)
78
+{
79
+ uint32_t map_mask, masked_id, map_len;
80
+ const __be32 *map = NULL;
81
+
82
+ if ( !np || !map_name || (!target && !id_out) )
83
+ return -EINVAL;
84
+
85
+ map = dt_get_property(np, map_name, &map_len);
86
+ if ( !map )
87
+ {
88
+ if ( target )
89
+ return -ENODEV;
90
+
91
+ /* Otherwise, no map implies no translation */
92
+ *id_out = id;
93
+ return 0;
94
+ }
95
+
96
+ if ( !map_len || (map_len % (4 * sizeof(*map))) )
97
+ {
98
+ printk(XENLOG_ERR "%s: Error: Bad %s length: %u\n", np->full_name,
99
+ map_name, map_len);
100
+ return -EINVAL;
101
+ }
102
+
103
+ /* The default is to select all bits. */
104
+ map_mask = 0xffffffff;
105
+
106
+ /*
107
+ * Can be overridden by "{iommu,msi}-map-mask" property.
108
+ * If df_property_read_u32() fails, the default is used.
109
+ */
110
+ if ( map_mask_name )
111
+ dt_property_read_u32(np, map_mask_name, &map_mask);
112
+
113
+ masked_id = map_mask & id;
114
+ for ( ; (int)map_len > 0; map_len -= 4 * sizeof(*map), map += 4 )
115
+ {
116
+ struct dt_device_node *phandle_node;
117
+ uint32_t id_base = be32_to_cpup(map + 0);
118
+ uint32_t phandle = be32_to_cpup(map + 1);
119
+ uint32_t out_base = be32_to_cpup(map + 2);
120
+ uint32_t id_len = be32_to_cpup(map + 3);
121
+
122
+ if ( id_base & ~map_mask )
123
+ {
124
+ printk(XENLOG_ERR "%s: Invalid %s translation - %s-mask (0x%"PRIx32") ignores id-base (0x%"PRIx32")\n",
125
+ np->full_name, map_name, map_name, map_mask, id_base);
126
+ return -EFAULT;
127
+ }
128
+
129
+ if ( (masked_id < id_base) || (masked_id >= (id_base + id_len)) )
130
+ continue;
131
+
132
+ phandle_node = dt_find_node_by_phandle(phandle);
133
+ if ( !phandle_node )
134
+ return -ENODEV;
135
+
136
+ if ( target )
137
+ {
138
+ if ( !*target )
139
+ *target = phandle_node;
140
+
141
+ if ( *target != phandle_node )
142
+ continue;
143
+ }
144
+
145
+ if ( id_out )
146
+ *id_out = masked_id - id_base + out_base;
147
+
148
+ printk(XENLOG_DEBUG "%s: %s, using mask %08"PRIx32", id-base: %08"PRIx32", out-base: %08"PRIx32", length: %08"PRIx32", id: %08"PRIx32" -> %08"PRIx32"\n",
149
+ np->full_name, map_name, map_mask, id_base, out_base, id_len, id,
150
+ masked_id - id_base + out_base);
151
+ return 0;
152
+ }
153
+
154
+ printk(XENLOG_ERR "%s: no %s translation for id 0x%"PRIx32" on %s\n",
155
+ np->full_name, map_name, id, (target && *target) ? (*target)->full_name : NULL);
156
+
157
+ /*
158
+ * NOTE: Linux bypasses translation without returning an error here,
159
+ * but should we behave in the same way on Xen? Restrict for now.
160
+ */
161
+ return -EFAULT;
162
+}
163
+
164
+int iommu_add_dt_pci_sideband_ids(struct pci_dev *pdev)
218
+int iommu_add_dt_pci_sideband_ids(struct pci_dev *pdev)
165
+{
219
+{
166
+ const struct iommu_ops *ops = iommu_get_ops();
220
+ const struct iommu_ops *ops = iommu_get_ops();
167
+ struct dt_phandle_args iommu_spec = { .args_count = 1 };
221
+ struct dt_phandle_args iommu_spec = { .args_count = 1 };
168
+ struct device *dev = pci_to_dev(pdev);
222
+ struct device *dev = pci_to_dev(pdev);
169
+ const struct dt_device_node *np;
223
+ const struct dt_device_node *np;
170
+ int rc = NO_IOMMU;
224
+ int rc;
171
+
225
+
172
+ if ( !iommu_enabled )
226
+ if ( !iommu_enabled )
173
+ return NO_IOMMU;
227
+ return NO_IOMMU;
174
+
228
+
175
+ if ( !ops )
229
+ if ( !ops )
176
+ return -EINVAL;
230
+ return -EINVAL;
177
+
178
+ if ( device_is_protected(dev) )
179
+ return 0;
180
+
231
+
181
+ if ( dev_iommu_fwspec_get(dev) )
232
+ if ( dev_iommu_fwspec_get(dev) )
182
+ return -EEXIST;
233
+ return -EEXIST;
183
+
234
+
184
+ np = pci_find_host_bridge_node(pdev);
235
+ np = pci_find_host_bridge_node(pdev);
...
...
192
+ rc = dt_map_id(np, PCI_BDF(pdev->bus, pdev->devfn), "iommu-map",
243
+ rc = dt_map_id(np, PCI_BDF(pdev->bus, pdev->devfn), "iommu-map",
193
+ "iommu-map-mask", &iommu_spec.np, iommu_spec.args);
244
+ "iommu-map-mask", &iommu_spec.np, iommu_spec.args);
194
+ if ( rc )
245
+ if ( rc )
195
+ return (rc == -ENODEV) ? NO_IOMMU : rc;
246
+ return (rc == -ENODEV) ? NO_IOMMU : rc;
196
+
247
+
197
+ rc = iommu_dt_xlate(dev, &iommu_spec);
248
+ rc = iommu_dt_xlate(dev, &iommu_spec, ops);
198
+ if ( rc < 0 )
249
+ if ( rc < 0 )
199
+ {
250
+ {
200
+ iommu_fwspec_free(dev);
251
+ iommu_fwspec_free(dev);
201
+ return -EINVAL;
252
+ return -EINVAL;
202
+ }
253
+ }
203
+
254
+
204
+ return rc;
255
+ return rc;
205
+}
256
+}
206
+#endif /* CONFIG_HAS_PCI */
257
+#endif /* CONFIG_HAS_PCI */
207
+
258
+
208
int iommu_add_dt_device(struct dt_device_node *np)
259
int iommu_remove_dt_device(struct dt_device_node *np)
209
{
260
{
210
const struct iommu_ops *ops = iommu_get_ops();
261
const struct iommu_ops *ops = iommu_get_ops();
211
diff --git a/xen/include/xen/device_tree.h b/xen/include/xen/device_tree.h
262
diff --git a/xen/include/xen/device_tree.h b/xen/include/xen/device_tree.h
212
index XXXXXXX..XXXXXXX 100644
263
index XXXXXXX..XXXXXXX 100644
213
--- a/xen/include/xen/device_tree.h
264
--- a/xen/include/xen/device_tree.h
214
+++ b/xen/include/xen/device_tree.h
265
+++ b/xen/include/xen/device_tree.h
215
@@ -XXX,XX +XXX,XX @@ int dt_count_phandle_with_args(const struct dt_device_node *np,
266
@@ -XXX,XX +XXX,XX @@ int dt_count_phandle_with_args(const struct dt_device_node *np,
216
*/
267
*/
217
int dt_get_pci_domain_nr(struct dt_device_node *node);
268
int dt_get_pci_domain_nr(struct dt_device_node *node);
218
269
219
+#ifdef CONFIG_HAS_PCI
220
+/**
270
+/**
221
+ * dt_map_id - Translate an ID through a downstream mapping.
271
+ * dt_map_id - Translate an ID through a downstream mapping.
222
+ * @np: root complex device node.
272
+ * @np: root complex device node.
223
+ * @id: device ID to map.
273
+ * @id: device ID to map.
224
+ * @map_name: property name of the map to use.
274
+ * @map_name: property name of the map to use.
...
...
237
+ * Return: 0 on success or a standard error code on failure.
287
+ * Return: 0 on success or a standard error code on failure.
238
+ */
288
+ */
239
+int dt_map_id(const struct dt_device_node *np, uint32_t id,
289
+int dt_map_id(const struct dt_device_node *np, uint32_t id,
240
+ const char *map_name, const char *map_mask_name,
290
+ const char *map_name, const char *map_mask_name,
241
+ struct dt_device_node **target, uint32_t *id_out);
291
+ struct dt_device_node **target, uint32_t *id_out);
242
+#endif /* CONFIG_HAS_PCI */
243
+
292
+
244
struct dt_device_node *dt_find_node_by_phandle(dt_phandle handle);
293
struct dt_device_node *dt_find_node_by_phandle(dt_phandle handle);
245
294
246
#ifdef CONFIG_DEVICE_TREE_DEBUG
295
#ifdef CONFIG_DEVICE_TREE_DEBUG
247
diff --git a/xen/include/xen/iommu.h b/xen/include/xen/iommu.h
296
diff --git a/xen/include/xen/iommu.h b/xen/include/xen/iommu.h
248
index XXXXXXX..XXXXXXX 100644
297
index XXXXXXX..XXXXXXX 100644
249
--- a/xen/include/xen/iommu.h
298
--- a/xen/include/xen/iommu.h
250
+++ b/xen/include/xen/iommu.h
299
+++ b/xen/include/xen/iommu.h
251
@@ -XXX,XX +XXX,XX @@
300
@@ -XXX,XX +XXX,XX @@
252
#include <xen/spinlock.h>
301
#include <xen/errno.h>
253
#include <public/domctl.h>
302
#include <public/domctl.h>
254
#include <public/hvm/ioreq.h>
303
#include <public/hvm/ioreq.h>
255
+#ifdef CONFIG_ACPI
304
+#include <xen/acpi.h>
256
+#include <asm/acpi.h>
257
+#endif
258
#include <asm/device.h>
305
#include <asm/device.h>
259
306
260
TYPE_SAFE(uint64_t, dfn);
307
TYPE_SAFE(uint64_t, dfn);
261
@@ -XXX,XX +XXX,XX @@ int iommu_dt_domain_init(struct domain *d);
308
@@ -XXX,XX +XXX,XX @@ int iommu_dt_domain_init(struct domain *d);
262
int iommu_release_dt_devices(struct domain *d);
309
int iommu_release_dt_devices(struct domain *d);
...
...
272
* (IOMMU is not enabled/present or device is not connected to it).
319
* (IOMMU is not enabled/present or device is not connected to it).
273
*/
320
*/
274
int iommu_add_dt_device(struct dt_device_node *np);
321
int iommu_add_dt_device(struct dt_device_node *np);
275
+int iommu_add_dt_pci_sideband_ids(struct pci_dev *pdev);
322
+int iommu_add_dt_pci_sideband_ids(struct pci_dev *pdev);
276
323
277
int iommu_do_dt_domctl(struct xen_domctl *, struct domain *,
324
int iommu_do_dt_domctl(struct xen_domctl *domctl, struct domain *d,
278
XEN_GUEST_HANDLE_PARAM(xen_domctl_t));
325
XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl);
326
@@ -XXX,XX +XXX,XX @@ int iommu_remove_dt_device(struct dt_device_node *np);
327
/* Error code for reporting no IOMMU is present */
328
#define NO_IOMMU 1
279
329
280
+#else /* !HAS_DEVICE_TREE */
330
+#else /* !HAS_DEVICE_TREE */
281
+static inline int iommu_add_dt_pci_sideband_ids(struct pci_dev *pdev)
331
+static inline int iommu_add_dt_pci_sideband_ids(struct pci_dev *pdev)
282
+{
332
+{
283
+ return 0;
333
+ return -ENOSYS;
284
+}
334
+}
335
+
285
#endif /* HAS_DEVICE_TREE */
336
#endif /* HAS_DEVICE_TREE */
286
337
338
+#ifdef CONFIG_HAS_PCI
287
+static inline int iommu_add_pci_sideband_ids(struct pci_dev *pdev)
339
+static inline int iommu_add_pci_sideband_ids(struct pci_dev *pdev)
288
+{
340
+{
289
+ int ret = 0;
341
+ int ret = -ENOSYS;
290
+#ifdef CONFIG_ACPI
342
+
291
+ if ( acpi_disabled )
343
+ if ( acpi_disabled )
344
+ ret = iommu_add_dt_pci_sideband_ids(pdev);
345
+
346
+ return ret;
347
+}
348
+#else /* !HAS_PCI */
349
+static inline int iommu_add_pci_sideband_ids(struct pci_dev *pdev)
350
+{
351
+ return -ENOSYS;
352
+}
292
+#endif
353
+#endif
293
+ ret = iommu_add_dt_pci_sideband_ids(pdev);
294
+ return ret;
295
+}
296
+
354
+
297
struct page_info;
355
struct page_info;
298
356
299
/*
357
/*
300
--
358
--
301
2.40.1
359
2.34.1
diff view generated by jsdifflib
1
From: Stewart Hildebrand <stewart.hildebrand@amd.com>
2
1
Handle phantom functions in iommu_add_dt_pci_sideband_ids(). Each phantom
3
Handle phantom functions in iommu_add_dt_pci_sideband_ids(). Each phantom
2
function will have a unique requestor ID (RID)/BDF. On ARM, we need to
4
function will have a unique requestor ID (RID)/BDF. On ARM, we need to
3
map/translate the RID/BDF to an AXI stream ID for each phantom function
5
map/translate the RID/BDF to an AXI stream ID for each phantom function
4
according to the pci-iommu device tree mapping [1]. The RID/BDF -> AXI stream ID
6
according to the pci-iommu device tree mapping [1]. The RID/BDF -> AXI stream ID
5
mapping in DT could allow phantom devices (i.e. devices with phantom functions)
7
mapping in DT could allow phantom devices (i.e. devices with phantom functions)
6
to use different AXI stream IDs based on the (phantom) function.
8
to use different AXI stream IDs based on the (phantom) function.
7
9
8
[1] https://www.kernel.org/doc/Documentation/devicetree/bindings/pci/pci-iommu.txt
10
[1] https://www.kernel.org/doc/Documentation/devicetree/bindings/pci/pci-iommu.txt
9
11
10
Signed-off-by: Stewart Hildebrand <stewart.hildebrand@amd.com>
12
Signed-off-by: Stewart Hildebrand <stewart.hildebrand@amd.com>
11
---
13
---
14
v6->v7:
15
* no change
16
17
v5->v6:
18
* no change
19
20
v4->v5:
21
* no change
22
12
v3->v4:
23
v3->v4:
13
* s/iommu_dt_pci_map_id/dt_map_id/
24
* s/iommu_dt_pci_map_id/dt_map_id/
14
25
15
v2->v3:
26
v2->v3:
16
* new patch title (was: iommu/arm: iommu_add_dt_pci_device phantom handling)
27
* new patch title (was: iommu/arm: iommu_add_dt_pci_device phantom handling)
17
* rework loop to reduce duplication
28
* rework loop to reduce duplication
18
* s/iommu_fwspec_free(pci_to_dev(pdev))/iommu_fwspec_free(dev)/
29
* s/iommu_fwspec_free(pci_to_dev(pdev))/iommu_fwspec_free(dev)/
19
30
20
v1->v2:
31
v1->v2:
21
* new patch
32
* new patch
33
34
---
35
TODO: investigate Jan's comment [2]
36
[2] https://lore.kernel.org/xen-devel/806a2978-19fb-4d31-ab6a-35ea7317c8de@suse.com/
22
---
37
---
23
xen/drivers/passthrough/device_tree.c | 33 ++++++++++++++++-----------
38
xen/drivers/passthrough/device_tree.c | 33 ++++++++++++++++-----------
24
1 file changed, 20 insertions(+), 13 deletions(-)
39
1 file changed, 20 insertions(+), 13 deletions(-)
25
40
26
diff --git a/xen/drivers/passthrough/device_tree.c b/xen/drivers/passthrough/device_tree.c
41
diff --git a/xen/drivers/passthrough/device_tree.c b/xen/drivers/passthrough/device_tree.c
27
index XXXXXXX..XXXXXXX 100644
42
index XXXXXXX..XXXXXXX 100644
28
--- a/xen/drivers/passthrough/device_tree.c
43
--- a/xen/drivers/passthrough/device_tree.c
29
+++ b/xen/drivers/passthrough/device_tree.c
44
+++ b/xen/drivers/passthrough/device_tree.c
30
@@ -XXX,XX +XXX,XX @@ int iommu_add_dt_pci_sideband_ids(struct pci_dev *pdev)
45
@@ -XXX,XX +XXX,XX @@ int iommu_add_dt_pci_sideband_ids(struct pci_dev *pdev)
31
struct device *dev = pci_to_dev(pdev);
46
struct device *dev = pci_to_dev(pdev);
32
const struct dt_device_node *np;
47
const struct dt_device_node *np;
33
int rc = NO_IOMMU;
48
int rc;
34
+ unsigned int devfn = pdev->devfn;
49
+ unsigned int devfn = pdev->devfn;
35
50
36
if ( !iommu_enabled )
51
if ( !iommu_enabled )
37
return NO_IOMMU;
52
return NO_IOMMU;
38
@@ -XXX,XX +XXX,XX @@ int iommu_add_dt_pci_sideband_ids(struct pci_dev *pdev)
53
@@ -XXX,XX +XXX,XX @@ int iommu_add_dt_pci_sideband_ids(struct pci_dev *pdev)
...
...
55
+ rc = dt_map_id(np, PCI_BDF(pdev->bus, devfn), "iommu-map",
70
+ rc = dt_map_id(np, PCI_BDF(pdev->bus, devfn), "iommu-map",
56
+ "iommu-map-mask", &iommu_spec.np, iommu_spec.args);
71
+ "iommu-map-mask", &iommu_spec.np, iommu_spec.args);
57
+ if ( rc )
72
+ if ( rc )
58
+ return (rc == -ENODEV) ? NO_IOMMU : rc;
73
+ return (rc == -ENODEV) ? NO_IOMMU : rc;
59
74
60
- rc = iommu_dt_xlate(dev, &iommu_spec);
75
- rc = iommu_dt_xlate(dev, &iommu_spec, ops);
61
- if ( rc < 0 )
76
- if ( rc < 0 )
62
- {
77
- {
63
- iommu_fwspec_free(dev);
78
- iommu_fwspec_free(dev);
64
- return -EINVAL;
79
- return -EINVAL;
65
+ rc = iommu_dt_xlate(dev, &iommu_spec);
80
+ rc = iommu_dt_xlate(dev, &iommu_spec, ops);
66
+ if ( rc < 0 )
81
+ if ( rc < 0 )
67
+ {
82
+ {
68
+ iommu_fwspec_free(dev);
83
+ iommu_fwspec_free(dev);
69
+ return -EINVAL;
84
+ return -EINVAL;
70
+ }
85
+ }
...
...
75
+ (PCI_SLOT(devfn) == PCI_SLOT(pdev->devfn)) );
90
+ (PCI_SLOT(devfn) == PCI_SLOT(pdev->devfn)) );
76
91
77
return rc;
92
return rc;
78
}
93
}
79
--
94
--
80
2.40.1
95
2.34.1
diff view generated by jsdifflib
1
From: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>
1
From: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>
2
3
Implement support for PCI devices in the SMMU driver. Make arm_smmu_master
4
structure to hold a pointer to the device to allow it to hold PCI devices.
5
Trigger iommu-map parsing when new PCI device is added. Add checks to
6
assign/deassign functions to ensure PCI devices are handled correctly.
7
Implement basic quarantining.
8
9
All pci devices are automatically assigned to hardware domain if it exists
10
to ensure it can probe them.
11
12
TODO:
13
Implement scratch page quarantining support.
2
14
3
Signed-off-by: Oleksandr Tyshchenko <oleksandr_tyshchenko@epam.com>
15
Signed-off-by: Oleksandr Tyshchenko <oleksandr_tyshchenko@epam.com>
4
Signed-off-by: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>
16
Signed-off-by: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>
5
Signed-off-by: Stewart Hildebrand <stewart.hildebrand@amd.com>
17
Signed-off-by: Stewart Hildebrand <stewart.hildebrand@amd.com>
18
Signed-off-by: Mykyta Poturai <mykyta_poturai@epam.com>
6
---
19
---
20
v6->v7:
21
* use d->pci_lock in arm_smmu_assign_dev()
22
* remove !is_hardware_domain and pdev->domain == d checks in assign to
23
support future dom0less use case when dom0 is using vPCI
24
* remove stale todo in dev_get_dev_node
25
* don't print ""
26
* remove redundant dt_device_is_protected check
27
* remove assign/deassing prints
28
* change assign logic to remove reassign reimplementation
29
* check if pdev->domain exists before assigning to it
30
* explain pdev->devfn check
31
* make reassign check stricter and update comment
32
33
v5->v6:
34
* check for hardware_domain == NULL (dom0less test case)
35
* locking: assign pdev->domain before list_add()
36
37
v4->v5:
38
* assign device to pdev->domain (usually dom0) by default in add_device() hook
39
* deassign from hwdom
40
* rebase on top of ("dynamic node programming using overlay dtbo") series
41
* remove TODO in comment about device prints
42
* add TODO regarding locking
43
* fixup after dropping ("xen/arm: Move is_protected flag to struct device")
44
7
v3->v4:
45
v3->v4:
8
* add new device_is_protected check in add_device hook to match SMMUv3 and
46
* add new device_is_protected check in add_device hook to match SMMUv3 and
9
IPMMU-VMSA drivers
47
IPMMU-VMSA drivers
10
48
11
v2->v3:
49
v2->v3:
...
...
27
65
28
(cherry picked from commit 0c11a7f65f044c26d87d1e27ac6283ef1f9cfb7a from
66
(cherry picked from commit 0c11a7f65f044c26d87d1e27ac6283ef1f9cfb7a from
29
the downstream branch spider-master from
67
the downstream branch spider-master from
30
https://github.com/xen-troops/xen.git)
68
https://github.com/xen-troops/xen.git)
31
---
69
---
32
70
xen/drivers/passthrough/arm/smmu.c | 190 ++++++++++++++++++++++-------
33
This is a file imported from Linux with modifications for Xen. What should be
71
1 file changed, 147 insertions(+), 43 deletions(-)
34
the coding style for Xen modifications?
35
---
36
xen/drivers/passthrough/arm/smmu.c | 120 ++++++++++++++++++++++++-----
37
1 file changed, 99 insertions(+), 21 deletions(-)
38
72
39
diff --git a/xen/drivers/passthrough/arm/smmu.c b/xen/drivers/passthrough/arm/smmu.c
73
diff --git a/xen/drivers/passthrough/arm/smmu.c b/xen/drivers/passthrough/arm/smmu.c
40
index XXXXXXX..XXXXXXX 100644
74
index XXXXXXX..XXXXXXX 100644
41
--- a/xen/drivers/passthrough/arm/smmu.c
75
--- a/xen/drivers/passthrough/arm/smmu.c
42
+++ b/xen/drivers/passthrough/arm/smmu.c
76
+++ b/xen/drivers/passthrough/arm/smmu.c
43
@@ -XXX,XX +XXX,XX @@ typedef enum irqreturn irqreturn_t;
77
@@ -XXX,XX +XXX,XX @@ enum irqreturn {
44
/* Device logger functions
78
45
* TODO: Handle PCI
79
typedef enum irqreturn irqreturn_t;
46
*/
80
81
-/* Device logger functions
82
- * TODO: Handle PCI
83
- */
47
-#define dev_print(dev, lvl, fmt, ...)                        \
84
-#define dev_print(dev, lvl, fmt, ...)                        \
48
-     printk(lvl "smmu: %s: " fmt, dt_node_full_name(dev_to_dt(dev)), ## __VA_ARGS__)
85
-     printk(lvl "smmu: %s: " fmt, dt_node_full_name(dev_to_dt(dev)), ## __VA_ARGS__)
86
+/* Device logger functions */
49
+#ifndef CONFIG_HAS_PCI
87
+#ifndef CONFIG_HAS_PCI
50
+#define dev_print(dev, lvl, fmt, ...) \
88
+#define dev_print(dev, lvl, fmt, ...) \
51
+ printk(lvl "smmu: %s: " fmt, dev_name(dev), ## __VA_ARGS__)
89
+ printk(lvl "smmu: %s: " fmt, dev_name(dev), ## __VA_ARGS__)
52
+#else
90
+#else
53
+#define dev_print(dev, lvl, fmt, ...) ({ \
91
+#define dev_print(dev, lvl, fmt, ...) ({ \
...
...
78
+#endif
116
+#endif
79
117
80
/* Xen: misc */
118
/* Xen: misc */
81
#define PHYS_MASK_SHIFT        PADDR_BITS
119
#define PHYS_MASK_SHIFT        PADDR_BITS
82
@@ -XXX,XX +XXX,XX @@ struct arm_smmu_master_cfg {
120
@@ -XXX,XX +XXX,XX @@ struct arm_smmu_master_cfg {
83
    for (i = 0; idx = cfg->smendx[i], i < num; ++i)
121
    for (i = 0; idx = (cfg)->smendx[i], (i) < (num); ++(i))
84
122
85
struct arm_smmu_master {
123
struct arm_smmu_master {
86
-    struct device_node        *of_node;
124
-    struct device_node        *of_node;
87
+    struct device            *dev;
125
+    struct device            *dev;
88
    struct rb_node            node;
126
    struct rb_node            node;
...
...
95
-    return dev_iommu_fwspec_get(&master->of_node->dev);
133
-    return dev_iommu_fwspec_get(&master->of_node->dev);
96
+    return dev_iommu_fwspec_get(master->dev);
134
+    return dev_iommu_fwspec_get(master->dev);
97
}
135
}
98
136
99
static void parse_driver_options(struct arm_smmu_device *smmu)
137
static void parse_driver_options(struct arm_smmu_device *smmu)
100
@@ -XXX,XX +XXX,XX @@ static struct device_node *dev_get_dev_node(struct device *dev)
138
@@ -XXX,XX +XXX,XX @@ static void parse_driver_options(struct arm_smmu_device *smmu)
101
}
139
140
static struct device_node *dev_get_dev_node(struct device *dev)
141
{
142
-#if 0 /* Xen: TODO: Add support for PCI */
143
-    if (dev_is_pci(dev)) {
144
-        struct pci_bus *bus = to_pci_dev(dev)->bus;
145
-
146
-        while (!pci_is_root_bus(bus))
147
-            bus = bus->parent;
148
-        return bus->bridge->parent->of_node;
149
-    }
150
-#endif
151
-
152
    return dev->of_node;
153
}
102
154
103
static struct arm_smmu_master *find_smmu_master(struct arm_smmu_device *smmu,
155
static struct arm_smmu_master *find_smmu_master(struct arm_smmu_device *smmu,
104
-                        struct device_node *dev_node)
156
-                        struct device_node *dev_node)
105
+                        struct device *dev)
157
+                        struct device *dev)
106
{
158
{
...
...
136
188
137
-    master = find_smmu_master(smmu, dev_node);
189
-    master = find_smmu_master(smmu, dev_node);
138
+    master = find_smmu_master(smmu, dev);
190
+    master = find_smmu_master(smmu, dev);
139
    if (master) {
191
    if (master) {
140
        dev_err(dev,
192
        dev_err(dev,
141
            "rejecting multiple registrations for master device %s\n",
193
-            "rejecting multiple registrations for master device %s\n",
142
-            dev_node->name);
194
-            dev_node->name);
143
+            dev_node ? dev_node->name : "");
195
+            "rejecting multiple registrations for master device\n");
144
        return -EBUSY;
196
        return -EBUSY;
145
    }
197
    }
146
198
147
    master = devm_kzalloc(dev, sizeof(*master), GFP_KERNEL);
199
    master = devm_kzalloc(dev, sizeof(*master), GFP_KERNEL);
148
    if (!master)
200
    if (!master)
149
        return -ENOMEM;
201
        return -ENOMEM;
150
-    master->of_node = dev_node;
202
-    master->of_node = dev_node;
151
+    master->dev = dev;
203
+    master->dev = dev;
152
+
204
153
+    if ( device_is_protected(dev) )
205
-    /* Xen: Let Xen know that the device is protected by an SMMU */
154
+    {
206
-    dt_device_set_protected(dev_node);
155
+        dev_err(dev, "Already added to SMMU\n");
207
+    if ( !dev_is_pci(dev) )
156
+        return -EEXIST;
208
+    {
209
+        /* Xen: Let Xen know that the device is protected by an SMMU */
210
+        dt_device_set_protected(dev_node);
157
+    }
211
+    }
158
212
159
    /* Xen: Let Xen know that the device is protected by an SMMU */
213
    for (i = 0; i < fwspec->num_ids; ++i) {
160
    device_set_protected(dev);
214
        if (!(smmu->features & ARM_SMMU_FEAT_STREAM_MATCH) &&
161
@@ -XXX,XX +XXX,XX @@ static int arm_smmu_dt_add_device_legacy(struct arm_smmu_device *smmu,
162
         (fwspec->ids[i] >= smmu->num_mapping_groups)) {
215
         (fwspec->ids[i] >= smmu->num_mapping_groups)) {
163
            dev_err(dev,
216
            dev_err(dev,
164
                "stream ID for master device %s greater than maximum allowed (%d)\n",
217
-                "stream ID for master device %s greater than maximum allowed (%d)\n",
165
-                dev_node->name, smmu->num_mapping_groups);
218
-                dev_node->name, smmu->num_mapping_groups);
166
+                dev_node ? dev_node->name : "", smmu->num_mapping_groups);
219
+                "SMMU stream ID %d is greater than maximum allowed (%d)\n",
220
+                fwspec->ids[i], smmu->num_mapping_groups);
167
            return -ERANGE;
221
            return -ERANGE;
168
        }
222
        }
169
        master->cfg.smendx[i] = INVALID_SMENDX;
223
        master->cfg.smendx[i] = INVALID_SMENDX;
224
@@ -XXX,XX +XXX,XX @@ static int arm_smmu_dt_remove_device_legacy(struct arm_smmu_device *smmu,
225
    struct device_node *dev_node = dev_get_dev_node(dev);
226
    int ret;
227
228
-    master = find_smmu_master(smmu, dev_node);
229
+    master = find_smmu_master(smmu, dev);
230
    if (master == NULL) {
231
        dev_err(dev,
232
            "No registrations found for master device %s\n",
233
@@ -XXX,XX +XXX,XX @@ static int arm_smmu_dt_remove_device_legacy(struct arm_smmu_device *smmu,
234
    if (ret)
235
        return ret;
236
237
-    /* Protected by dt_host_lock and dtdevs_lock as caller holds these locks. */
238
-    dev_node->is_protected = false;
239
+    if ( !dev_is_pci(dev) )
240
+        /* Protected by dt_host_lock and dtdevs_lock as caller holds these locks. */
241
+        dev_node->is_protected = false;
242
243
    kfree(master);
244
    return 0;
245
@@ -XXX,XX +XXX,XX @@ static int register_smmu_master(struct arm_smmu_device *smmu,
246
                     fwspec);
247
}
248
249
+/* Forward declaration */
250
+static int arm_smmu_assign_dev(struct domain *d, u8 devfn,
251
+             struct device *dev, u32 flag);
252
+static int arm_smmu_deassign_dev(struct domain *d, uint8_t devfn,
253
+                 struct device *dev);
254
+
255
/*
256
* The driver which supports generic IOMMU DT bindings must have this
257
* callback implemented.
170
@@ -XXX,XX +XXX,XX @@ static int arm_smmu_dt_add_device_generic(u8 devfn, struct device *dev)
258
@@ -XXX,XX +XXX,XX @@ static int arm_smmu_dt_add_device_generic(u8 devfn, struct device *dev)
259
{
171
    struct arm_smmu_device *smmu;
260
    struct arm_smmu_device *smmu;
172
    struct iommu_fwspec *fwspec;
261
    struct iommu_fwspec *fwspec;
173
262
+    int ret;
263
+
174
+#ifdef CONFIG_HAS_PCI
264
+#ifdef CONFIG_HAS_PCI
175
+    if ( dev_is_pci(dev) )
265
+    if ( dev_is_pci(dev) )
176
+    {
266
+    {
177
+        struct pci_dev *pdev = dev_to_pci(dev);
267
+        struct pci_dev *pdev = dev_to_pci(dev);
178
+        int ret;
268
+        int ret;
179
+
269
+
270
+        /* Ignore calls for phantom functions */
180
+        if ( devfn != pdev->devfn )
271
+        if ( devfn != pdev->devfn )
181
+            return 0;
272
+            return 0;
182
+
273
+
183
+        ret = iommu_add_pci_sideband_ids(pdev);
274
+        ret = iommu_add_pci_sideband_ids(pdev);
184
+        if ( ret < 0 )
275
+        if ( ret < 0 )
185
+            iommu_fwspec_free(dev);
276
+            iommu_fwspec_free(dev);
186
+    }
277
+    }
187
+#endif
278
+#endif
188
+
279
189
    fwspec = dev_iommu_fwspec_get(dev);
280
    fwspec = dev_iommu_fwspec_get(dev);
190
    if (fwspec == NULL)
281
    if (fwspec == NULL)
282
@@ -XXX,XX +XXX,XX @@ static int arm_smmu_dt_add_device_generic(u8 devfn, struct device *dev)
283
    if (smmu == NULL)
191
        return -ENXIO;
284
        return -ENXIO;
285
286
-    return arm_smmu_dt_add_device_legacy(smmu, dev, fwspec);
287
+    ret = arm_smmu_dt_add_device_legacy(smmu, dev, fwspec);
288
+    if ( ret )
289
+        return ret;
290
+
291
+#ifdef CONFIG_HAS_PCI
292
+    if ( dev_is_pci(dev) )
293
+    {
294
+        struct pci_dev *pdev = dev_to_pci(dev);
295
+
296
+        /*
297
+         * During PHYSDEVOP_pci_device_add, Xen does not assign the
298
+         * device, so we must do it here.
299
+         */
300
+        if ( pdev->domain )
301
+            ret = arm_smmu_assign_dev(pdev->domain, devfn, dev, 0);
302
+    }
303
+#endif
304
+
305
+    return ret;
306
}
307
308
static int arm_smmu_dt_xlate_generic(struct device *dev,
192
@@ -XXX,XX +XXX,XX @@ static struct arm_smmu_device *find_smmu_for_device(struct device *dev)
309
@@ -XXX,XX +XXX,XX @@ static struct arm_smmu_device *find_smmu_for_device(struct device *dev)
193
{
310
{
194
    struct arm_smmu_device *smmu;
311
    struct arm_smmu_device *smmu;
195
    struct arm_smmu_master *master = NULL;
312
    struct arm_smmu_master *master = NULL;
196
-    struct device_node *dev_node = dev_get_dev_node(dev);
313
-    struct device_node *dev_node = dev_get_dev_node(dev);
...
...
219
static int arm_smmu_add_device(struct device *dev)
336
static int arm_smmu_add_device(struct device *dev)
220
{
337
{
221
@@ -XXX,XX +XXX,XX @@ static int arm_smmu_add_device(struct device *dev)
338
@@ -XXX,XX +XXX,XX @@ static int arm_smmu_add_device(struct device *dev)
222
    struct arm_smmu_master_cfg *cfg;
339
    struct arm_smmu_master_cfg *cfg;
223
    struct iommu_group *group;
340
    struct iommu_group *group;
224
    void (*releasefn)(void *) = NULL;
341
    void (*releasefn)(void *data) = NULL;
225
-    int ret;
342
-    int ret;
226
343
227
    smmu = find_smmu_for_device(dev);
344
    smmu = find_smmu_for_device(dev);
228
    if (!smmu)
345
    if (!smmu)
229
        return -ENODEV;
346
        return -ENODEV;
...
...
251
@@ -XXX,XX +XXX,XX @@ static int arm_smmu_assign_dev(struct domain *d, u8 devfn,
368
@@ -XXX,XX +XXX,XX @@ static int arm_smmu_assign_dev(struct domain *d, u8 devfn,
252
            return -ENOMEM;
369
            return -ENOMEM;
253
    }
370
    }
254
371
255
+#ifdef CONFIG_HAS_PCI
372
+#ifdef CONFIG_HAS_PCI
256
+    if ( dev_is_pci(dev) && !is_hardware_domain(d) )
373
+    if ( dev_is_pci(dev) )
257
+    {
374
+    {
258
+        struct pci_dev *pdev = dev_to_pci(dev);
375
+        struct pci_dev *pdev = dev_to_pci(dev);
259
+
376
+
260
+        printk(XENLOG_INFO "Assigning device %04x:%02x:%02x.%u to dom%d\n",
377
+        /* Ignore calls for phantom functions */
261
+         pdev->seg, pdev->bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
378
+        if ( devfn != pdev->devfn )
262
+         d->domain_id);
263
+
264
+        if ( devfn != pdev->devfn || pdev->domain == d )
265
+            return 0;
379
+            return 0;
266
+
380
+
267
+        list_move(&pdev->domain_list, &d->pdev_list);
381
+        ASSERT(pcidevs_locked());
382
+
383
+        write_lock(&pdev->domain->pci_lock);
384
+        list_del(&pdev->domain_list);
385
+        write_unlock(&pdev->domain->pci_lock);
386
+
268
+        pdev->domain = d;
387
+        pdev->domain = d;
388
+
389
+        write_lock(&d->pci_lock);
390
+        list_add(&pdev->domain_list, &d->pdev_list);
391
+        write_unlock(&d->pci_lock);
269
+
392
+
270
+        /* dom_io is used as a sentinel for quarantined devices */
393
+        /* dom_io is used as a sentinel for quarantined devices */
271
+        if ( d == dom_io )
394
+        if ( d == dom_io )
395
+        {
396
+            struct iommu_domain *domain = dev_iommu_domain(dev);
397
+            if ( !iommu_quarantine )
398
+                return 0;
399
+
400
+            if ( domain && domain->priv )
401
+                arm_smmu_deassign_dev(domain->priv->cfg.domain, devfn, dev);
402
+
272
+            return 0;
403
+            return 0;
404
+        }
273
+    }
405
+    }
274
+#endif
406
+#endif
275
+
407
+
276
    if (!dev_iommu_group(dev)) {
408
    if (!dev_iommu_group(dev)) {
277
        ret = arm_smmu_add_device(dev);
409
        ret = arm_smmu_add_device(dev);
278
        if (ret)
410
        if (ret)
279
@@ -XXX,XX +XXX,XX @@ out:
411
@@ -XXX,XX +XXX,XX @@ out:
280
    return ret;
412
    return ret;
281
}
413
}
282
414
283
-static int arm_smmu_deassign_dev(struct domain *d, struct device *dev)
415
-static int arm_smmu_deassign_dev(struct domain *d, struct device *dev)
284
+static int arm_smmu_deassign_dev(struct domain *d, u8 devfn, struct device *dev)
416
+static int arm_smmu_deassign_dev(struct domain *d, uint8_t devfn,
417
+                 struct device *dev)
285
{
418
{
286
    struct iommu_domain *domain = dev_iommu_domain(dev);
419
    struct iommu_domain *domain = dev_iommu_domain(dev);
287
    struct arm_smmu_xen_domain *xen_domain;
420
    struct arm_smmu_xen_domain *xen_domain;
288
421
289
+#ifdef CONFIG_HAS_PCI
422
+#ifdef CONFIG_HAS_PCI
290
+    if ( dev_is_pci(dev) )
423
+    if ( dev_is_pci(dev) )
291
+    {
424
+    {
292
+        struct pci_dev *pdev = dev_to_pci(dev);
425
+        struct pci_dev *pdev = dev_to_pci(dev);
293
+
426
+
294
+        printk(XENLOG_INFO "Deassigning device %04x:%02x:%02x.%u from dom%d\n",
427
+        /* Ignore calls for phantom functions */
295
+         pdev->seg, pdev->bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
296
+         d->domain_id);
297
+
298
+        if ( devfn != pdev->devfn )
428
+        if ( devfn != pdev->devfn )
299
+            return 0;
429
+            return 0;
300
+
430
+
301
+        /* dom_io is used as a sentinel for quarantined devices */
431
+        /* dom_io is used as a sentinel for quarantined devices */
302
+        if ( d == dom_io )
432
+        if ( d == dom_io )
...
...
306
+
436
+
307
    xen_domain = dom_iommu(d)->arch.priv;
437
    xen_domain = dom_iommu(d)->arch.priv;
308
438
309
    if (!domain || domain->priv->cfg.domain != d) {
439
    if (!domain || domain->priv->cfg.domain != d) {
310
@@ -XXX,XX +XXX,XX @@ static int arm_smmu_reassign_dev(struct domain *s, struct domain *t,
440
@@ -XXX,XX +XXX,XX @@ static int arm_smmu_reassign_dev(struct domain *s, struct domain *t,
441
{
311
    int ret = 0;
442
    int ret = 0;
312
443
313
    /* Don't allow remapping on other domain than hwdom */
444
-    /* Don't allow remapping on other domain than hwdom */
314
-    if ( t && !is_hardware_domain(t) )
445
-    if ( t && !is_hardware_domain(t) )
315
+    if ( t && !is_hardware_domain(t) && t != dom_io )
446
+    /* Don't allow remapping on other domain than hwdom
447
+     * or dom_io for PCI devices
448
+     */
449
+    if ( t && !is_hardware_domain(t) && (t != dom_io || !dev_is_pci(dev)) )
316
        return -EPERM;
450
        return -EPERM;
317
451
318
    if (t == s)
452
    if (t == s)
319
        return 0;
453
        return 0;
320
454
321
-    ret = arm_smmu_deassign_dev(s, dev);
455
-    ret = arm_smmu_deassign_dev(s, dev);
322
+    ret = arm_smmu_deassign_dev(s, devfn, dev);
456
+    ret = arm_smmu_deassign_dev(s, devfn, dev);
323
    if (ret)
457
    if (ret)
324
        return ret;
458
        return ret;
325
459
326
--
460
--
327
2.40.1
461
2.34.1
diff view generated by jsdifflib
1
From: Rahul Singh <rahul.singh@arm.com>
1
From: Rahul Singh <rahul.singh@arm.com>
2
3
Implement support for PCI devices in the SMMU driver. Trigger iommu-map
4
parsing when new PCI device is added. Add checks to assign/deassign
5
functions to ensure PCI devices are handled correctly. Implement basic
6
quarantining.
7
8
All pci devices are automatically assigned to hardware domain if it exists
9
to ensure it can probe them.
10
11
TODO:
12
Implement scratch page quarantining support.
2
13
3
Signed-off-by: Rahul Singh <rahul.singh@arm.com>
14
Signed-off-by: Rahul Singh <rahul.singh@arm.com>
4
Signed-off-by: Stewart Hildebrand <stewart.hildebrand@amd.com>
15
Signed-off-by: Stewart Hildebrand <stewart.hildebrand@amd.com>
16
Signed-off-by: Mykyta Poturai <mykyta_poturai@epam.com>
5
---
17
---
18
v6->v7:
19
* address TODO: use d->pci_lock in arm_smmu_assign_dev()
20
* remove !is_hardware_domain and pdev->domain == d checks in assign to
21
support future dom0less use case when dom0 is using vPCI
22
* check if pdev->domain exists before assigning to it
23
* don't print ""
24
* change assign logic to remove reassign reimplementation
25
* explain pdev->devfn check
26
* make reassign check stricter and update comment
27
28
v5->v6:
29
* check for hardware_domain == NULL (dom0less test case)
30
* locking: assign pdev->domain before list_add()
31
32
v4->v5:
33
* deassign from hwdom
34
* add TODO regarding locking
35
* fixup after dropping ("xen/arm: Move is_protected flag to struct device")
36
6
v3->v4:
37
v3->v4:
7
* no change
38
* no change
8
39
9
v2->v3:
40
v2->v3:
10
* rebase
41
* rebase
...
...
27
58
28
(cherry picked from commit 7ed6c3ab250d899fe6e893a514278e406a2893e8 from
59
(cherry picked from commit 7ed6c3ab250d899fe6e893a514278e406a2893e8 from
29
the downstream branch poc/pci-passthrough from
60
the downstream branch poc/pci-passthrough from
30
https://gitlab.com/xen-project/people/bmarquis/xen-arm-poc.git)
61
https://gitlab.com/xen-project/people/bmarquis/xen-arm-poc.git)
31
---
62
---
32
63
xen/drivers/passthrough/arm/smmu-v3.c | 117 +++++++++++++++++++++++---
33
This is a file imported from Linux with modifications for Xen. What should be
64
1 file changed, 106 insertions(+), 11 deletions(-)
34
the coding style used for Xen modifications?
35
---
36
xen/drivers/passthrough/arm/smmu-v3.c | 76 +++++++++++++++++++++++++--
37
1 file changed, 72 insertions(+), 4 deletions(-)
38
65
39
diff --git a/xen/drivers/passthrough/arm/smmu-v3.c b/xen/drivers/passthrough/arm/smmu-v3.c
66
diff --git a/xen/drivers/passthrough/arm/smmu-v3.c b/xen/drivers/passthrough/arm/smmu-v3.c
40
index XXXXXXX..XXXXXXX 100644
67
index XXXXXXX..XXXXXXX 100644
41
--- a/xen/drivers/passthrough/arm/smmu-v3.c
68
--- a/xen/drivers/passthrough/arm/smmu-v3.c
42
+++ b/xen/drivers/passthrough/arm/smmu-v3.c
69
+++ b/xen/drivers/passthrough/arm/smmu-v3.c
43
@@ -XXX,XX +XXX,XX @@ static bool arm_smmu_sid_in_range(struct arm_smmu_device *smmu, u32 sid)
70
@@ -XXX,XX +XXX,XX @@ static bool arm_smmu_sid_in_range(struct arm_smmu_device *smmu, u32 sid)
44
}
71
}
45
/* Forward declaration */
72
/* Forward declaration */
46
static struct arm_smmu_device *arm_smmu_get_by_dev(const struct device *dev);
73
static struct arm_smmu_device *arm_smmu_get_by_dev(const struct device *dev);
47
+static int arm_smmu_assign_dev(struct domain *d, u8 devfn,
74
+static int arm_smmu_assign_dev(struct domain *d, u8 devfn, struct device *dev,
48
+            struct device *dev, u32 flag);
75
+             u32 flag);
76
+static int arm_smmu_deassign_dev(struct domain *d, uint8_t devfn,
77
+                 struct device *dev);
49
78
50
static int arm_smmu_add_device(u8 devfn, struct device *dev)
79
static int arm_smmu_add_device(u8 devfn, struct device *dev)
51
{
80
{
52
    int i, ret;
81
    int i, ret;
53
    struct arm_smmu_device *smmu;
82
    struct arm_smmu_device *smmu;
...
...
58
+#ifdef CONFIG_HAS_PCI
87
+#ifdef CONFIG_HAS_PCI
59
+    if ( dev_is_pci(dev) )
88
+    if ( dev_is_pci(dev) )
60
+    {
89
+    {
61
+        struct pci_dev *pdev = dev_to_pci(dev);
90
+        struct pci_dev *pdev = dev_to_pci(dev);
62
+        int ret;
91
+        int ret;
63
+
92
+                
93
+        /* Ignore calls for phantom functions */
64
+        if ( devfn != pdev->devfn )
94
+        if ( devfn != pdev->devfn )
65
+            return 0;
95
+            return 0;
66
+
96
+
67
+        ret = iommu_add_pci_sideband_ids(pdev);
97
+        ret = iommu_add_pci_sideband_ids(pdev);
68
+        if ( ret < 0 )
98
+        if ( ret < 0 )
...
...
73
+    fwspec = dev_iommu_fwspec_get(dev);
103
+    fwspec = dev_iommu_fwspec_get(dev);
74
    if (!fwspec)
104
    if (!fwspec)
75
        return -ENODEV;
105
        return -ENODEV;
76
106
77
@@ -XXX,XX +XXX,XX @@ static int arm_smmu_add_device(u8 devfn, struct device *dev)
107
@@ -XXX,XX +XXX,XX @@ static int arm_smmu_add_device(u8 devfn, struct device *dev)
108
     */
109
    arm_smmu_enable_pasid(master);
110
111
-    if (dt_device_is_protected(dev_to_dt(dev))) {
112
-        dev_err(dev, "Already added to SMMUv3\n");
113
-        return -EEXIST;
114
-    }
115
+    if ( !dev_is_pci(dev) )
116
+    {
117
+        if (dt_device_is_protected(dev_to_dt(dev))) {
118
+            dev_err(dev, "Already added to SMMUv3\n");
119
+            return -EEXIST;
120
+        }
121
122
-    /* Let Xen know that the master device is protected by an IOMMU. */
123
-    dt_device_set_protected(dev_to_dt(dev));
124
+        /* Let Xen know that the master device is protected by an IOMMU. */
125
+        dt_device_set_protected(dev_to_dt(dev));
126
+    }
127
78
    dev_info(dev, "Added master device (SMMUv3 %s StreamIds %u)\n",
128
    dev_info(dev, "Added master device (SMMUv3 %s StreamIds %u)\n",
79
            dev_name(fwspec->iommu_dev), fwspec->num_ids);
129
            dev_name(fwspec->iommu_dev), fwspec->num_ids);
80
130
81
+#ifdef CONFIG_HAS_PCI
131
+#ifdef CONFIG_HAS_PCI
82
+    if ( dev_is_pci(dev) )
132
+    if ( dev_is_pci(dev) )
83
+    {
133
+    {
84
+        struct pci_dev *pdev = dev_to_pci(dev);
134
+        struct pci_dev *pdev = dev_to_pci(dev);
85
+
135
+
86
+        ret = arm_smmu_assign_dev(pdev->domain, devfn, dev, 0);
136
+        /*
87
+        if (ret)
137
+         * During PHYSDEVOP_pci_device_add, Xen does not assign the
88
+            goto err_free_master;
138
+         * device, so we must do it here.
139
+         */
140
+        if ( pdev->domain )
141
+        {
142
+            ret = arm_smmu_assign_dev(pdev->domain, devfn, dev, 0);
143
+            if (ret)
144
+                goto err_free_master;
145
+        }
89
+    }
146
+    }
90
+#endif
147
+#endif
91
+
148
+
92
    return 0;
149
    return 0;
93
150
94
err_free_master:
151
err_free_master:
95
@@ -XXX,XX +XXX,XX @@ static int arm_smmu_assign_dev(struct domain *d, u8 devfn,
152
@@ -XXX,XX +XXX,XX @@ static int arm_smmu_assign_dev(struct domain *d, u8 devfn,
96
    struct arm_smmu_domain *smmu_domain;
153
    struct arm_smmu_domain *smmu_domain;
97
    struct arm_smmu_xen_domain *xen_domain = dom_iommu(d)->arch.priv;
154
    struct arm_smmu_xen_domain *xen_domain = dom_iommu(d)->arch.priv;
98
155
99
+#ifdef CONFIG_HAS_PCI
156
+#ifdef CONFIG_HAS_PCI
100
+    if ( dev_is_pci(dev) && !is_hardware_domain(d) )
157
+    if ( dev_is_pci(dev) )
101
+    {
158
+    {
102
+        struct pci_dev *pdev = dev_to_pci(dev);
159
+        struct pci_dev *pdev = dev_to_pci(dev);
103
+
160
+
104
+        printk(XENLOG_INFO "Assigning device %04x:%02x:%02x.%u to dom%d\n",
161
+        /* Ignore calls for phantom functions */
105
+            pdev->seg, pdev->bus, PCI_SLOT(devfn),
162
+        if ( devfn != pdev->devfn )
106
+            PCI_FUNC(devfn), d->domain_id);
163
+            return 0;
107
+
164
+
108
+        if ( devfn != pdev->devfn || pdev->domain == d )
165
+        ASSERT(pcidevs_locked());
109
+            return 0;
166
+
110
+
167
+        write_lock(&pdev->domain->pci_lock);
111
+        list_move(&pdev->domain_list, &d->pdev_list);
168
+        list_del(&pdev->domain_list);
169
+        write_unlock(&pdev->domain->pci_lock);
170
+
112
+        pdev->domain = d;
171
+        pdev->domain = d;
172
+
173
+        write_lock(&d->pci_lock);
174
+        list_add(&pdev->domain_list, &d->pdev_list);
175
+        write_unlock(&d->pci_lock);
113
+
176
+
114
+        /* dom_io is used as a sentinel for quarantined devices */
177
+        /* dom_io is used as a sentinel for quarantined devices */
115
+        if ( d == dom_io )
178
+        if ( d == dom_io )
116
+            return 0;
179
+        {
180
+            struct arm_smmu_master *master = dev_iommu_priv_get(dev);
181
+            if ( !iommu_quarantine )
182
+                return 0;
183
+
184
+            if ( master && master->domain )
185
+                arm_smmu_deassign_dev(master->domain->d, devfn, dev);
186
+
187
+            return 0;
188
+        }
117
+    }
189
+    }
118
+#endif
190
+#endif
119
+
191
+
120
    spin_lock(&xen_domain->lock);
192
    spin_lock(&xen_domain->lock);
121
193
...
...
136
+#ifdef CONFIG_HAS_PCI
208
+#ifdef CONFIG_HAS_PCI
137
+    if ( dev_is_pci(dev) )
209
+    if ( dev_is_pci(dev) )
138
+    {
210
+    {
139
+        struct pci_dev *pdev = dev_to_pci(dev);
211
+        struct pci_dev *pdev = dev_to_pci(dev);
140
+
212
+
141
+        printk(XENLOG_INFO "Deassigning device %04x:%02x:%02x.%u from dom%d\n",
213
+        /* Ignore calls for phantom functions */
142
+            pdev->seg, pdev->bus, PCI_SLOT(devfn),
143
+            PCI_FUNC(devfn), d->domain_id);
144
+
145
+        if ( devfn != pdev->devfn )
214
+        if ( devfn != pdev->devfn )
146
+            return 0;
215
+            return 0;
147
+
216
+
148
+        /* dom_io is used as a sentinel for quarantined devices */
217
+        /* dom_io is used as a sentinel for quarantined devices */
149
+        if ( d == dom_io )
218
+        if ( d == dom_io )
...
...
153
+
222
+
154
    spin_lock(&xen_domain->lock);
223
    spin_lock(&xen_domain->lock);
155
224
156
    arm_smmu_detach_dev(master);
225
    arm_smmu_detach_dev(master);
157
@@ -XXX,XX +XXX,XX @@ static int arm_smmu_reassign_dev(struct domain *s, struct domain *t,
226
@@ -XXX,XX +XXX,XX @@ static int arm_smmu_reassign_dev(struct domain *s, struct domain *t,
227
{
158
    int ret = 0;
228
    int ret = 0;
159
229
160
    /* Don't allow remapping on other domain than hwdom */
230
-    /* Don't allow remapping on other domain than hwdom */
161
-    if ( t && !is_hardware_domain(t) )
231
-    if ( t && !is_hardware_domain(t) )
162
+    if ( t && !is_hardware_domain(t) && (t != dom_io) )
232
+    /* Don't allow remapping on other domain than hwdom
233
+     * or dom_io for PCI devices
234
+     */
235
+    if ( t && !is_hardware_domain(t) && (t != dom_io || !dev_is_pci(dev)) )
163
        return -EPERM;
236
        return -EPERM;
164
237
165
    if (t == s)
238
    if (t == s)
166
        return 0;
239
        return 0;
167
240
168
-    ret = arm_smmu_deassign_dev(s, dev);
241
-    ret = arm_smmu_deassign_dev(s, dev);
169
+    ret = arm_smmu_deassign_dev(s, devfn, dev);
242
+    ret = arm_smmu_deassign_dev(s, devfn, dev);
170
    if (ret)
243
    if (ret)
171
        return ret;
244
        return ret;
172
245
173
--
246
--
174
2.40.1
247
2.34.1
diff view generated by jsdifflib
New patch
1
From: Rahul Singh <rahul.singh@arm.com>
1
2
3
Current code skip the mapping for PCI bridge MMIO region to dom0 when
4
pci_passthrough_enabled flag is set. Mapping should be skip when
5
has_vpci(d) is enabled for the domain, as we need to skip the mapping
6
only when VPCI handler are registered for ECAM.
7
8
Signed-off-by: Rahul Singh <rahul.singh@arm.com>
9
Signed-off-by: Stewart Hildebrand <stewart.hildebrand@amd.com>
10
Acked-by: Julien Grall <jgrall@amazon.com>
11
---
12
This patch was originally picked up from [1]
13
v6->v7:
14
* add Julien's A-b
15
16
v5->v6:
17
* drop unrelated change in xen/arch/arm/domain_build.c:handle_linux_pci_domain()
18
19
v4->v5:
20
* new patch
21
22
changes since picking up from [1]:
23
* rebase on top of "dynamic node programming using overlay dtbo" series
24
* replace !is_pci_passthrough_enabled() check with !IS_ENABLED(CONFIG_HAS_PCI)
25
instead of removing
26
27
[1] https://lists.xenproject.org/archives/html/xen-devel/2023-07/msg00483.html
28
---
29
xen/arch/arm/device.c | 2 +-
30
1 file changed, 1 insertion(+), 1 deletion(-)
31
32
diff --git a/xen/arch/arm/device.c b/xen/arch/arm/device.c
33
index XXXXXXX..XXXXXXX 100644
34
--- a/xen/arch/arm/device.c
35
+++ b/xen/arch/arm/device.c
36
@@ -XXX,XX +XXX,XX @@ int handle_device(struct domain *d, struct dt_device_node *dev, p2m_type_t p2mt,
37
.d = d,
38
.p2mt = p2mt,
39
.skip_mapping = !own_device ||
40
- (is_pci_passthrough_enabled() &&
41
+ (has_vpci(d) &&
42
(device_get_class(dev) == DEVICE_PCI_HOSTBRIDGE)),
43
.iomem_ranges = iomem_ranges,
44
.irq_ranges = irq_ranges
45
--
46
2.34.1
diff view generated by jsdifflib
1
From: Oleksandr Tyshchenko <oleksandr_tyshchenko@epam.com>
1
From: Stewart Hildebrand <stewart.hildebrand@amd.com>
2
2
3
This flag will be re-used for PCI devices by the subsequent
3
Enable the use of IOMMU + PCI in dom0 without having to specify
4
patches.
4
"pci-passthrough=yes". We rely on dom0 to initialize the PCI controller
5
and perform a PHYSDEVOP_pci_device_add call to add each device to SMMU.
5
6
6
Signed-off-by: Oleksandr Tyshchenko <oleksandr_tyshchenko@epam.com>
7
Enable pci_init() for initializing Xen's internal PCI subsystem, and
8
allow PHYSDEVOP_pci_device_add when pci-passthrough is disabled.
9
10
is_pci_passthrough_enabled() is not an Arm-only construct, so remove the
11
x86 definition of the function.
12
7
Signed-off-by: Stewart Hildebrand <stewart.hildebrand@amd.com>
13
Signed-off-by: Stewart Hildebrand <stewart.hildebrand@amd.com>
14
Signed-off-by: Mykyta Poturai <mykyta_poturai@epam.com>
8
---
15
---
9
v3->v4:
16
hmm. Since
10
* move is_protected flag within struct device to reduce padding
17
dec9e02f3190 ("xen: avoid generation of stub <asm/pci.h> header")
11
* re-add device_is_protected checks in add_device hooks in smmu-v3.c/ipmmu-vmsa.c
18
Should we also move is_pci_passthrough_enabled() back to xen/arch/arm/include/asm/pci.h ?
12
* split mmu-masters check into separate patch
19
Not sure if PPC/RISC-V will plan on using this check.
13
20
14
v2->v3:
21
v6->v7:
15
* no change
22
* remove x86 definition of is_pci_passthrough_enabled()
23
* update comments
24
* make pci_physdev_op checks stricter
16
25
17
v1->v2:
26
v5->v6:
18
* no change
27
* new patch - this effectively replaces
28
("Revert "xen/arm: Add cmdline boot option "pci-passthrough = <boolean>""")
29
---
30
xen/arch/arm/pci/pci.c | 5 +++--
31
xen/arch/x86/include/asm/pci.h | 6 ------
32
xen/drivers/pci/physdev.c | 4 ++--
33
3 files changed, 5 insertions(+), 10 deletions(-)
19
34
20
downstream->v1:
35
diff --git a/xen/arch/arm/pci/pci.c b/xen/arch/arm/pci/pci.c
21
* rebase
22
* s/dev_node->is_protected/dev_node->dev.is_protected/ in smmu.c
23
* s/dt_device_set_protected(dev_to_dt(dev))/device_set_protected(dev)/ in smmu-v3.c
24
* remove redundant device_is_protected checks in smmu-v3.c/ipmmu-vmsa.c
25
26
(cherry picked from commit 59753aac77528a584d3950936b853ebf264b68e7 from
27
the downstream branch poc/pci-passthrough from
28
https://gitlab.com/xen-project/people/bmarquis/xen-arm-poc.git)
29
---
30
xen/arch/arm/domain_build.c | 4 ++--
31
xen/arch/arm/include/asm/device.h | 14 ++++++++++++++
32
xen/common/device_tree.c | 2 +-
33
xen/drivers/passthrough/arm/ipmmu-vmsa.c | 4 ++--
34
xen/drivers/passthrough/arm/smmu-v3.c | 5 +++--
35
xen/drivers/passthrough/arm/smmu.c | 2 +-
36
xen/drivers/passthrough/device_tree.c | 8 ++++----
37
xen/include/xen/device_tree.h | 13 -------------
38
8 files changed, 27 insertions(+), 25 deletions(-)
39
40
diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
41
index XXXXXXX..XXXXXXX 100644
36
index XXXXXXX..XXXXXXX 100644
42
--- a/xen/arch/arm/domain_build.c
37
--- a/xen/arch/arm/pci/pci.c
43
+++ b/xen/arch/arm/domain_build.c
38
+++ b/xen/arch/arm/pci/pci.c
44
@@ -XXX,XX +XXX,XX @@ static int __init handle_device(struct domain *d, struct dt_device_node *dev,
39
@@ -XXX,XX +XXX,XX @@
45
return res;
40
#include <xen/device_tree.h>
46
}
41
#include <xen/errno.h>
47
42
#include <xen/init.h>
48
- if ( dt_device_is_protected(dev) )
43
+#include <xen/iommu.h>
49
+ if ( device_is_protected(dt_to_dev(dev)) )
44
#include <xen/param.h>
50
{
45
#include <xen/pci.h>
51
dt_dprintk("%s setup iommu\n", dt_node_full_name(dev));
46
52
res = iommu_assign_dt_device(d, dev);
47
@@ -XXX,XX +XXX,XX @@ static int __init pci_init(void)
53
@@ -XXX,XX +XXX,XX @@ static int __init handle_passthrough_prop(struct kernel_info *kinfo,
48
{
54
return res;
49
/*
55
50
* Enable PCI passthrough when has been enabled explicitly
56
/* If xen_force, we allow assignment of devices without IOMMU protection. */
51
- * (pci-passthrough=on).
57
- if ( xen_force && !dt_device_is_protected(node) )
52
+ * (pci-passthrough=on) or IOMMU is present and enabled.
58
+ if ( xen_force && !device_is_protected(dt_to_dev(node)) )
53
*/
54
- if ( !pci_passthrough_enabled )
55
+ if ( !is_pci_passthrough_enabled() && !iommu_enabled )
59
return 0;
56
return 0;
60
57
61
return iommu_assign_dt_device(kinfo->d, node);
58
pci_segments_init();
62
diff --git a/xen/arch/arm/include/asm/device.h b/xen/arch/arm/include/asm/device.h
59
diff --git a/xen/arch/x86/include/asm/pci.h b/xen/arch/x86/include/asm/pci.h
63
index XXXXXXX..XXXXXXX 100644
60
index XXXXXXX..XXXXXXX 100644
64
--- a/xen/arch/arm/include/asm/device.h
61
--- a/xen/arch/x86/include/asm/pci.h
65
+++ b/xen/arch/arm/include/asm/device.h
62
+++ b/xen/arch/x86/include/asm/pci.h
66
@@ -XXX,XX +XXX,XX @@
63
@@ -XXX,XX +XXX,XX @@ bool pci_ro_mmcfg_decode(unsigned long mfn, unsigned int *seg,
67
#ifndef __ASM_ARM_DEVICE_H
64
extern int pci_mmcfg_config_num;
68
#define __ASM_ARM_DEVICE_H
65
extern struct acpi_mcfg_allocation *pci_mmcfg_config;
69
66
70
+#include <xen/types.h>
67
-/* Unlike ARM, PCI passthrough is always enabled for x86. */
71
+
68
-static always_inline bool is_pci_passthrough_enabled(void)
72
enum device_type
73
{
74
DEV_DT,
75
@@ -XXX,XX +XXX,XX @@ struct dev_archdata {
76
struct device
77
{
78
enum device_type type;
79
+ bool is_protected; /* Shows that device is protected by IOMMU */
80
+ uint8_t _pad[3];
81
#ifdef CONFIG_HAS_DEVICE_TREE
82
struct dt_device_node *of_node; /* Used by drivers imported from Linux */
83
#endif
84
@@ -XXX,XX +XXX,XX @@ int device_init(struct dt_device_node *dev, enum device_class class,
85
*/
86
enum device_class device_get_class(const struct dt_device_node *dev);
87
88
+static inline void device_set_protected(struct device *device)
89
+{
90
+ device->is_protected = true;
91
+}
92
+
93
+static inline bool device_is_protected(const struct device *device)
94
+{
95
+ return device->is_protected;
96
+}
97
+
98
#define DT_DEVICE_START(_name, _namestr, _class) \
99
static const struct device_desc __dev_desc_##_name __used \
100
__section(".dev.info") = { \
101
diff --git a/xen/common/device_tree.c b/xen/common/device_tree.c
102
index XXXXXXX..XXXXXXX 100644
103
--- a/xen/common/device_tree.c
104
+++ b/xen/common/device_tree.c
105
@@ -XXX,XX +XXX,XX @@ static unsigned long __init unflatten_dt_node(const void *fdt,
106
/* By default dom0 owns the device */
107
np->used_by = 0;
108
/* By default the device is not protected */
109
- np->is_protected = false;
110
+ np->dev.is_protected = false;
111
INIT_LIST_HEAD(&np->domain_list);
112
113
if ( new_format )
114
diff --git a/xen/drivers/passthrough/arm/ipmmu-vmsa.c b/xen/drivers/passthrough/arm/ipmmu-vmsa.c
115
index XXXXXXX..XXXXXXX 100644
116
--- a/xen/drivers/passthrough/arm/ipmmu-vmsa.c
117
+++ b/xen/drivers/passthrough/arm/ipmmu-vmsa.c
118
@@ -XXX,XX +XXX,XX @@ static int ipmmu_add_device(u8 devfn, struct device *dev)
119
if ( !to_ipmmu(dev) )
120
return -ENODEV;
121
122
- if ( dt_device_is_protected(dev_to_dt(dev)) )
123
+ if ( device_is_protected(dev) )
124
{
125
dev_err(dev, "Already added to IPMMU\n");
126
return -EEXIST;
127
}
128
129
/* Let Xen know that the master device is protected by an IOMMU. */
130
- dt_device_set_protected(dev_to_dt(dev));
131
+ device_set_protected(dev);
132
133
dev_info(dev, "Added master device (IPMMU %s micro-TLBs %u)\n",
134
dev_name(fwspec->iommu_dev), fwspec->num_ids);
135
diff --git a/xen/drivers/passthrough/arm/smmu-v3.c b/xen/drivers/passthrough/arm/smmu-v3.c
136
index XXXXXXX..XXXXXXX 100644
137
--- a/xen/drivers/passthrough/arm/smmu-v3.c
138
+++ b/xen/drivers/passthrough/arm/smmu-v3.c
139
@@ -XXX,XX +XXX,XX @@ static int arm_smmu_add_device(u8 devfn, struct device *dev)
140
     */
141
    arm_smmu_enable_pasid(master);
142
143
-    if (dt_device_is_protected(dev_to_dt(dev))) {
144
+    if ( device_is_protected(dev) )
145
+    {
146
        dev_err(dev, "Already added to SMMUv3\n");
147
        return -EEXIST;
148
    }
149
150
    /* Let Xen know that the master device is protected by an IOMMU. */
151
-    dt_device_set_protected(dev_to_dt(dev));
152
+    device_set_protected(dev);
153
154
    dev_info(dev, "Added master device (SMMUv3 %s StreamIds %u)\n",
155
            dev_name(fwspec->iommu_dev), fwspec->num_ids);
156
diff --git a/xen/drivers/passthrough/arm/smmu.c b/xen/drivers/passthrough/arm/smmu.c
157
index XXXXXXX..XXXXXXX 100644
158
--- a/xen/drivers/passthrough/arm/smmu.c
159
+++ b/xen/drivers/passthrough/arm/smmu.c
160
@@ -XXX,XX +XXX,XX @@ static int arm_smmu_dt_add_device_legacy(struct arm_smmu_device *smmu,
161
    master->of_node = dev_node;
162
163
    /* Xen: Let Xen know that the device is protected by an SMMU */
164
-    dt_device_set_protected(dev_node);
165
+    device_set_protected(dev);
166
167
    for (i = 0; i < fwspec->num_ids; ++i) {
168
        if (!(smmu->features & ARM_SMMU_FEAT_STREAM_MATCH) &&
169
diff --git a/xen/drivers/passthrough/device_tree.c b/xen/drivers/passthrough/device_tree.c
170
index XXXXXXX..XXXXXXX 100644
171
--- a/xen/drivers/passthrough/device_tree.c
172
+++ b/xen/drivers/passthrough/device_tree.c
173
@@ -XXX,XX +XXX,XX @@ int iommu_assign_dt_device(struct domain *d, struct dt_device_node *dev)
174
if ( !is_iommu_enabled(d) )
175
return -EINVAL;
176
177
- if ( !dt_device_is_protected(dev) )
178
+ if ( !device_is_protected(dt_to_dev(dev)) )
179
return -EINVAL;
180
181
spin_lock(&dtdevs_lock);
182
@@ -XXX,XX +XXX,XX @@ int iommu_deassign_dt_device(struct domain *d, struct dt_device_node *dev)
183
if ( !is_iommu_enabled(d) )
184
return -EINVAL;
185
186
- if ( !dt_device_is_protected(dev) )
187
+ if ( !device_is_protected(dt_to_dev(dev)) )
188
return -EINVAL;
189
190
spin_lock(&dtdevs_lock);
191
@@ -XXX,XX +XXX,XX @@ static bool_t iommu_dt_device_is_assigned(const struct dt_device_node *dev)
192
{
193
bool_t assigned = 0;
194
195
- if ( !dt_device_is_protected(dev) )
196
+ if ( !device_is_protected(dt_to_dev(dev)) )
197
return 0;
198
199
spin_lock(&dtdevs_lock);
200
@@ -XXX,XX +XXX,XX @@ int iommu_add_dt_device(struct dt_device_node *np)
201
* and iommus property, there is no need to register it again. In this case
202
* simply return success early.
203
*/
204
- if ( dt_device_is_protected(np) )
205
+ if ( device_is_protected(dev) )
206
return 0;
207
208
if ( dev_iommu_fwspec_get(dev) )
209
diff --git a/xen/include/xen/device_tree.h b/xen/include/xen/device_tree.h
210
index XXXXXXX..XXXXXXX 100644
211
--- a/xen/include/xen/device_tree.h
212
+++ b/xen/include/xen/device_tree.h
213
@@ -XXX,XX +XXX,XX @@ struct dt_device_node {
214
struct dt_device_node *next; /* TODO: Remove it. Only use to know the last children */
215
struct dt_device_node *allnext;
216
217
- /* IOMMU specific fields */
218
- bool is_protected;
219
-
220
/* HACK: Remove this if there is a need of space */
221
bool_t static_evtchn_created;
222
223
@@ -XXX,XX +XXX,XX @@ static inline domid_t dt_device_used_by(const struct dt_device_node *device)
224
return device->used_by;
225
}
226
227
-static inline void dt_device_set_protected(struct dt_device_node *device)
228
-{
69
-{
229
- device->is_protected = true;
70
- return true;
230
-}
71
-}
231
-
72
-
232
-static inline bool dt_device_is_protected(const struct dt_device_node *device)
73
void arch_pci_init_pdev(struct pci_dev *pdev);
233
-{
74
234
- return device->is_protected;
75
static inline bool pci_check_bar(const struct pci_dev *pdev,
235
-}
76
diff --git a/xen/drivers/pci/physdev.c b/xen/drivers/pci/physdev.c
236
-
77
index XXXXXXX..XXXXXXX 100644
237
static inline bool_t dt_property_name_is_equal(const struct dt_property *pp,
78
--- a/xen/drivers/pci/physdev.c
238
const char *name)
79
+++ b/xen/drivers/pci/physdev.c
239
{
80
@@ -XXX,XX +XXX,XX @@ ret_t pci_physdev_op(int cmd, XEN_GUEST_HANDLE_PARAM(void) arg)
81
struct pci_dev_info pdev_info;
82
nodeid_t node = NUMA_NO_NODE;
83
84
- if ( !is_pci_passthrough_enabled() )
85
+ if ( !is_pci_passthrough_enabled() && !iommu_enabled )
86
return -EOPNOTSUPP;
87
88
ret = -EFAULT;
89
@@ -XXX,XX +XXX,XX @@ ret_t pci_physdev_op(int cmd, XEN_GUEST_HANDLE_PARAM(void) arg)
90
case PHYSDEVOP_pci_device_remove: {
91
struct physdev_pci_device dev;
92
93
- if ( !is_pci_passthrough_enabled() )
94
+ if ( !is_pci_passthrough_enabled() && !iommu_enabled )
95
return -EOPNOTSUPP;
96
97
ret = -EFAULT;
240
--
98
--
241
2.40.1
99
2.34.1
diff view generated by jsdifflib
1
From: Oleksandr Tyshchenko <oleksandr_tyshchenko@epam.com>
1
From: Rahul Singh <rahul.singh@arm.com>
2
2
3
Improve readability of check for devices already registered with the SMMU with
3
When ITS is enabled and PCI devices that are behind an SMMU generate an
4
legacy mmu-masters DT bindings by using is_protected.
4
MSI interrupt, SMMU fault will be observed as there is currently no
5
mapping in p2m table for the ITS translation register (GITS_TRANSLATER).
5
6
6
There are 2 device tree bindings for registering a device with the SMMU:
7
A mapping is required in the iommu page tables so that the device can
7
* mmu-masters (legacy, SMMUv1/2 only)
8
generate the MSI interrupt writing to the GITS_TRANSLATER register.
8
* iommus
9
9
10
A device tree may include both mmu-masters and iommus properties (although it is
10
The GITS_TRANSLATER register is a 32-bit register, and there is nothing
11
unnecessary to do so). When a device appears in the mmu-masters list,
11
else in a page containing it, so map that page.
12
np->is_protected and dev->iommu_fwspec both get set by the SMMUv1/2 driver. The
13
function iommu_add_dt_device() is subsequently invoked for devices that have an
14
iommus specification.
15
12
16
The check as it was before this patch:
13
Signed-off-by: Rahul Singh <rahul.singh@arm.com>
14
Signed-off-by: Stewart Hildebrand <stewart.hildebrand@amd.com>
15
Signed-off-by: Mykyta Poturai <mykyta_poturai@epam.com>
16
---
17
This patch was originally picked up from [1], and commit description
18
loosely borrowed from [2].
17
19
18
if ( dev_iommu_fwspec_get(dev) )
20
Example SMMUv3 fault (qemu-system-aarch64 virt model), ITS base 0x8080000:
19
return 0;
20
21
21
and the new check:
22
(XEN) SMMUv3: /smmuv3@9050000: event 0x10 received:
23
(XEN) SMMUv3: /smmuv3@9050000: 0x0000000800000010
24
(XEN) SMMUv3: /smmuv3@9050000: 0x0000008000000000
25
(XEN) SMMUv3: /smmuv3@9050000: 0x0000000008090040
26
(XEN) SMMUv3: /smmuv3@9050000: 0x0000000000000000
22
27
23
if ( dt_device_is_protected(np) )
28
Example SMMUv2 fault (AMD/Xilinx Versal), ITS base 0xf9020000:
24
return 0;
25
29
26
are guarding against the same corner case: when a device has both mmu-masters
30
(XEN) smmu: /axi/smmu@fd800000: Unhandled context fault: fsr=0x402, iova=0xf9030040, fsynr=0x12, cb=0
27
and iommus specifications in the device tree. The is_protected naming is more
28
descriptive.
29
31
30
If np->is_protected is not set (i.e. false), but dev->iommu_fwspec is set, it is
32
v6->v7:
31
an error condition, so return an error in this case.
33
* add tlb flush after mapping
34
* style: update formatting
35
* revert back to printk with XENLOG_G_ERR
32
36
33
Expand the comment to further clarify the corner case.
37
v5->v6:
38
* switch to iommu_map() interface
39
* fix page_count argument
40
* style fixup
41
* use gprintk instead of printk
42
* add my Signed-off-by
43
* move to vgic_v3_its_init_virtual()
34
44
35
Signed-off-by: Oleksandr Tyshchenko <oleksandr_tyshchenko@epam.com>
45
v4->v5:
36
Signed-off-by: Stewart Hildebrand <stewart.hildebrand@amd.com>
46
* new patch
47
48
[1] https://lists.xenproject.org/archives/html/xen-devel/2023-07/msg00483.html
49
[2] https://gitlab.com/xen-project/people/bmarquis/xen-arm-poc/-/commit/6232a0d53377009bb7fbc3c3ab81d0153734be6b
37
---
50
---
38
v3->v4:
51
xen/arch/arm/vgic-v3-its.c | 20 ++++++++++++++++++++
39
* new patch: this change was split from ("xen/arm: Move is_protected flag to struct device")
52
1 file changed, 20 insertions(+)
40
---
41
xen/drivers/passthrough/device_tree.c | 11 ++++++++---
42
1 file changed, 8 insertions(+), 3 deletions(-)
43
53
44
diff --git a/xen/drivers/passthrough/device_tree.c b/xen/drivers/passthrough/device_tree.c
54
diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c
45
index XXXXXXX..XXXXXXX 100644
55
index XXXXXXX..XXXXXXX 100644
46
--- a/xen/drivers/passthrough/device_tree.c
56
--- a/xen/arch/arm/vgic-v3-its.c
47
+++ b/xen/drivers/passthrough/device_tree.c
57
+++ b/xen/arch/arm/vgic-v3-its.c
48
@@ -XXX,XX +XXX,XX @@ int iommu_add_dt_device(struct dt_device_node *np)
58
@@ -XXX,XX +XXX,XX @@ static int vgic_v3_its_init_virtual(struct domain *d, paddr_t guest_addr,
49
return -EINVAL;
59
50
60
register_mmio_handler(d, &vgic_its_mmio_handler, guest_addr, SZ_64K, its);
51
/*
61
52
- * The device may already have been registered. As there is no harm in
62
+ if ( is_iommu_enabled(its->d) )
53
- * it just return success early.
63
+ {
54
+ * Devices that appear in the legacy mmu-masters list may have already been
64
+ mfn_t mfn = maddr_to_mfn(its->doorbell_address);
55
+ * registered with the SMMU. In case a device has both a mmu-masters entry
65
+ unsigned int flush_flags = 0;
56
+ * and iommus property, there is no need to register it again. In this case
66
+ int ret = iommu_map(its->d, _dfn(mfn_x(mfn)), mfn, 1, IOMMUF_writable,
57
+ * simply return success early.
67
+ &flush_flags);
58
*/
59
- if ( dev_iommu_fwspec_get(dev) )
60
+ if ( dt_device_is_protected(np) )
61
return 0;
62
63
+ if ( dev_iommu_fwspec_get(dev) )
64
+ return -EEXIST;
65
+
68
+
66
/*
69
+ if ( ret < 0 )
67
* According to the Documentation/devicetree/bindings/iommu/iommu.txt
70
+ {
68
* from Linux.
71
+ printk(XENLOG_G_ERR
72
+ "GICv3: Map ITS translation register for %pd failed.\n",
73
+ its->d);
74
+ return ret;
75
+ }
76
+
77
+ ret = iommu_iotlb_flush(its->d, _dfn(mfn_x(mfn)), 1, flush_flags);
78
+ if ( ret < 0 )
79
+ return ret;
80
+ }
81
+
82
/* Register the virtual ITS to be able to clean it up later. */
83
list_add_tail(&its->vits_list, &d->arch.vgic.vits_list);
84
69
--
85
--
70
2.40.1
86
2.34.1
diff view generated by jsdifflib