aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoerg Roedel <jroedel@suse.de>2016-04-08 09:12:24 -0400
committerJoerg Roedel <jroedel@suse.de>2016-04-11 10:07:51 -0400
commite3156048346c28c695f5cf9db67a8cf88c90f947 (patch)
tree03038b4566a5e1421bd59e0e5e9aeb8464aba810
parentbf16200689118d19de1b8d2a3c314fc21f5dc7bb (diff)
iommu/amd: Fix checking of pci dma aliases
Commit 61289cb ('iommu/amd: Remove old alias handling code') removed the old alias handling code from the AMD IOMMU driver because this is now handled by the IOMMU core code. But this also removed the handling of PCI aliases, which is not handled by the core code. This caused issues with PCI devices that have hidden PCIe-to-PCI bridges that rewrite the request-id. Fix this bug by re-introducing some of the removed functions from commit 61289cbaf6c8 and add a alias field 'struct iommu_dev_data'. This field carrys the return value of the get_alias() function and uses that instead of the amd_iommu_alias_table[] array in the code. Fixes: 61289cbaf6c8 ('iommu/amd: Remove old alias handling code') Cc: stable@vger.kernel.org # v4.4+ Tested-by: Tomasz Golinski <tomaszg@math.uwb.edu.pl> Signed-off-by: Joerg Roedel <jroedel@suse.de>
-rw-r--r--drivers/iommu/amd_iommu.c87
1 files changed, 76 insertions, 11 deletions
diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index 374c129219ef..5efadad4615b 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -92,6 +92,7 @@ struct iommu_dev_data {
92 struct list_head dev_data_list; /* For global dev_data_list */ 92 struct list_head dev_data_list; /* For global dev_data_list */
93 struct protection_domain *domain; /* Domain the device is bound to */ 93 struct protection_domain *domain; /* Domain the device is bound to */
94 u16 devid; /* PCI Device ID */ 94 u16 devid; /* PCI Device ID */
95 u16 alias; /* Alias Device ID */
95 bool iommu_v2; /* Device can make use of IOMMUv2 */ 96 bool iommu_v2; /* Device can make use of IOMMUv2 */
96 bool passthrough; /* Device is identity mapped */ 97 bool passthrough; /* Device is identity mapped */
97 struct { 98 struct {
@@ -166,6 +167,13 @@ static struct protection_domain *to_pdomain(struct iommu_domain *dom)
166 return container_of(dom, struct protection_domain, domain); 167 return container_of(dom, struct protection_domain, domain);
167} 168}
168 169
170static inline u16 get_device_id(struct device *dev)
171{
172 struct pci_dev *pdev = to_pci_dev(dev);
173
174 return PCI_DEVID(pdev->bus->number, pdev->devfn);
175}
176
169static struct iommu_dev_data *alloc_dev_data(u16 devid) 177static struct iommu_dev_data *alloc_dev_data(u16 devid)
170{ 178{
171 struct iommu_dev_data *dev_data; 179 struct iommu_dev_data *dev_data;
@@ -203,6 +211,68 @@ out_unlock:
203 return dev_data; 211 return dev_data;
204} 212}
205 213
214static int __last_alias(struct pci_dev *pdev, u16 alias, void *data)
215{
216 *(u16 *)data = alias;
217 return 0;
218}
219
220static u16 get_alias(struct device *dev)
221{
222 struct pci_dev *pdev = to_pci_dev(dev);
223 u16 devid, ivrs_alias, pci_alias;
224
225 devid = get_device_id(dev);
226 ivrs_alias = amd_iommu_alias_table[devid];
227 pci_for_each_dma_alias(pdev, __last_alias, &pci_alias);
228
229 if (ivrs_alias == pci_alias)
230 return ivrs_alias;
231
232 /*
233 * DMA alias showdown
234 *
235 * The IVRS is fairly reliable in telling us about aliases, but it
236 * can't know about every screwy device. If we don't have an IVRS
237 * reported alias, use the PCI reported alias. In that case we may
238 * still need to initialize the rlookup and dev_table entries if the
239 * alias is to a non-existent device.
240 */
241 if (ivrs_alias == devid) {
242 if (!amd_iommu_rlookup_table[pci_alias]) {
243 amd_iommu_rlookup_table[pci_alias] =
244 amd_iommu_rlookup_table[devid];
245 memcpy(amd_iommu_dev_table[pci_alias].data,
246 amd_iommu_dev_table[devid].data,
247 sizeof(amd_iommu_dev_table[pci_alias].data));
248 }
249
250 return pci_alias;
251 }
252
253 pr_info("AMD-Vi: Using IVRS reported alias %02x:%02x.%d "
254 "for device %s[%04x:%04x], kernel reported alias "
255 "%02x:%02x.%d\n", PCI_BUS_NUM(ivrs_alias), PCI_SLOT(ivrs_alias),
256 PCI_FUNC(ivrs_alias), dev_name(dev), pdev->vendor, pdev->device,
257 PCI_BUS_NUM(pci_alias), PCI_SLOT(pci_alias),
258 PCI_FUNC(pci_alias));
259
260 /*
261 * If we don't have a PCI DMA alias and the IVRS alias is on the same
262 * bus, then the IVRS table may know about a quirk that we don't.
263 */
264 if (pci_alias == devid &&
265 PCI_BUS_NUM(ivrs_alias) == pdev->bus->number) {
266 pdev->dev_flags |= PCI_DEV_FLAGS_DMA_ALIAS_DEVFN;
267 pdev->dma_alias_devfn = ivrs_alias & 0xff;
268 pr_info("AMD-Vi: Added PCI DMA alias %02x.%d for %s\n",
269 PCI_SLOT(ivrs_alias), PCI_FUNC(ivrs_alias),
270 dev_name(dev));
271 }
272
273 return ivrs_alias;
274}
275
206static struct iommu_dev_data *find_dev_data(u16 devid) 276static struct iommu_dev_data *find_dev_data(u16 devid)
207{ 277{
208 struct iommu_dev_data *dev_data; 278 struct iommu_dev_data *dev_data;
@@ -215,13 +285,6 @@ static struct iommu_dev_data *find_dev_data(u16 devid)
215 return dev_data; 285 return dev_data;
216} 286}
217 287
218static inline u16 get_device_id(struct device *dev)
219{
220 struct pci_dev *pdev = to_pci_dev(dev);
221
222 return PCI_DEVID(pdev->bus->number, pdev->devfn);
223}
224
225static struct iommu_dev_data *get_dev_data(struct device *dev) 288static struct iommu_dev_data *get_dev_data(struct device *dev)
226{ 289{
227 return dev->archdata.iommu; 290 return dev->archdata.iommu;
@@ -349,6 +412,8 @@ static int iommu_init_device(struct device *dev)
349 if (!dev_data) 412 if (!dev_data)
350 return -ENOMEM; 413 return -ENOMEM;
351 414
415 dev_data->alias = get_alias(dev);
416
352 if (pci_iommuv2_capable(pdev)) { 417 if (pci_iommuv2_capable(pdev)) {
353 struct amd_iommu *iommu; 418 struct amd_iommu *iommu;
354 419
@@ -369,7 +434,7 @@ static void iommu_ignore_device(struct device *dev)
369 u16 devid, alias; 434 u16 devid, alias;
370 435
371 devid = get_device_id(dev); 436 devid = get_device_id(dev);
372 alias = amd_iommu_alias_table[devid]; 437 alias = get_alias(dev);
373 438
374 memset(&amd_iommu_dev_table[devid], 0, sizeof(struct dev_table_entry)); 439 memset(&amd_iommu_dev_table[devid], 0, sizeof(struct dev_table_entry));
375 memset(&amd_iommu_dev_table[alias], 0, sizeof(struct dev_table_entry)); 440 memset(&amd_iommu_dev_table[alias], 0, sizeof(struct dev_table_entry));
@@ -1061,7 +1126,7 @@ static int device_flush_dte(struct iommu_dev_data *dev_data)
1061 int ret; 1126 int ret;
1062 1127
1063 iommu = amd_iommu_rlookup_table[dev_data->devid]; 1128 iommu = amd_iommu_rlookup_table[dev_data->devid];
1064 alias = amd_iommu_alias_table[dev_data->devid]; 1129 alias = dev_data->alias;
1065 1130
1066 ret = iommu_flush_dte(iommu, dev_data->devid); 1131 ret = iommu_flush_dte(iommu, dev_data->devid);
1067 if (!ret && alias != dev_data->devid) 1132 if (!ret && alias != dev_data->devid)
@@ -2039,7 +2104,7 @@ static void do_attach(struct iommu_dev_data *dev_data,
2039 bool ats; 2104 bool ats;
2040 2105
2041 iommu = amd_iommu_rlookup_table[dev_data->devid]; 2106 iommu = amd_iommu_rlookup_table[dev_data->devid];
2042 alias = amd_iommu_alias_table[dev_data->devid]; 2107 alias = dev_data->alias;
2043 ats = dev_data->ats.enabled; 2108 ats = dev_data->ats.enabled;
2044 2109
2045 /* Update data structures */ 2110 /* Update data structures */
@@ -2073,7 +2138,7 @@ static void do_detach(struct iommu_dev_data *dev_data)
2073 return; 2138 return;
2074 2139
2075 iommu = amd_iommu_rlookup_table[dev_data->devid]; 2140 iommu = amd_iommu_rlookup_table[dev_data->devid];
2076 alias = amd_iommu_alias_table[dev_data->devid]; 2141 alias = dev_data->alias;
2077 2142
2078 /* decrease reference counters */ 2143 /* decrease reference counters */
2079 dev_data->domain->dev_iommu[iommu->index] -= 1; 2144 dev_data->domain->dev_iommu[iommu->index] -= 1;