Linux 6.9-rc1
[linux-2.6-microblaze.git] / drivers / acpi / viot.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Virtual I/O topology
4  *
5  * The Virtual I/O Translation Table (VIOT) describes the topology of
6  * para-virtual IOMMUs and the endpoints they manage. The OS uses it to
7  * initialize devices in the right order, preventing endpoints from issuing DMA
8  * before their IOMMU is ready.
9  *
10  * When binding a driver to a device, before calling the device driver's probe()
11  * method, the driver infrastructure calls dma_configure(). At that point the
12  * VIOT driver looks for an IOMMU associated to the device in the VIOT table.
13  * If an IOMMU exists and has been initialized, the VIOT driver initializes the
14  * device's IOMMU fwspec, allowing the DMA infrastructure to invoke the IOMMU
15  * ops when the device driver configures DMA mappings. If an IOMMU exists and
16  * hasn't yet been initialized, VIOT returns -EPROBE_DEFER to postpone probing
17  * the device until the IOMMU is available.
18  */
19 #define pr_fmt(fmt) "ACPI: VIOT: " fmt
20
21 #include <linux/acpi_viot.h>
22 #include <linux/fwnode.h>
23 #include <linux/iommu.h>
24 #include <linux/list.h>
25 #include <linux/pci.h>
26 #include <linux/platform_device.h>
27
28 struct viot_iommu {
29         /* Node offset within the table */
30         unsigned int                    offset;
31         struct fwnode_handle            *fwnode;
32         struct list_head                list;
33 };
34
35 struct viot_endpoint {
36         union {
37                 /* PCI range */
38                 struct {
39                         u16             segment_start;
40                         u16             segment_end;
41                         u16             bdf_start;
42                         u16             bdf_end;
43                 };
44                 /* MMIO */
45                 u64                     address;
46         };
47         u32                             endpoint_id;
48         struct viot_iommu               *viommu;
49         struct list_head                list;
50 };
51
52 static struct acpi_table_viot *viot;
53 static LIST_HEAD(viot_iommus);
54 static LIST_HEAD(viot_pci_ranges);
55 static LIST_HEAD(viot_mmio_endpoints);
56
57 static int __init viot_check_bounds(const struct acpi_viot_header *hdr)
58 {
59         struct acpi_viot_header *start, *end, *hdr_end;
60
61         start = ACPI_ADD_PTR(struct acpi_viot_header, viot,
62                              max_t(size_t, sizeof(*viot), viot->node_offset));
63         end = ACPI_ADD_PTR(struct acpi_viot_header, viot, viot->header.length);
64         hdr_end = ACPI_ADD_PTR(struct acpi_viot_header, hdr, sizeof(*hdr));
65
66         if (hdr < start || hdr_end > end) {
67                 pr_err(FW_BUG "Node pointer overflows\n");
68                 return -EOVERFLOW;
69         }
70         if (hdr->length < sizeof(*hdr)) {
71                 pr_err(FW_BUG "Empty node\n");
72                 return -EINVAL;
73         }
74         return 0;
75 }
76
77 static int __init viot_get_pci_iommu_fwnode(struct viot_iommu *viommu,
78                                             u16 segment, u16 bdf)
79 {
80         struct pci_dev *pdev;
81         struct fwnode_handle *fwnode;
82
83         pdev = pci_get_domain_bus_and_slot(segment, PCI_BUS_NUM(bdf),
84                                            bdf & 0xff);
85         if (!pdev) {
86                 pr_err("Could not find PCI IOMMU\n");
87                 return -ENODEV;
88         }
89
90         fwnode = dev_fwnode(&pdev->dev);
91         if (!fwnode) {
92                 /*
93                  * PCI devices aren't necessarily described by ACPI. Create a
94                  * fwnode so the IOMMU subsystem can identify this device.
95                  */
96                 fwnode = acpi_alloc_fwnode_static();
97                 if (!fwnode) {
98                         pci_dev_put(pdev);
99                         return -ENOMEM;
100                 }
101                 set_primary_fwnode(&pdev->dev, fwnode);
102         }
103         viommu->fwnode = dev_fwnode(&pdev->dev);
104         pci_dev_put(pdev);
105         return 0;
106 }
107
108 static int __init viot_get_mmio_iommu_fwnode(struct viot_iommu *viommu,
109                                              u64 address)
110 {
111         struct acpi_device *adev;
112         struct resource res = {
113                 .start  = address,
114                 .end    = address,
115                 .flags  = IORESOURCE_MEM,
116         };
117
118         adev = acpi_resource_consumer(&res);
119         if (!adev) {
120                 pr_err("Could not find MMIO IOMMU\n");
121                 return -EINVAL;
122         }
123         viommu->fwnode = &adev->fwnode;
124         return 0;
125 }
126
127 static struct viot_iommu * __init viot_get_iommu(unsigned int offset)
128 {
129         int ret;
130         struct viot_iommu *viommu;
131         struct acpi_viot_header *hdr = ACPI_ADD_PTR(struct acpi_viot_header,
132                                                     viot, offset);
133         union {
134                 struct acpi_viot_virtio_iommu_pci pci;
135                 struct acpi_viot_virtio_iommu_mmio mmio;
136         } *node = (void *)hdr;
137
138         list_for_each_entry(viommu, &viot_iommus, list)
139                 if (viommu->offset == offset)
140                         return viommu;
141
142         if (viot_check_bounds(hdr))
143                 return NULL;
144
145         viommu = kzalloc(sizeof(*viommu), GFP_KERNEL);
146         if (!viommu)
147                 return NULL;
148
149         viommu->offset = offset;
150         switch (hdr->type) {
151         case ACPI_VIOT_NODE_VIRTIO_IOMMU_PCI:
152                 if (hdr->length < sizeof(node->pci))
153                         goto err_free;
154
155                 ret = viot_get_pci_iommu_fwnode(viommu, node->pci.segment,
156                                                 node->pci.bdf);
157                 break;
158         case ACPI_VIOT_NODE_VIRTIO_IOMMU_MMIO:
159                 if (hdr->length < sizeof(node->mmio))
160                         goto err_free;
161
162                 ret = viot_get_mmio_iommu_fwnode(viommu,
163                                                  node->mmio.base_address);
164                 break;
165         default:
166                 ret = -EINVAL;
167         }
168         if (ret)
169                 goto err_free;
170
171         list_add(&viommu->list, &viot_iommus);
172         return viommu;
173
174 err_free:
175         kfree(viommu);
176         return NULL;
177 }
178
179 static int __init viot_parse_node(const struct acpi_viot_header *hdr)
180 {
181         int ret = -EINVAL;
182         struct list_head *list;
183         struct viot_endpoint *ep;
184         union {
185                 struct acpi_viot_mmio mmio;
186                 struct acpi_viot_pci_range pci;
187         } *node = (void *)hdr;
188
189         if (viot_check_bounds(hdr))
190                 return -EINVAL;
191
192         if (hdr->type == ACPI_VIOT_NODE_VIRTIO_IOMMU_PCI ||
193             hdr->type == ACPI_VIOT_NODE_VIRTIO_IOMMU_MMIO)
194                 return 0;
195
196         ep = kzalloc(sizeof(*ep), GFP_KERNEL);
197         if (!ep)
198                 return -ENOMEM;
199
200         switch (hdr->type) {
201         case ACPI_VIOT_NODE_PCI_RANGE:
202                 if (hdr->length < sizeof(node->pci)) {
203                         pr_err(FW_BUG "Invalid PCI node size\n");
204                         goto err_free;
205                 }
206
207                 ep->segment_start = node->pci.segment_start;
208                 ep->segment_end = node->pci.segment_end;
209                 ep->bdf_start = node->pci.bdf_start;
210                 ep->bdf_end = node->pci.bdf_end;
211                 ep->endpoint_id = node->pci.endpoint_start;
212                 ep->viommu = viot_get_iommu(node->pci.output_node);
213                 list = &viot_pci_ranges;
214                 break;
215         case ACPI_VIOT_NODE_MMIO:
216                 if (hdr->length < sizeof(node->mmio)) {
217                         pr_err(FW_BUG "Invalid MMIO node size\n");
218                         goto err_free;
219                 }
220
221                 ep->address = node->mmio.base_address;
222                 ep->endpoint_id = node->mmio.endpoint;
223                 ep->viommu = viot_get_iommu(node->mmio.output_node);
224                 list = &viot_mmio_endpoints;
225                 break;
226         default:
227                 pr_warn("Unsupported node %x\n", hdr->type);
228                 ret = 0;
229                 goto err_free;
230         }
231
232         if (!ep->viommu) {
233                 pr_warn("No IOMMU node found\n");
234                 /*
235                  * A future version of the table may use the node for other
236                  * purposes. Keep parsing.
237                  */
238                 ret = 0;
239                 goto err_free;
240         }
241
242         list_add(&ep->list, list);
243         return 0;
244
245 err_free:
246         kfree(ep);
247         return ret;
248 }
249
250 /**
251  * acpi_viot_early_init - Test the presence of VIOT and enable ACS
252  *
253  * If the VIOT does exist, ACS must be enabled. This cannot be
254  * done in acpi_viot_init() which is called after the bus scan
255  */
256 void __init acpi_viot_early_init(void)
257 {
258 #ifdef CONFIG_PCI
259         acpi_status status;
260         struct acpi_table_header *hdr;
261
262         status = acpi_get_table(ACPI_SIG_VIOT, 0, &hdr);
263         if (ACPI_FAILURE(status))
264                 return;
265         pci_request_acs();
266         acpi_put_table(hdr);
267 #endif
268 }
269
270 /**
271  * acpi_viot_init - Parse the VIOT table
272  *
273  * Parse the VIOT table, prepare the list of endpoints to be used during DMA
274  * setup of devices.
275  */
276 void __init acpi_viot_init(void)
277 {
278         int i;
279         acpi_status status;
280         struct acpi_table_header *hdr;
281         struct acpi_viot_header *node;
282
283         status = acpi_get_table(ACPI_SIG_VIOT, 0, &hdr);
284         if (ACPI_FAILURE(status)) {
285                 if (status != AE_NOT_FOUND) {
286                         const char *msg = acpi_format_exception(status);
287
288                         pr_err("Failed to get table, %s\n", msg);
289                 }
290                 return;
291         }
292
293         viot = (void *)hdr;
294
295         node = ACPI_ADD_PTR(struct acpi_viot_header, viot, viot->node_offset);
296         for (i = 0; i < viot->node_count; i++) {
297                 if (viot_parse_node(node))
298                         return;
299
300                 node = ACPI_ADD_PTR(struct acpi_viot_header, node,
301                                     node->length);
302         }
303
304         acpi_put_table(hdr);
305 }
306
307 static int viot_dev_iommu_init(struct device *dev, struct viot_iommu *viommu,
308                                u32 epid)
309 {
310         const struct iommu_ops *ops;
311
312         if (!viommu)
313                 return -ENODEV;
314
315         /* We're not translating ourself */
316         if (device_match_fwnode(dev, viommu->fwnode))
317                 return -EINVAL;
318
319         ops = iommu_ops_from_fwnode(viommu->fwnode);
320         if (!ops)
321                 return IS_ENABLED(CONFIG_VIRTIO_IOMMU) ?
322                         -EPROBE_DEFER : -ENODEV;
323
324         return acpi_iommu_fwspec_init(dev, epid, viommu->fwnode, ops);
325 }
326
327 static int viot_pci_dev_iommu_init(struct pci_dev *pdev, u16 dev_id, void *data)
328 {
329         u32 epid;
330         struct viot_endpoint *ep;
331         struct device *aliased_dev = data;
332         u32 domain_nr = pci_domain_nr(pdev->bus);
333
334         list_for_each_entry(ep, &viot_pci_ranges, list) {
335                 if (domain_nr >= ep->segment_start &&
336                     domain_nr <= ep->segment_end &&
337                     dev_id >= ep->bdf_start &&
338                     dev_id <= ep->bdf_end) {
339                         epid = ((domain_nr - ep->segment_start) << 16) +
340                                 dev_id - ep->bdf_start + ep->endpoint_id;
341
342                         return viot_dev_iommu_init(aliased_dev, ep->viommu,
343                                                    epid);
344                 }
345         }
346         return -ENODEV;
347 }
348
349 static int viot_mmio_dev_iommu_init(struct platform_device *pdev)
350 {
351         struct resource *mem;
352         struct viot_endpoint *ep;
353
354         mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
355         if (!mem)
356                 return -ENODEV;
357
358         list_for_each_entry(ep, &viot_mmio_endpoints, list) {
359                 if (ep->address == mem->start)
360                         return viot_dev_iommu_init(&pdev->dev, ep->viommu,
361                                                    ep->endpoint_id);
362         }
363         return -ENODEV;
364 }
365
366 /**
367  * viot_iommu_configure - Setup IOMMU ops for an endpoint described by VIOT
368  * @dev: the endpoint
369  *
370  * Return: 0 on success, <0 on failure
371  */
372 int viot_iommu_configure(struct device *dev)
373 {
374         if (dev_is_pci(dev))
375                 return pci_for_each_dma_alias(to_pci_dev(dev),
376                                               viot_pci_dev_iommu_init, dev);
377         else if (dev_is_platform(dev))
378                 return viot_mmio_dev_iommu_init(to_platform_device(dev));
379         return -ENODEV;
380 }