forked from Minki/linux
Merge branch 'iommu/fixes' into arm/mediatek
This commit is contained in:
commit
894901b5c9
@ -4452,6 +4452,7 @@ static int amd_ir_set_vcpu_affinity(struct irq_data *data, void *vcpu_info)
|
||||
/* Setting */
|
||||
irte->hi.fields.ga_root_ptr = (pi_data->base >> 12);
|
||||
irte->hi.fields.vector = vcpu_pi_info->vector;
|
||||
irte->lo.fields_vapic.ga_log_intr = 1;
|
||||
irte->lo.fields_vapic.guest_mode = 1;
|
||||
irte->lo.fields_vapic.ga_tag = pi_data->ga_tag;
|
||||
|
||||
|
@ -2440,11 +2440,11 @@ static int __init state_next(void)
|
||||
break;
|
||||
case IOMMU_ACPI_FINISHED:
|
||||
early_enable_iommus();
|
||||
register_syscore_ops(&amd_iommu_syscore_ops);
|
||||
x86_platform.iommu_shutdown = disable_iommus;
|
||||
init_state = IOMMU_ENABLED;
|
||||
break;
|
||||
case IOMMU_ENABLED:
|
||||
register_syscore_ops(&amd_iommu_syscore_ops);
|
||||
ret = amd_iommu_init_pci();
|
||||
init_state = ret ? IOMMU_INIT_ERROR : IOMMU_PCI_INIT;
|
||||
enable_iommus_v2();
|
||||
|
@ -574,7 +574,9 @@ struct amd_iommu {
|
||||
|
||||
static inline struct amd_iommu *dev_to_amd_iommu(struct device *dev)
|
||||
{
|
||||
return container_of(dev, struct amd_iommu, iommu.dev);
|
||||
struct iommu_device *iommu = dev_to_iommu_device(dev);
|
||||
|
||||
return container_of(iommu, struct amd_iommu, iommu);
|
||||
}
|
||||
|
||||
#define ACPIHID_UID_LEN 256
|
||||
|
@ -400,6 +400,8 @@ struct arm_smmu_device {
|
||||
|
||||
u32 cavium_id_base; /* Specific to Cavium */
|
||||
|
||||
spinlock_t global_sync_lock;
|
||||
|
||||
/* IOMMU core code handle */
|
||||
struct iommu_device iommu;
|
||||
};
|
||||
@ -436,7 +438,7 @@ struct arm_smmu_domain {
|
||||
struct arm_smmu_cfg cfg;
|
||||
enum arm_smmu_domain_stage stage;
|
||||
struct mutex init_mutex; /* Protects smmu pointer */
|
||||
spinlock_t cb_lock; /* Serialises ATS1* ops */
|
||||
spinlock_t cb_lock; /* Serialises ATS1* ops and TLB syncs */
|
||||
struct iommu_domain domain;
|
||||
};
|
||||
|
||||
@ -602,9 +604,12 @@ static void __arm_smmu_tlb_sync(struct arm_smmu_device *smmu,
|
||||
static void arm_smmu_tlb_sync_global(struct arm_smmu_device *smmu)
|
||||
{
|
||||
void __iomem *base = ARM_SMMU_GR0(smmu);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&smmu->global_sync_lock, flags);
|
||||
__arm_smmu_tlb_sync(smmu, base + ARM_SMMU_GR0_sTLBGSYNC,
|
||||
base + ARM_SMMU_GR0_sTLBGSTATUS);
|
||||
spin_unlock_irqrestore(&smmu->global_sync_lock, flags);
|
||||
}
|
||||
|
||||
static void arm_smmu_tlb_sync_context(void *cookie)
|
||||
@ -612,9 +617,12 @@ static void arm_smmu_tlb_sync_context(void *cookie)
|
||||
struct arm_smmu_domain *smmu_domain = cookie;
|
||||
struct arm_smmu_device *smmu = smmu_domain->smmu;
|
||||
void __iomem *base = ARM_SMMU_CB(smmu, smmu_domain->cfg.cbndx);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&smmu_domain->cb_lock, flags);
|
||||
__arm_smmu_tlb_sync(smmu, base + ARM_SMMU_CB_TLBSYNC,
|
||||
base + ARM_SMMU_CB_TLBSTATUS);
|
||||
spin_unlock_irqrestore(&smmu_domain->cb_lock, flags);
|
||||
}
|
||||
|
||||
static void arm_smmu_tlb_sync_vmid(void *cookie)
|
||||
@ -1511,6 +1519,12 @@ static int arm_smmu_add_device(struct device *dev)
|
||||
|
||||
if (using_legacy_binding) {
|
||||
ret = arm_smmu_register_legacy_master(dev, &smmu);
|
||||
|
||||
/*
|
||||
* If dev->iommu_fwspec is initally NULL, arm_smmu_register_legacy_master()
|
||||
* will allocate/initialise a new one. Thus we need to update fwspec for
|
||||
* later use.
|
||||
*/
|
||||
fwspec = dev->iommu_fwspec;
|
||||
if (ret)
|
||||
goto out_free;
|
||||
@ -1550,15 +1564,15 @@ static int arm_smmu_add_device(struct device *dev)
|
||||
|
||||
ret = arm_smmu_master_alloc_smes(dev);
|
||||
if (ret)
|
||||
goto out_free;
|
||||
goto out_cfg_free;
|
||||
|
||||
iommu_device_link(&smmu->iommu, dev);
|
||||
|
||||
return 0;
|
||||
|
||||
out_cfg_free:
|
||||
kfree(cfg);
|
||||
out_free:
|
||||
if (fwspec)
|
||||
kfree(fwspec->iommu_priv);
|
||||
iommu_fwspec_free(dev);
|
||||
return ret;
|
||||
}
|
||||
@ -1925,6 +1939,7 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu)
|
||||
|
||||
smmu->num_mapping_groups = size;
|
||||
mutex_init(&smmu->stream_map_mutex);
|
||||
spin_lock_init(&smmu->global_sync_lock);
|
||||
|
||||
if (smmu->version < ARM_SMMU_V2 || !(id & ID0_PTFS_NO_AARCH32)) {
|
||||
smmu->features |= ARM_SMMU_FEAT_FMT_AARCH32_L;
|
||||
|
@ -4736,7 +4736,9 @@ static void intel_disable_iommus(void)
|
||||
|
||||
static inline struct intel_iommu *dev_to_intel_iommu(struct device *dev)
|
||||
{
|
||||
return container_of(dev, struct intel_iommu, iommu.dev);
|
||||
struct iommu_device *iommu_dev = dev_to_iommu_device(dev);
|
||||
|
||||
return container_of(iommu_dev, struct intel_iommu, iommu);
|
||||
}
|
||||
|
||||
static ssize_t intel_iommu_show_version(struct device *dev,
|
||||
|
@ -479,6 +479,9 @@ static int arm_v7s_map(struct io_pgtable_ops *ops, unsigned long iova,
|
||||
if (!(prot & (IOMMU_READ | IOMMU_WRITE)))
|
||||
return 0;
|
||||
|
||||
if (WARN_ON(upper_32_bits(iova) || upper_32_bits(paddr)))
|
||||
return -ERANGE;
|
||||
|
||||
ret = __arm_v7s_map(data, iova, paddr, size, prot, 1, data->pgd);
|
||||
/*
|
||||
* Synchronise all PTE updates for the new mapping before there's
|
||||
@ -659,6 +662,9 @@ static int arm_v7s_unmap(struct io_pgtable_ops *ops, unsigned long iova,
|
||||
struct arm_v7s_io_pgtable *data = io_pgtable_ops_to_data(ops);
|
||||
size_t unmapped;
|
||||
|
||||
if (WARN_ON(upper_32_bits(iova)))
|
||||
return 0;
|
||||
|
||||
unmapped = __arm_v7s_unmap(data, iova, size, 1, data->pgd);
|
||||
if (unmapped)
|
||||
io_pgtable_tlb_sync(&data->iop);
|
||||
|
@ -452,6 +452,10 @@ static int arm_lpae_map(struct io_pgtable_ops *ops, unsigned long iova,
|
||||
if (!(iommu_prot & (IOMMU_READ | IOMMU_WRITE)))
|
||||
return 0;
|
||||
|
||||
if (WARN_ON(iova >= (1ULL << data->iop.cfg.ias) ||
|
||||
paddr >= (1ULL << data->iop.cfg.oas)))
|
||||
return -ERANGE;
|
||||
|
||||
prot = arm_lpae_prot_to_pte(data, iommu_prot);
|
||||
ret = __arm_lpae_map(data, iova, paddr, size, prot, lvl, ptep);
|
||||
/*
|
||||
@ -610,6 +614,9 @@ static int arm_lpae_unmap(struct io_pgtable_ops *ops, unsigned long iova,
|
||||
arm_lpae_iopte *ptep = data->pgd;
|
||||
int lvl = ARM_LPAE_START_LVL(data);
|
||||
|
||||
if (WARN_ON(iova >= (1ULL << data->iop.cfg.ias)))
|
||||
return 0;
|
||||
|
||||
unmapped = __arm_lpae_unmap(data, iova, size, lvl, ptep);
|
||||
if (unmapped)
|
||||
io_pgtable_tlb_sync(&data->iop);
|
||||
|
@ -158,14 +158,12 @@ void free_io_pgtable_ops(struct io_pgtable_ops *ops);
|
||||
* @fmt: The page table format.
|
||||
* @cookie: An opaque token provided by the IOMMU driver and passed back to
|
||||
* any callback routines.
|
||||
* @tlb_sync_pending: Private flag for optimising out redundant syncs.
|
||||
* @cfg: A copy of the page table configuration.
|
||||
* @ops: The page table operations in use for this set of page tables.
|
||||
*/
|
||||
struct io_pgtable {
|
||||
enum io_pgtable_fmt fmt;
|
||||
void *cookie;
|
||||
bool tlb_sync_pending;
|
||||
struct io_pgtable_cfg cfg;
|
||||
struct io_pgtable_ops ops;
|
||||
};
|
||||
@ -175,22 +173,17 @@ struct io_pgtable {
|
||||
static inline void io_pgtable_tlb_flush_all(struct io_pgtable *iop)
|
||||
{
|
||||
iop->cfg.tlb->tlb_flush_all(iop->cookie);
|
||||
iop->tlb_sync_pending = true;
|
||||
}
|
||||
|
||||
static inline void io_pgtable_tlb_add_flush(struct io_pgtable *iop,
|
||||
unsigned long iova, size_t size, size_t granule, bool leaf)
|
||||
{
|
||||
iop->cfg.tlb->tlb_add_flush(iova, size, granule, leaf, iop->cookie);
|
||||
iop->tlb_sync_pending = true;
|
||||
}
|
||||
|
||||
static inline void io_pgtable_tlb_sync(struct io_pgtable *iop)
|
||||
{
|
||||
if (iop->tlb_sync_pending) {
|
||||
iop->cfg.tlb->tlb_sync(iop->cookie);
|
||||
iop->tlb_sync_pending = false;
|
||||
}
|
||||
iop->cfg.tlb->tlb_sync(iop->cookie);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -62,32 +62,40 @@ int iommu_device_sysfs_add(struct iommu_device *iommu,
|
||||
va_list vargs;
|
||||
int ret;
|
||||
|
||||
device_initialize(&iommu->dev);
|
||||
iommu->dev = kzalloc(sizeof(*iommu->dev), GFP_KERNEL);
|
||||
if (!iommu->dev)
|
||||
return -ENOMEM;
|
||||
|
||||
iommu->dev.class = &iommu_class;
|
||||
iommu->dev.parent = parent;
|
||||
iommu->dev.groups = groups;
|
||||
device_initialize(iommu->dev);
|
||||
|
||||
iommu->dev->class = &iommu_class;
|
||||
iommu->dev->parent = parent;
|
||||
iommu->dev->groups = groups;
|
||||
|
||||
va_start(vargs, fmt);
|
||||
ret = kobject_set_name_vargs(&iommu->dev.kobj, fmt, vargs);
|
||||
ret = kobject_set_name_vargs(&iommu->dev->kobj, fmt, vargs);
|
||||
va_end(vargs);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
ret = device_add(&iommu->dev);
|
||||
ret = device_add(iommu->dev);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
dev_set_drvdata(iommu->dev, iommu);
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
put_device(&iommu->dev);
|
||||
put_device(iommu->dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void iommu_device_sysfs_remove(struct iommu_device *iommu)
|
||||
{
|
||||
device_unregister(&iommu->dev);
|
||||
dev_set_drvdata(iommu->dev, NULL);
|
||||
device_unregister(iommu->dev);
|
||||
iommu->dev = NULL;
|
||||
}
|
||||
/*
|
||||
* IOMMU drivers can indicate a device is managed by a given IOMMU using
|
||||
@ -102,14 +110,14 @@ int iommu_device_link(struct iommu_device *iommu, struct device *link)
|
||||
if (!iommu || IS_ERR(iommu))
|
||||
return -ENODEV;
|
||||
|
||||
ret = sysfs_add_link_to_group(&iommu->dev.kobj, "devices",
|
||||
ret = sysfs_add_link_to_group(&iommu->dev->kobj, "devices",
|
||||
&link->kobj, dev_name(link));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = sysfs_create_link_nowarn(&link->kobj, &iommu->dev.kobj, "iommu");
|
||||
ret = sysfs_create_link_nowarn(&link->kobj, &iommu->dev->kobj, "iommu");
|
||||
if (ret)
|
||||
sysfs_remove_link_from_group(&iommu->dev.kobj, "devices",
|
||||
sysfs_remove_link_from_group(&iommu->dev->kobj, "devices",
|
||||
dev_name(link));
|
||||
|
||||
return ret;
|
||||
@ -121,5 +129,5 @@ void iommu_device_unlink(struct iommu_device *iommu, struct device *link)
|
||||
return;
|
||||
|
||||
sysfs_remove_link(&link->kobj, "iommu");
|
||||
sysfs_remove_link_from_group(&iommu->dev.kobj, "devices", dev_name(link));
|
||||
sysfs_remove_link_from_group(&iommu->dev->kobj, "devices", dev_name(link));
|
||||
}
|
||||
|
@ -129,6 +129,7 @@ static void mtk_iommu_tlb_add_flush_nosync(unsigned long iova, size_t size,
|
||||
writel_relaxed(iova, data->base + REG_MMU_INVLD_START_A);
|
||||
writel_relaxed(iova + size - 1, data->base + REG_MMU_INVLD_END_A);
|
||||
writel_relaxed(F_MMU_INV_RANGE, data->base + REG_MMU_INVALIDATE);
|
||||
data->tlb_flush_active = true;
|
||||
}
|
||||
|
||||
static void mtk_iommu_tlb_sync(void *cookie)
|
||||
@ -137,6 +138,10 @@ static void mtk_iommu_tlb_sync(void *cookie)
|
||||
int ret;
|
||||
u32 tmp;
|
||||
|
||||
/* Avoid timing out if there's nothing to wait for */
|
||||
if (!data->tlb_flush_active)
|
||||
return;
|
||||
|
||||
ret = readl_poll_timeout_atomic(data->base + REG_MMU_CPE_DONE, tmp,
|
||||
tmp != 0, 10, 100000);
|
||||
if (ret) {
|
||||
@ -146,6 +151,7 @@ static void mtk_iommu_tlb_sync(void *cookie)
|
||||
}
|
||||
/* Clear the CPE status */
|
||||
writel_relaxed(0, data->base + REG_MMU_CPE_DONE);
|
||||
data->tlb_flush_active = false;
|
||||
}
|
||||
|
||||
static const struct iommu_gather_ops mtk_iommu_gather_ops = {
|
||||
|
@ -47,6 +47,7 @@ struct mtk_iommu_data {
|
||||
struct iommu_group *m4u_group;
|
||||
struct mtk_smi_iommu smi_imu; /* SMI larb iommu info */
|
||||
bool enable_4GB;
|
||||
bool tlb_flush_active;
|
||||
|
||||
struct iommu_device iommu;
|
||||
};
|
||||
|
@ -240,7 +240,7 @@ struct iommu_device {
|
||||
struct list_head list;
|
||||
const struct iommu_ops *ops;
|
||||
struct fwnode_handle *fwnode;
|
||||
struct device dev;
|
||||
struct device *dev;
|
||||
};
|
||||
|
||||
int iommu_device_register(struct iommu_device *iommu);
|
||||
@ -265,6 +265,11 @@ static inline void iommu_device_set_fwnode(struct iommu_device *iommu,
|
||||
iommu->fwnode = fwnode;
|
||||
}
|
||||
|
||||
static inline struct iommu_device *dev_to_iommu_device(struct device *dev)
|
||||
{
|
||||
return (struct iommu_device *)dev_get_drvdata(dev);
|
||||
}
|
||||
|
||||
#define IOMMU_GROUP_NOTIFY_ADD_DEVICE 1 /* Device added */
|
||||
#define IOMMU_GROUP_NOTIFY_DEL_DEVICE 2 /* Pre Device removed */
|
||||
#define IOMMU_GROUP_NOTIFY_BIND_DRIVER 3 /* Pre Driver bind */
|
||||
@ -589,6 +594,11 @@ static inline void iommu_device_set_fwnode(struct iommu_device *iommu,
|
||||
{
|
||||
}
|
||||
|
||||
static inline struct iommu_device *dev_to_iommu_device(struct device *dev)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void iommu_device_unregister(struct iommu_device *iommu)
|
||||
{
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user