aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iommu/of_iommu.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-10-11 15:52:41 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-10-11 15:52:41 -0400
commit56e520c7a0a490b63b042b047ec9659fc08762a4 (patch)
treeb20296f4b088d81aba3c41174d52afa209afff9b /drivers/iommu/of_iommu.c
parentd09ba13110e303d7baa29d170da94cd24f7662b2 (diff)
parent13a08259187c5cd3f63d98efa159ab42976d85a4 (diff)
Merge tag 'iommu-updates-v4.9' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu
Pull IOMMU updates from Joerg Roedel: - support for interrupt virtualization in the AMD IOMMU driver. These patches were shared with the KVM tree and are already merged through that tree. - generic DT-binding support for the ARM-SMMU driver. With this the driver now makes use of the generic DMA-API code. This also required some changes outside of the IOMMU code, but these are acked by the respective maintainers. - more cleanups and fixes all over the place. * tag 'iommu-updates-v4.9' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu: (40 commits) iommu/amd: No need to wait iommu completion if no dte irq entry change iommu/amd: Free domain id when free a domain of struct dma_ops_domain iommu/amd: Use standard bitmap operation to set bitmap iommu/amd: Clean up the cmpxchg64 invocation iommu/io-pgtable-arm: Check for v7s-incapable systems iommu/dma: Avoid PCI host bridge windows iommu/dma: Add support for mapping MSIs iommu/arm-smmu: Set domain geometry iommu/arm-smmu: Wire up generic configuration support Docs: dt: document ARM SMMU generic binding usage iommu/arm-smmu: Convert to iommu_fwspec iommu/arm-smmu: Intelligent SMR allocation iommu/arm-smmu: Add a stream map entry iterator iommu/arm-smmu: Streamline SMMU data lookups iommu/arm-smmu: Refactor mmu-masters handling iommu/arm-smmu: Keep track of S2CR state iommu/arm-smmu: Consolidate stream map entry state iommu/arm-smmu: Handle stream IDs more dynamically iommu/arm-smmu: Set PRIVCFG in stage 1 STEs iommu/arm-smmu: Support non-PCI devices with SMMUv3 ...
Diffstat (limited to 'drivers/iommu/of_iommu.c')
-rw-r--r--drivers/iommu/of_iommu.c52
1 files changed, 46 insertions, 6 deletions
diff --git a/drivers/iommu/of_iommu.c b/drivers/iommu/of_iommu.c
index 57f23eaaa2f9..5b82862f571f 100644
--- a/drivers/iommu/of_iommu.c
+++ b/drivers/iommu/of_iommu.c
@@ -22,6 +22,7 @@
22#include <linux/limits.h> 22#include <linux/limits.h>
23#include <linux/of.h> 23#include <linux/of.h>
24#include <linux/of_iommu.h> 24#include <linux/of_iommu.h>
25#include <linux/of_pci.h>
25#include <linux/slab.h> 26#include <linux/slab.h>
26 27
27static const struct of_device_id __iommu_of_table_sentinel 28static const struct of_device_id __iommu_of_table_sentinel
@@ -134,6 +135,47 @@ const struct iommu_ops *of_iommu_get_ops(struct device_node *np)
134 return ops; 135 return ops;
135} 136}
136 137
138static int __get_pci_rid(struct pci_dev *pdev, u16 alias, void *data)
139{
140 struct of_phandle_args *iommu_spec = data;
141
142 iommu_spec->args[0] = alias;
143 return iommu_spec->np == pdev->bus->dev.of_node;
144}
145
146static const struct iommu_ops
147*of_pci_iommu_configure(struct pci_dev *pdev, struct device_node *bridge_np)
148{
149 const struct iommu_ops *ops;
150 struct of_phandle_args iommu_spec;
151
152 /*
153 * Start by tracing the RID alias down the PCI topology as
154 * far as the host bridge whose OF node we have...
155 * (we're not even attempting to handle multi-alias devices yet)
156 */
157 iommu_spec.args_count = 1;
158 iommu_spec.np = bridge_np;
159 pci_for_each_dma_alias(pdev, __get_pci_rid, &iommu_spec);
160 /*
161 * ...then find out what that becomes once it escapes the PCI
162 * bus into the system beyond, and which IOMMU it ends up at.
163 */
164 iommu_spec.np = NULL;
165 if (of_pci_map_rid(bridge_np, iommu_spec.args[0], "iommu-map",
166 "iommu-map-mask", &iommu_spec.np, iommu_spec.args))
167 return NULL;
168
169 ops = of_iommu_get_ops(iommu_spec.np);
170 if (!ops || !ops->of_xlate ||
171 iommu_fwspec_init(&pdev->dev, &iommu_spec.np->fwnode, ops) ||
172 ops->of_xlate(&pdev->dev, &iommu_spec))
173 ops = NULL;
174
175 of_node_put(iommu_spec.np);
176 return ops;
177}
178
137const struct iommu_ops *of_iommu_configure(struct device *dev, 179const struct iommu_ops *of_iommu_configure(struct device *dev,
138 struct device_node *master_np) 180 struct device_node *master_np)
139{ 181{
@@ -142,12 +184,8 @@ const struct iommu_ops *of_iommu_configure(struct device *dev,
142 const struct iommu_ops *ops = NULL; 184 const struct iommu_ops *ops = NULL;
143 int idx = 0; 185 int idx = 0;
144 186
145 /*
146 * We can't do much for PCI devices without knowing how
147 * device IDs are wired up from the PCI bus to the IOMMU.
148 */
149 if (dev_is_pci(dev)) 187 if (dev_is_pci(dev))
150 return NULL; 188 return of_pci_iommu_configure(to_pci_dev(dev), master_np);
151 189
152 /* 190 /*
153 * We don't currently walk up the tree looking for a parent IOMMU. 191 * We don't currently walk up the tree looking for a parent IOMMU.
@@ -160,7 +198,9 @@ const struct iommu_ops *of_iommu_configure(struct device *dev,
160 np = iommu_spec.np; 198 np = iommu_spec.np;
161 ops = of_iommu_get_ops(np); 199 ops = of_iommu_get_ops(np);
162 200
163 if (!ops || !ops->of_xlate || ops->of_xlate(dev, &iommu_spec)) 201 if (!ops || !ops->of_xlate ||
202 iommu_fwspec_init(dev, &np->fwnode, ops) ||
203 ops->of_xlate(dev, &iommu_spec))
164 goto err_put_node; 204 goto err_put_node;
165 205
166 of_node_put(np); 206 of_node_put(np);