xref: /openbmc/linux/drivers/acpi/viot.c (revision fadbafc1)
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 	u32 domain_nr = pci_domain_nr(pdev->bus);
332 
333 	list_for_each_entry(ep, &viot_pci_ranges, list) {
334 		if (domain_nr >= ep->segment_start &&
335 		    domain_nr <= ep->segment_end &&
336 		    dev_id >= ep->bdf_start &&
337 		    dev_id <= ep->bdf_end) {
338 			epid = ((domain_nr - ep->segment_start) << 16) +
339 				dev_id - ep->bdf_start + ep->endpoint_id;
340 
341 			return viot_dev_iommu_init(&pdev->dev, ep->viommu,
342 						   epid);
343 		}
344 	}
345 	return -ENODEV;
346 }
347 
348 static int viot_mmio_dev_iommu_init(struct platform_device *pdev)
349 {
350 	struct resource *mem;
351 	struct viot_endpoint *ep;
352 
353 	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
354 	if (!mem)
355 		return -ENODEV;
356 
357 	list_for_each_entry(ep, &viot_mmio_endpoints, list) {
358 		if (ep->address == mem->start)
359 			return viot_dev_iommu_init(&pdev->dev, ep->viommu,
360 						   ep->endpoint_id);
361 	}
362 	return -ENODEV;
363 }
364 
365 /**
366  * viot_iommu_configure - Setup IOMMU ops for an endpoint described by VIOT
367  * @dev: the endpoint
368  *
369  * Return: 0 on success, <0 on failure
370  */
371 int viot_iommu_configure(struct device *dev)
372 {
373 	if (dev_is_pci(dev))
374 		return pci_for_each_dma_alias(to_pci_dev(dev),
375 					      viot_pci_dev_iommu_init, NULL);
376 	else if (dev_is_platform(dev))
377 		return viot_mmio_dev_iommu_init(to_platform_device(dev));
378 	return -ENODEV;
379 }
380