Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 23971bdf authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull IOMMU updates from Joerg Roedel:
 "This pull-request includes:

   - change in the IOMMU-API to convert the former iommu_domain_capable
     function to just iommu_capable

   - various fixes in handling RMRR ranges for the VT-d driver (one fix
     requires a device driver core change which was acked by Greg KH)

   - the AMD IOMMU driver now assigns and deassigns complete alias
     groups to fix issues with devices using the wrong PCI request-id

   - MMU-401 support for the ARM SMMU driver

   - multi-master IOMMU group support for the ARM SMMU driver

   - various other small fixes all over the place"

* tag 'iommu-updates-v3.18' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu: (41 commits)
  iommu/vt-d: Work around broken RMRR firmware entries
  iommu/vt-d: Store bus information in RMRR PCI device path
  iommu/vt-d: Only remove domain when device is removed
  driver core: Add BUS_NOTIFY_REMOVED_DEVICE event
  iommu/amd: Fix devid mapping for ivrs_ioapic override
  iommu/irq_remapping: Fix the regression of hpet irq remapping
  iommu: Fix bus notifier breakage
  iommu/amd: Split init_iommu_group() from iommu_init_device()
  iommu: Rework iommu_group_get_for_pci_dev()
  iommu: Make of_device_id array const
  amd_iommu: do not dereference a NULL pointer address.
  iommu/omap: Remove omap_iommu unused owner field
  iommu: Remove iommu_domain_has_cap() API function
  IB/usnic: Convert to use new iommu_capable() API function
  vfio: Convert to use new iommu_capable() API function
  kvm: iommu: Convert to use new iommu_capable() API function
  iommu/tegra: Convert to iommu_capable() API function
  iommu/msm: Convert to iommu_capable() API function
  iommu/vt-d: Convert to iommu_capable() API function
  iommu/fsl: Convert to iommu_capable() API function
  ...
parents c0fa2373 09b5269a
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@ conditions.
                        "arm,smmu-v1"
                        "arm,smmu-v2"
                        "arm,mmu-400"
                        "arm,mmu-401"
                        "arm,mmu-500"

                  depending on the particular implementation and/or the
+3 −0
Original line number Diff line number Diff line
@@ -1211,6 +1211,9 @@ void device_del(struct device *dev)
	 */
	if (platform_notify_remove)
		platform_notify_remove(dev);
	if (dev->bus)
		blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
					     BUS_NOTIFY_REMOVED_DEVICE, dev);
	kobject_uevent(&dev->kobj, KOBJ_REMOVE);
	cleanup_device_parent(dev);
	kobject_del(&dev->kobj);
+1 −1
Original line number Diff line number Diff line
@@ -507,7 +507,7 @@ int usnic_uiom_attach_dev_to_pd(struct usnic_uiom_pd *pd, struct device *dev)
	if (err)
		goto out_free_dev;

	if (!iommu_domain_has_cap(pd->domain, IOMMU_CAP_CACHE_COHERENCY)) {
	if (!iommu_capable(dev->bus, IOMMU_CAP_CACHE_COHERENCY)) {
		usnic_err("IOMMU of %s does not support cache coherency\n",
				dev_name(dev));
		err = -EINVAL;
+68 −49
Original line number Diff line number Diff line
@@ -87,6 +87,27 @@ int amd_iommu_max_glx_val = -1;

static struct dma_map_ops amd_iommu_dma_ops;

/*
 * This struct contains device specific data for the IOMMU
 */
struct iommu_dev_data {
	struct list_head list;		  /* For domain->dev_list */
	struct list_head dev_data_list;	  /* For global dev_data_list */
	struct list_head alias_list;      /* Link alias-groups together */
	struct iommu_dev_data *alias_data;/* The alias dev_data */
	struct protection_domain *domain; /* Domain the device is bound to */
	u16 devid;			  /* PCI Device ID */
	bool iommu_v2;			  /* Device can make use of IOMMUv2 */
	bool passthrough;		  /* Default for device is pt_domain */
	struct {
		bool enabled;
		int qdep;
	} ats;				  /* ATS state */
	bool pri_tlp;			  /* PASID TLB required for
					     PPR completions */
	u32 errata;			  /* Bitmap for errata to apply */
};

/*
 * general struct to manage commands send to an IOMMU
 */
@@ -114,8 +135,9 @@ static struct iommu_dev_data *alloc_dev_data(u16 devid)
	if (!dev_data)
		return NULL;

	INIT_LIST_HEAD(&dev_data->alias_list);

	dev_data->devid = devid;
	atomic_set(&dev_data->bind, 0);

	spin_lock_irqsave(&dev_data_list_lock, flags);
	list_add_tail(&dev_data->dev_data_list, &dev_data_list);
@@ -260,17 +282,13 @@ static bool check_device(struct device *dev)
	return true;
}

static int init_iommu_group(struct device *dev)
static void init_iommu_group(struct device *dev)
{
	struct iommu_group *group;

	group = iommu_group_get_for_dev(dev);

	if (IS_ERR(group))
		return PTR_ERR(group);

	if (!IS_ERR(group))
		iommu_group_put(group);
	return 0;
}

static int __last_alias(struct pci_dev *pdev, u16 alias, void *data)
@@ -340,7 +358,6 @@ static int iommu_init_device(struct device *dev)
	struct pci_dev *pdev = to_pci_dev(dev);
	struct iommu_dev_data *dev_data;
	u16 alias;
	int ret;

	if (dev->archdata.iommu)
		return 0;
@@ -362,12 +379,9 @@ static int iommu_init_device(struct device *dev)
			return -ENOTSUPP;
		}
		dev_data->alias_data = alias_data;
	}

	ret = init_iommu_group(dev);
	if (ret) {
		free_dev_data(dev_data);
		return ret;
		/* Add device to the alias_list */
		list_add(&dev_data->alias_list, &alias_data->alias_list);
	}

	if (pci_iommuv2_capable(pdev)) {
@@ -455,6 +469,15 @@ int __init amd_iommu_init_devices(void)
			goto out_free;
	}

	/*
	 * Initialize IOMMU groups only after iommu_init_device() has
	 * had a chance to populate any IVRS defined aliases.
	 */
	for_each_pci_dev(pdev) {
		if (check_device(&pdev->dev))
			init_iommu_group(&pdev->dev);
	}

	return 0;

