xref: /openbmc/linux/drivers/acpi/viot.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
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  
viot_check_bounds(const struct acpi_viot_header * hdr)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  
viot_get_pci_iommu_fwnode(struct viot_iommu * viommu,u16 segment,u16 bdf)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  
viot_get_mmio_iommu_fwnode(struct viot_iommu * viommu,u64 address)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  
viot_get_iommu(unsigned int offset)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  
viot_parse_node(const struct acpi_viot_header * hdr)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   */
acpi_viot_early_init(void)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   */
acpi_viot_init(void)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  
viot_dev_iommu_init(struct device * dev,struct viot_iommu * viommu,u32 epid)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  
viot_pci_dev_iommu_init(struct pci_dev * pdev,u16 dev_id,void * data)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  
viot_mmio_dev_iommu_init(struct platform_device * pdev)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   */
viot_iommu_configure(struct device * dev)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  }
381