Commit 213e4eb2 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'iommu-fixes-v4.11-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu

Pull IOMMU fixes from Joerg Roedel:
 "A few fixes piled up:

   - fix a NULL-ptr dereference that happens in VT-d on some platforms

   - a fix for ARM MSI region reporting, so that a sane interface makes
     it to a released kernel

   - fixes for leaf-checking in ARM io-page-table code

   - two fixes for IO/TLB flushing code on ARM Exynos platforms"

* tag 'iommu-fixes-v4.11-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu:
  iommu: Disambiguate MSI region types
  iommu/exynos: Workaround FLPD cache flush issues for SYSMMU v5
  iommu/exynos: Block SYSMMU while invalidating FLPD cache
  iommu/vt-d: Fix NULL pointer dereference in device_to_iommu
  iommu/io-pgtable-arm-v7s: Check for leaf entry before dereferencing it
  iommu/io-pgtable-arm: Check for leaf entry before dereferencing it
parents 9a31328f 11cd3386
...@@ -3202,7 +3202,7 @@ static void amd_iommu_get_resv_regions(struct device *dev, ...@@ -3202,7 +3202,7 @@ static void amd_iommu_get_resv_regions(struct device *dev,
region = iommu_alloc_resv_region(MSI_RANGE_START, region = iommu_alloc_resv_region(MSI_RANGE_START,
MSI_RANGE_END - MSI_RANGE_START + 1, MSI_RANGE_END - MSI_RANGE_START + 1,
0, IOMMU_RESV_RESERVED); 0, IOMMU_RESV_MSI);
if (!region) if (!region)
return; return;
list_add_tail(&region->list, head); list_add_tail(&region->list, head);
......
...@@ -1888,7 +1888,7 @@ static void arm_smmu_get_resv_regions(struct device *dev, ...@@ -1888,7 +1888,7 @@ static void arm_smmu_get_resv_regions(struct device *dev,
int prot = IOMMU_WRITE | IOMMU_NOEXEC | IOMMU_MMIO; int prot = IOMMU_WRITE | IOMMU_NOEXEC | IOMMU_MMIO;
region = iommu_alloc_resv_region(MSI_IOVA_BASE, MSI_IOVA_LENGTH, region = iommu_alloc_resv_region(MSI_IOVA_BASE, MSI_IOVA_LENGTH,
prot, IOMMU_RESV_MSI); prot, IOMMU_RESV_SW_MSI);
if (!region) if (!region)
return; return;
......
...@@ -1608,7 +1608,7 @@ static void arm_smmu_get_resv_regions(struct device *dev, ...@@ -1608,7 +1608,7 @@ static void arm_smmu_get_resv_regions(struct device *dev,
int prot = IOMMU_WRITE | IOMMU_NOEXEC | IOMMU_MMIO; int prot = IOMMU_WRITE | IOMMU_NOEXEC | IOMMU_MMIO;
region = iommu_alloc_resv_region(MSI_IOVA_BASE, MSI_IOVA_LENGTH, region = iommu_alloc_resv_region(MSI_IOVA_BASE, MSI_IOVA_LENGTH,
prot, IOMMU_RESV_MSI); prot, IOMMU_RESV_SW_MSI);
if (!region) if (!region)
return; return;
......
...@@ -512,7 +512,13 @@ static void sysmmu_tlb_invalidate_flpdcache(struct sysmmu_drvdata *data, ...@@ -512,7 +512,13 @@ static void sysmmu_tlb_invalidate_flpdcache(struct sysmmu_drvdata *data,
spin_lock_irqsave(&data->lock, flags); spin_lock_irqsave(&data->lock, flags);
if (data->active && data->version >= MAKE_MMU_VER(3, 3)) { if (data->active && data->version >= MAKE_MMU_VER(3, 3)) {
clk_enable(data->clk_master); clk_enable(data->clk_master);
__sysmmu_tlb_invalidate_entry(data, iova, 1); if (sysmmu_block(data)) {
if (data->version >= MAKE_MMU_VER(5, 0))
__sysmmu_tlb_invalidate(data);
else
__sysmmu_tlb_invalidate_entry(data, iova, 1);
sysmmu_unblock(data);
}
clk_disable(data->clk_master); clk_disable(data->clk_master);
} }
spin_unlock_irqrestore(&data->lock, flags); spin_unlock_irqrestore(&data->lock, flags);
......
...@@ -916,7 +916,7 @@ static struct intel_iommu *device_to_iommu(struct device *dev, u8 *bus, u8 *devf ...@@ -916,7 +916,7 @@ static struct intel_iommu *device_to_iommu(struct device *dev, u8 *bus, u8 *devf
* which we used for the IOMMU lookup. Strictly speaking * which we used for the IOMMU lookup. Strictly speaking
* we could do this for all PCI devices; we only need to * we could do this for all PCI devices; we only need to
* get the BDF# from the scope table for ACPI matches. */ * get the BDF# from the scope table for ACPI matches. */
if (pdev->is_virtfn) if (pdev && pdev->is_virtfn)
goto got_pdev; goto got_pdev;
*bus = drhd->devices[i].bus; *bus = drhd->devices[i].bus;
...@@ -5249,7 +5249,7 @@ static void intel_iommu_get_resv_regions(struct device *device, ...@@ -5249,7 +5249,7 @@ static void intel_iommu_get_resv_regions(struct device *device,
reg = iommu_alloc_resv_region(IOAPIC_RANGE_START, reg = iommu_alloc_resv_region(IOAPIC_RANGE_START,
IOAPIC_RANGE_END - IOAPIC_RANGE_START + 1, IOAPIC_RANGE_END - IOAPIC_RANGE_START + 1,
0, IOMMU_RESV_RESERVED); 0, IOMMU_RESV_MSI);
if (!reg) if (!reg)
return; return;
list_add_tail(&reg->list, head); list_add_tail(&reg->list, head);
......
...@@ -422,8 +422,12 @@ static int __arm_v7s_map(struct arm_v7s_io_pgtable *data, unsigned long iova, ...@@ -422,8 +422,12 @@ static int __arm_v7s_map(struct arm_v7s_io_pgtable *data, unsigned long iova,
pte |= ARM_V7S_ATTR_NS_TABLE; pte |= ARM_V7S_ATTR_NS_TABLE;
__arm_v7s_set_pte(ptep, pte, 1, cfg); __arm_v7s_set_pte(ptep, pte, 1, cfg);
} else { } else if (ARM_V7S_PTE_IS_TABLE(pte, lvl)) {
cptep = iopte_deref(pte, lvl); cptep = iopte_deref(pte, lvl);
} else {
/* We require an unmap first */
WARN_ON(!selftest_running);
return -EEXIST;
} }
/* Rinse, repeat */ /* Rinse, repeat */
......
...@@ -335,8 +335,12 @@ static int __arm_lpae_map(struct arm_lpae_io_pgtable *data, unsigned long iova, ...@@ -335,8 +335,12 @@ static int __arm_lpae_map(struct arm_lpae_io_pgtable *data, unsigned long iova,
if (cfg->quirks & IO_PGTABLE_QUIRK_ARM_NS) if (cfg->quirks & IO_PGTABLE_QUIRK_ARM_NS)
pte |= ARM_LPAE_PTE_NSTABLE; pte |= ARM_LPAE_PTE_NSTABLE;
__arm_lpae_set_pte(ptep, pte, cfg); __arm_lpae_set_pte(ptep, pte, cfg);
} else { } else if (!iopte_leaf(pte, lvl)) {
cptep = iopte_deref(pte, data); cptep = iopte_deref(pte, data);
} else {
/* We require an unmap first */
WARN_ON(!selftest_running);
return -EEXIST;
} }
/* Rinse, repeat */ /* Rinse, repeat */
......
...@@ -72,6 +72,7 @@ static const char * const iommu_group_resv_type_string[] = { ...@@ -72,6 +72,7 @@ static const char * const iommu_group_resv_type_string[] = {
[IOMMU_RESV_DIRECT] = "direct", [IOMMU_RESV_DIRECT] = "direct",
[IOMMU_RESV_RESERVED] = "reserved", [IOMMU_RESV_RESERVED] = "reserved",
[IOMMU_RESV_MSI] = "msi", [IOMMU_RESV_MSI] = "msi",
[IOMMU_RESV_SW_MSI] = "msi",
}; };
#define IOMMU_GROUP_ATTR(_name, _mode, _show, _store) \ #define IOMMU_GROUP_ATTR(_name, _mode, _show, _store) \
...@@ -1743,8 +1744,8 @@ void iommu_put_resv_regions(struct device *dev, struct list_head *list) ...@@ -1743,8 +1744,8 @@ void iommu_put_resv_regions(struct device *dev, struct list_head *list)
} }
struct iommu_resv_region *iommu_alloc_resv_region(phys_addr_t start, struct iommu_resv_region *iommu_alloc_resv_region(phys_addr_t start,
size_t length, size_t length, int prot,
int prot, int type) enum iommu_resv_type type)
{ {
struct iommu_resv_region *region; struct iommu_resv_region *region;
......
...@@ -1182,8 +1182,7 @@ static struct vfio_group *find_iommu_group(struct vfio_domain *domain, ...@@ -1182,8 +1182,7 @@ static struct vfio_group *find_iommu_group(struct vfio_domain *domain,
return NULL; return NULL;
} }
static bool vfio_iommu_has_resv_msi(struct iommu_group *group, static bool vfio_iommu_has_sw_msi(struct iommu_group *group, phys_addr_t *base)
phys_addr_t *base)
{ {
struct list_head group_resv_regions; struct list_head group_resv_regions;
struct iommu_resv_region *region, *next; struct iommu_resv_region *region, *next;
...@@ -1192,7 +1191,7 @@ static bool vfio_iommu_has_resv_msi(struct iommu_group *group, ...@@ -1192,7 +1191,7 @@ static bool vfio_iommu_has_resv_msi(struct iommu_group *group,
INIT_LIST_HEAD(&group_resv_regions); INIT_LIST_HEAD(&group_resv_regions);
iommu_get_group_resv_regions(group, &group_resv_regions); iommu_get_group_resv_regions(group, &group_resv_regions);
list_for_each_entry(region, &group_resv_regions, list) { list_for_each_entry(region, &group_resv_regions, list) {
if (region->type & IOMMU_RESV_MSI) { if (region->type == IOMMU_RESV_SW_MSI) {
*base = region->start; *base = region->start;
ret = true; ret = true;
goto out; goto out;
...@@ -1283,7 +1282,7 @@ static int vfio_iommu_type1_attach_group(void *iommu_data, ...@@ -1283,7 +1282,7 @@ static int vfio_iommu_type1_attach_group(void *iommu_data,
if (ret) if (ret)
goto out_domain; goto out_domain;
resv_msi = vfio_iommu_has_resv_msi(iommu_group, &resv_msi_base); resv_msi = vfio_iommu_has_sw_msi(iommu_group, &resv_msi_base);
INIT_LIST_HEAD(&domain->group_list); INIT_LIST_HEAD(&domain->group_list);
list_add(&group->next, &domain->group_list); list_add(&group->next, &domain->group_list);
......
...@@ -125,9 +125,16 @@ enum iommu_attr { ...@@ -125,9 +125,16 @@ enum iommu_attr {
}; };
/* These are the possible reserved region types */ /* These are the possible reserved region types */
#define IOMMU_RESV_DIRECT (1 << 0) enum iommu_resv_type {
#define IOMMU_RESV_RESERVED (1 << 1) /* Memory regions which must be mapped 1:1 at all times */
#define IOMMU_RESV_MSI (1 << 2) IOMMU_RESV_DIRECT,
/* Arbitrary "never map this or give it to a device" address ranges */
IOMMU_RESV_RESERVED,
/* Hardware MSI region (untranslated) */
IOMMU_RESV_MSI,
/* Software-managed MSI translation window */
IOMMU_RESV_SW_MSI,
};
/** /**
* struct iommu_resv_region - descriptor for a reserved memory region * struct iommu_resv_region - descriptor for a reserved memory region
...@@ -142,7 +149,7 @@ struct iommu_resv_region { ...@@ -142,7 +149,7 @@ struct iommu_resv_region {
phys_addr_t start; phys_addr_t start;
size_t length; size_t length;
int prot; int prot;
int type; enum iommu_resv_type type;
}; };
#ifdef CONFIG_IOMMU_API #ifdef CONFIG_IOMMU_API
...@@ -288,7 +295,8 @@ extern void iommu_get_resv_regions(struct device *dev, struct list_head *list); ...@@ -288,7 +295,8 @@ extern void iommu_get_resv_regions(struct device *dev, struct list_head *list);
extern void iommu_put_resv_regions(struct device *dev, struct list_head *list); extern void iommu_put_resv_regions(struct device *dev, struct list_head *list);
extern int iommu_request_dm_for_dev(struct device *dev); extern int iommu_request_dm_for_dev(struct device *dev);
extern struct iommu_resv_region * extern struct iommu_resv_region *
iommu_alloc_resv_region(phys_addr_t start, size_t length, int prot, int type); iommu_alloc_resv_region(phys_addr_t start, size_t length, int prot,
enum iommu_resv_type type);
extern int iommu_get_group_resv_regions(struct iommu_group *group, extern int iommu_get_group_resv_regions(struct iommu_group *group,
struct list_head *head); struct list_head *head);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment