aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Williamson <alex.williamson@redhat.com>2014-07-03 11:51:30 -0400
committerJoerg Roedel <jroedel@suse.de>2014-07-04 06:35:58 -0400
commit65d5352f12e16dc9321b1e4f8213793565c124be (patch)
tree959786bc1c8f4a24a2a259e5362eafd08b596a61
parentc1931090a22b96b223f2a3b8420076f044da7531 (diff)
iommu/amd: Use iommu_group_get_for_dev()
The common iommu_group_get_for_dev() allows us to greatly simplify our group lookup for a new device. Also, since we insert IVRS aliases into the PCI DMA alias quirks, we should alway come up with the same results as the existing code. Signed-off-by: Alex Williamson <alex.williamson@redhat.com> Cc: Joerg Roedel <joro@8bytes.org> Signed-off-by: Joerg Roedel <jroedel@suse.de>
-rw-r--r--drivers/iommu/amd_iommu.c164
-rw-r--r--drivers/iommu/amd_iommu_types.h1
2 files changed, 5 insertions, 160 deletions
diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index 25d7571dfc1c..2e03c17c2499 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -46,7 +46,6 @@
46#include "amd_iommu_proto.h" 46#include "amd_iommu_proto.h"
47#include "amd_iommu_types.h" 47#include "amd_iommu_types.h"
48#include "irq_remapping.h" 48#include "irq_remapping.h"
49#include "pci.h"
50 49
51#define CMD_SET_TYPE(cmd, t) ((cmd)->data[1] |= ((t) << 28)) 50#define CMD_SET_TYPE(cmd, t) ((cmd)->data[1] |= ((t) << 28))
52 51
@@ -133,9 +132,6 @@ static void free_dev_data(struct iommu_dev_data *dev_data)
133 list_del(&dev_data->dev_data_list); 132 list_del(&dev_data->dev_data_list);
134 spin_unlock_irqrestore(&dev_data_list_lock, flags); 133 spin_unlock_irqrestore(&dev_data_list_lock, flags);
135 134
136 if (dev_data->group)
137 iommu_group_put(dev_data->group);
138
139 kfree(dev_data); 135 kfree(dev_data);
140} 136}
141 137
@@ -264,167 +260,17 @@ static bool check_device(struct device *dev)
264 return true; 260 return true;
265} 261}
266 262
267static struct pci_bus *find_hosted_bus(struct pci_bus *bus)
268{
269 while (!bus->self) {
270 if (!pci_is_root_bus(bus))
271 bus = bus->parent;
272 else
273 return ERR_PTR(-ENODEV);
274 }
275
276 return bus;
277}
278
279#define REQ_ACS_FLAGS (PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF)
280
281static struct pci_dev *get_isolation_root(struct pci_dev *pdev)
282{
283 struct pci_dev *dma_pdev = pdev;
284
285 /* Account for quirked devices */
286 swap_pci_ref(&dma_pdev, pci_get_dma_source(dma_pdev));
287
288 /*
289 * If it's a multifunction device that does not support our
290 * required ACS flags, add to the same group as lowest numbered
291 * function that also does not suport the required ACS flags.
292 */
293 if (dma_pdev->multifunction &&
294 !pci_acs_enabled(dma_pdev, REQ_ACS_FLAGS)) {
295 u8 i, slot = PCI_SLOT(dma_pdev->devfn);
296
297 for (i = 0; i < 8; i++) {
298 struct pci_dev *tmp;
299
300 tmp = pci_get_slot(dma_pdev->bus, PCI_DEVFN(slot, i));
301 if (!tmp)
302 continue;
303
304 if (!pci_acs_enabled(tmp, REQ_ACS_FLAGS)) {
305 swap_pci_ref(&dma_pdev, tmp);
306 break;
307 }
308 pci_dev_put(tmp);
309 }
310 }
311
312 /*
313 * Devices on the root bus go through the iommu. If that's not us,
314 * find the next upstream device and test ACS up to the root bus.
315 * Finding the next device may require skipping virtual buses.
316 */
317 while (!pci_is_root_bus(dma_pdev->bus)) {
318 struct pci_bus *bus = find_hosted_bus(dma_pdev->bus);
319 if (IS_ERR(bus))
320 break;
321
322 if (pci_acs_path_enabled(bus->self, NULL, REQ_ACS_FLAGS))
323 break;
324
325 swap_pci_ref(&dma_pdev, pci_dev_get(bus->self));
326 }
327
328 return dma_pdev;
329}
330
331static int use_pdev_iommu_group(struct pci_dev *pdev, struct device *dev)
332{
333 struct iommu_group *group = iommu_group_get(&pdev->dev);
334 int ret;
335
336 if (!group) {
337 group = iommu_group_alloc();
338 if (IS_ERR(group))
339 return PTR_ERR(group);
340
341 WARN_ON(&pdev->dev != dev);
342 }
343
344 ret = iommu_group_add_device(group, dev);
345 iommu_group_put(group);
346 return ret;
347}
348
349static int use_dev_data_iommu_group(struct iommu_dev_data *dev_data,
350 struct device *dev)
351{
352 if (!dev_data->group) {
353 struct iommu_group *group = iommu_group_alloc();
354 if (IS_ERR(group))
355 return PTR_ERR(group);
356
357 dev_data->group = group;
358 }
359
360 return iommu_group_add_device(dev_data->group, dev);
361}
362
363static int init_iommu_group(struct device *dev) 263static int init_iommu_group(struct device *dev)
364{ 264{
365 struct iommu_dev_data *dev_data;
366 struct iommu_group *group; 265 struct iommu_group *group;
367 struct pci_dev *dma_pdev;
368 int ret;
369 266
370 group = iommu_group_get(dev); 267 group = iommu_group_get_for_dev(dev);
371 if (group) {
372 iommu_group_put(group);
373 return 0;
374 }
375 268
376 dev_data = find_dev_data(get_device_id(dev)); 269 if (IS_ERR(group))
377 if (!dev_data) 270 return PTR_ERR(group);
378 return -ENOMEM;
379
380 if (dev_data->alias_data) {
381 u16 alias;
382 struct pci_bus *bus;
383
384 if (dev_data->alias_data->group)
385 goto use_group;
386 271
387 /* 272 iommu_group_put(group);
388 * If the alias device exists, it's effectively just a first 273 return 0;
389 * level quirk for finding the DMA source.
390 */
391 alias = amd_iommu_alias_table[dev_data->devid];
392 dma_pdev = pci_get_bus_and_slot(alias >> 8, alias & 0xff);
393 if (dma_pdev) {
394 dma_pdev = get_isolation_root(dma_pdev);
395 goto use_pdev;
396 }
397
398 /*
399 * If the alias is virtual, try to find a parent device
400 * and test whether the IOMMU group is actualy rooted above
401 * the alias. Be careful to also test the parent device if
402 * we think the alias is the root of the group.
403 */
404 bus = pci_find_bus(0, alias >> 8);
405 if (!bus)
406 goto use_group;
407
408 bus = find_hosted_bus(bus);
409 if (IS_ERR(bus) || !bus->self)
410 goto use_group;
411
412 dma_pdev = get_isolation_root(pci_dev_get(bus->self));
413 if (dma_pdev != bus->self || (dma_pdev->multifunction &&
414 !pci_acs_enabled(dma_pdev, REQ_ACS_FLAGS)))
415 goto use_pdev;
416
417 pci_dev_put(dma_pdev);
418 goto use_group;
419 }
420
421 dma_pdev = get_isolation_root(pci_dev_get(to_pci_dev(dev)));
422use_pdev:
423 ret = use_pdev_iommu_group(dma_pdev, dev);
424 pci_dev_put(dma_pdev);
425 return ret;
426use_group:
427 return use_dev_data_iommu_group(dev_data->alias_data, dev);
428} 274}
429 275
430static int __last_alias(struct pci_dev *pdev, u16 alias, void *data) 276static int __last_alias(struct pci_dev *pdev, u16 alias, void *data)
diff --git a/drivers/iommu/amd_iommu_types.h b/drivers/iommu/amd_iommu_types.h
index f1a5abf11acf..7277a200d916 100644
--- a/drivers/iommu/amd_iommu_types.h
+++ b/drivers/iommu/amd_iommu_types.h
@@ -432,7 +432,6 @@ struct iommu_dev_data {
432 struct iommu_dev_data *alias_data;/* The alias dev_data */ 432 struct iommu_dev_data *alias_data;/* The alias dev_data */
433 struct protection_domain *domain; /* Domain the device is bound to */ 433 struct protection_domain *domain; /* Domain the device is bound to */
434 atomic_t bind; /* Domain attach reference count */ 434 atomic_t bind; /* Domain attach reference count */
435 struct iommu_group *group; /* IOMMU group for virtual aliases */
436 u16 devid; /* PCI Device ID */ 435 u16 devid; /* PCI Device ID */
437 bool iommu_v2; /* Device can make use of IOMMUv2 */ 436 bool iommu_v2; /* Device can make use of IOMMUv2 */
438 bool passthrough; /* Default for device is pt_domain */ 437 bool passthrough; /* Default for device is pt_domain */