out_free:
@@ -1368,6 +1391,9 @@ static int iommu_map_page(struct protection_domain *dom,
	count     = PAGE_SIZE_PTE_COUNT(page_size);
	pte       = alloc_pte(dom, bus_addr, page_size, NULL, GFP_KERNEL);

	if (!pte)
		return -ENOMEM;

	for (i = 0; i < count; ++i)
		if (IOMMU_PTE_PRESENT(pte[i]))
			return -EBUSY;
@@ -2122,35 +2148,29 @@ static void do_detach(struct iommu_dev_data *dev_data)
static int __attach_device(struct iommu_dev_data *dev_data,
			   struct protection_domain *domain)
{
	struct iommu_dev_data *head, *entry;
	int ret;

	/* lock domain */
	spin_lock(&domain->lock);

	if (dev_data->alias_data != NULL) {
		struct iommu_dev_data *alias_data = dev_data->alias_data;

		/* Some sanity checks */
		ret = -EBUSY;
		if (alias_data->domain != NULL &&
				alias_data->domain != domain)
			goto out_unlock;
	head = dev_data;

		if (dev_data->domain != NULL &&
				dev_data->domain != domain)
			goto out_unlock;
	if (head->alias_data != NULL)
		head = head->alias_data;

		/* Do real assignment */
		if (alias_data->domain == NULL)
			do_attach(alias_data, domain);
	/* Now we have the root of the alias group, if any */

		atomic_inc(&alias_data->bind);
	}
	ret = -EBUSY;
	if (head->domain != NULL)
		goto out_unlock;

	if (dev_data->domain == NULL)
		do_attach(dev_data, domain);
	/* Attach alias group root */
	do_attach(head, domain);

	atomic_inc(&dev_data->bind);
	/* Attach other devices in the alias group */
	list_for_each_entry(entry, &head->alias_list, alias_list)
		do_attach(entry, domain);

	ret = 0;

@@ -2298,6 +2318,7 @@ static int attach_device(struct device *dev,
 */
static void __detach_device(struct iommu_dev_data *dev_data)
{
	struct iommu_dev_data *head, *entry;
	struct protection_domain *domain;
	unsigned long flags;

@@ -2307,15 +2328,14 @@ static void __detach_device(struct iommu_dev_data *dev_data)

	spin_lock_irqsave(&domain->lock, flags);

	if (dev_data->alias_data != NULL) {
		struct iommu_dev_data *alias_data = dev_data->alias_data;
	head = dev_data;
	if (head->alias_data != NULL)
		head = head->alias_data;

		if (atomic_dec_and_test(&alias_data->bind))
			do_detach(alias_data);
	}
	list_for_each_entry(entry, &head->alias_list, alias_list)
		do_detach(entry);

	if (atomic_dec_and_test(&dev_data->bind))
		do_detach(dev_data);
	do_detach(head);

	spin_unlock_irqrestore(&domain->lock, flags);

@@ -2415,6 +2435,7 @@ static int device_change_notifier(struct notifier_block *nb,
	case BUS_NOTIFY_ADD_DEVICE:

		iommu_init_device(dev);
		init_iommu_group(dev);

		/*
		 * dev_data is still NULL and
@@ -3158,7 +3179,6 @@ static void cleanup_domain(struct protection_domain *domain)
		entry = list_first_entry(&domain->dev_list,
					 struct iommu_dev_data, list);
		__detach_device(entry);
		atomic_set(&entry->bind, 0);
	}

	write_unlock_irqrestore(&amd_iommu_devtable_lock, flags);
@@ -3384,20 +3404,20 @@ static phys_addr_t amd_iommu_iova_to_phys(struct iommu_domain *dom,
	return paddr;
}

static int amd_iommu_domain_has_cap(struct iommu_domain *domain,
				    unsigned long cap)
static bool amd_iommu_capable(enum iommu_cap cap)
{
	switch (cap) {
	case IOMMU_CAP_CACHE_COHERENCY:
		return 1;
		return true;
	case IOMMU_CAP_INTR_REMAP:
		return irq_remapping_enabled;
		return (irq_remapping_enabled == 1);
	}

	return 0;
	return false;
}

static const struct iommu_ops amd_iommu_ops = {
	.capable = amd_iommu_capable,
	.domain_init = amd_iommu_domain_init,
	.domain_destroy = amd_iommu_domain_destroy,
	.attach_dev = amd_iommu_attach_device,
@@ -3405,7 +3425,6 @@ static const struct iommu_ops amd_iommu_ops = {
	.map = amd_iommu_map,
	.unmap = amd_iommu_unmap,
	.iova_to_phys = amd_iommu_iova_to_phys,
	.domain_has_cap = amd_iommu_domain_has_cap,
	.pgsize_bitmap	= AMD_IOMMU_PGSIZES,
};

@@ -4235,7 +4254,7 @@ static int msi_setup_irq(struct pci_dev *pdev, unsigned int irq,
	return 0;
}

static int setup_hpet_msi(unsigned int irq, unsigned int id)
static int alloc_hpet_msi(unsigned int irq, unsigned int id)
{
	struct irq_2_irte *irte_info;
	struct irq_cfg *cfg;
@@ -4274,6 +4293,6 @@ struct irq_remap_ops amd_iommu_irq_ops = {
	.compose_msi_msg	= compose_msi_msg,
	.msi_alloc_irq		= msi_alloc_irq,
	.msi_setup_irq		= msi_setup_irq,
	.setup_hpet_msi		= setup_hpet_msi,
	.alloc_hpet_msi		= alloc_hpet_msi,
};
#endif
+15 −6
Original line number Diff line number Diff line
@@ -712,7 +712,7 @@ static void __init set_dev_entry_from_acpi(struct amd_iommu *iommu,
	set_iommu_for_device(iommu, devid);
}

static int __init add_special_device(u8 type, u8 id, u16 devid, bool cmd_line)
static int __init add_special_device(u8 type, u8 id, u16 *devid, bool cmd_line)
{
	struct devid_map *entry;
	struct list_head *list;
@@ -731,6 +731,8 @@ static int __init add_special_device(u8 type, u8 id, u16 devid, bool cmd_line)
		pr_info("AMD-Vi: Command-line override present for %s id %d - ignoring\n",
			type == IVHD_SPECIAL_IOAPIC ? "IOAPIC" : "HPET", id);

		*devid = entry->devid;

		return 0;
	}

@@ -739,7 +741,7 @@ static int __init add_special_device(u8 type, u8 id, u16 devid, bool cmd_line)
		return -ENOMEM;

	entry->id	= id;
	entry->devid	= devid;
	entry->devid	= *devid;
	entry->cmd_line	= cmd_line;

	list_add_tail(&entry->list, list);
@@ -754,7 +756,7 @@ static int __init add_early_maps(void)
	for (i = 0; i < early_ioapic_map_size; ++i) {
		ret = add_special_device(IVHD_SPECIAL_IOAPIC,
					 early_ioapic_map[i].id,
					 early_ioapic_map[i].devid,
					 &early_ioapic_map[i].devid,
					 early_ioapic_map[i].cmd_line);
		if (ret)
			return ret;
@@ -763,7 +765,7 @@ static int __init add_early_maps(void)
	for (i = 0; i < early_hpet_map_size; ++i) {
		ret = add_special_device(IVHD_SPECIAL_HPET,
					 early_hpet_map[i].id,
					 early_hpet_map[i].devid,
					 &early_hpet_map[i].devid,
					 early_hpet_map[i].cmd_line);
		if (ret)
			return ret;
@@ -978,10 +980,17 @@ static int __init init_iommu_from_acpi(struct amd_iommu *iommu,
				    PCI_SLOT(devid),
				    PCI_FUNC(devid));

			set_dev_entry_from_acpi(iommu, devid, e->flags, 0);
			ret = add_special_device(type, handle, devid, false);
			ret = add_special_device(type, handle, &devid, false);
			if (ret)
				return ret;

			/*
			 * add_special_device might update the devid in case a
			 * command-line override is present. So call
			 * set_dev_entry_from_acpi after add_special_device.
			 */
			set_dev_entry_from_acpi(iommu, devid, e->flags, 0);

			break;
		}
		default:
Loading