Merge "iommu/arm-smmu: Fix atomic domain handling"

This commit is contained in:
qctecmdr 2019-11-20 21:55:22 -08:00 • committed by Gerrit - the friendly Code Review server
commit 0fa15b97cc
3 changed files with 83 additions and 97 deletions

View file

@ -241,13 +241,13 @@ static bool is_dynamic_domain(struct iommu_domain *domain)
{
struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
return !!(smmu_domain->attributes & (1ULL << DOMAIN_ATTR_DYNAMIC));
return test_bit(DOMAIN_ATTR_DYNAMIC, smmu_domain->attributes);
}
static bool is_iommu_pt_coherent(struct arm_smmu_domain *smmu_domain)
{
if (smmu_domain->attributes &
(1ULL << DOMAIN_ATTR_PAGE_TABLE_FORCE_COHERENT))
if (test_bit(DOMAIN_ATTR_PAGE_TABLE_FORCE_COHERENT,
smmu_domain->attributes))
return true;
else if (smmu_domain->smmu && smmu_domain->smmu->dev)
return dev_is_dma_coherent(smmu_domain->smmu->dev);
@ -831,8 +831,8 @@ static int arm_smmu_domain_power_on(struct iommu_domain *domain,
struct arm_smmu_device *smmu)
{
struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
bool atomic_domain = !!(smmu_domain->attributes &
(1ULL << DOMAIN_ATTR_ATOMIC));
bool atomic_domain = test_bit(DOMAIN_ATTR_ATOMIC,
smmu_domain->attributes);
if (atomic_domain)
return arm_smmu_power_on_atomic(smmu->pwr);
@ -848,8 +848,8 @@ static void arm_smmu_domain_power_off(struct iommu_domain *domain,
struct arm_smmu_device *smmu)
{
struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
bool atomic_domain = !!(smmu_domain->attributes &
(1ULL << DOMAIN_ATTR_ATOMIC));
bool atomic_domain = test_bit(DOMAIN_ATTR_ATOMIC,
smmu_domain->attributes);
if (atomic_domain) {
arm_smmu_power_off_atomic(smmu, smmu->pwr);
@ -1305,8 +1305,8 @@ static irqreturn_t arm_smmu_context_fault(int irq, void *dev)
bool fatal_asf = smmu->options & ARM_SMMU_OPT_FATAL_ASF;
phys_addr_t phys_soft;
uint64_t pte;
bool non_fatal_fault = !!(smmu_domain->attributes &
(1ULL << DOMAIN_ATTR_NON_FATAL_FAULTS));
bool non_fatal_fault = test_bit(DOMAIN_ATTR_NON_FATAL_FAULTS,
smmu_domain->attributes);
static DEFINE_RATELIMIT_STATE(_rs,
DEFAULT_RATELIMIT_INTERVAL,
@ -1519,7 +1519,7 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain,
}
static void arm_smmu_write_context_bank(struct arm_smmu_device *smmu, int idx,
u32 attributes)
unsigned long *attributes)
{
u32 reg;
bool stage1;
@ -1612,19 +1612,20 @@ static void arm_smmu_write_context_bank(struct arm_smmu_device *smmu, int idx,
FIELD_PREP(SCTLR_RACFG, SCTLR_RACFG_RA) |
SCTLR_MTCFG |
FIELD_PREP(SCTLR_MEM_ATTR, SCTLR_MEM_ATTR_OISH_WB_CACHE);
} else
} else {
reg |= FIELD_PREP(SCTLR_SHCFG, SCTLR_SHCFG_NSH);
}
if (attributes & (1ULL << DOMAIN_ATTR_CB_STALL_DISABLE)) {
if (attributes && test_bit(DOMAIN_ATTR_CB_STALL_DISABLE, attributes)) {
reg &= ~SCTLR_CFCFG;
reg |= SCTLR_HUPCF;
}
if (attributes & (1ULL << DOMAIN_ATTR_NO_CFRE))
if (attributes && test_bit(DOMAIN_ATTR_NO_CFRE, attributes))
reg &= ~SCTLR_CFRE;
if ((!(attributes & (1ULL << DOMAIN_ATTR_S1_BYPASS)) &&
!(attributes & (1ULL << DOMAIN_ATTR_EARLY_MAP))) || !stage1)
if (!attributes || (!test_bit(DOMAIN_ATTR_S1_BYPASS, attributes) &&
!test_bit(DOMAIN_ATTR_EARLY_MAP, attributes)) || !stage1)
reg |= SCTLR_M;
if (stage1)
reg |= SCTLR_S1_ASIDPNE;
@ -1736,9 +1737,9 @@ static int arm_smmu_adjust_domain_geometry(struct device *dev,
static int arm_smmu_get_dma_cookie(struct device *dev,
struct arm_smmu_domain *smmu_domain)
{
int is_fast = !!(smmu_domain->attributes & (1ULL << DOMAIN_ATTR_FAST));
int s1_bypass = !!(smmu_domain->attributes &
(1ULL << DOMAIN_ATTR_S1_BYPASS));
bool is_fast = test_bit(DOMAIN_ATTR_FAST, smmu_domain->attributes);
bool s1_bypass = test_bit(DOMAIN_ATTR_S1_BYPASS,
smmu_domain->attributes);
struct iommu_domain *domain = &smmu_domain->domain.iommu_domain;
struct io_pgtable_ops *pgtbl_ops = smmu_domain->pgtbl_ops;
@ -1769,9 +1770,9 @@ static void arm_smmu_domain_get_qcom_quirks(struct arm_smmu_domain *smmu_domain,
struct arm_smmu_device *smmu,
unsigned long *quirks)
{
if (smmu_domain->attributes & (1ULL << DOMAIN_ATTR_USE_UPSTREAM_HINT))
if (test_bit(DOMAIN_ATTR_USE_UPSTREAM_HINT, smmu_domain->attributes))
*quirks |= IO_PGTABLE_QUIRK_QCOM_USE_UPSTREAM_HINT;
if (smmu_domain->attributes & (1ULL << DOMAIN_ATTR_USE_LLC_NWA))
if (test_bit(DOMAIN_ATTR_USE_LLC_NWA, smmu_domain->attributes))
*quirks |= IO_PGTABLE_QUIRK_QCOM_USE_LLC_NWA;
}
@ -1950,7 +1951,7 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain,
}
#ifdef CONFIG_IOMMU_IO_PGTABLE_FAST
if (smmu_domain->attributes & (1ULL << DOMAIN_ATTR_FAST))
if (test_bit(DOMAIN_ATTR_FAST, smmu_domain->attributes))
fmt = ARM_V8L_FAST;
#endif
@ -2428,9 +2429,9 @@ static void arm_smmu_detach_dev(struct iommu_domain *domain,
struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
struct arm_smmu_device *smmu = smmu_domain->smmu;
struct iommu_fwspec *fwspec = dev->iommu_fwspec;
int dynamic = smmu_domain->attributes & (1ULL << DOMAIN_ATTR_DYNAMIC);
bool atomic_domain = !!(smmu_domain->attributes &
(1ULL << DOMAIN_ATTR_ATOMIC));
bool dynamic = is_dynamic_domain(domain);
bool atomic_domain = test_bit(DOMAIN_ATTR_ATOMIC,
smmu_domain->attributes);
if (dynamic)
return;
@ -2547,8 +2548,8 @@ static void arm_smmu_prealloc_memory(struct arm_smmu_domain *smmu_domain,
u32 nr = 0;
struct page *page;
if ((smmu_domain->attributes & (1ULL << DOMAIN_ATTR_ATOMIC)) ||
arm_smmu_has_secure_vmid(smmu_domain))
if (test_bit(DOMAIN_ATTR_ATOMIC, smmu_domain->attributes) ||
arm_smmu_has_secure_vmid(smmu_domain))
return;
/* number of 2nd level pagetable entries */
@ -2736,8 +2737,6 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
struct iommu_fwspec *fwspec = dev->iommu_fwspec;
struct arm_smmu_device *smmu;
struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
bool atomic_domain = !!(smmu_domain->attributes &
(1ULL << DOMAIN_ATTR_ATOMIC));
int s1_bypass = 0;
if (!fwspec || fwspec->ops != &arm_smmu_ops.iommu_ops) {
@ -2804,7 +2803,7 @@ out_power_off:
* Keep an additional vote for non-atomic power until domain is
* detached
*/
if (!ret && atomic_domain) {
if (!ret && test_bit(DOMAIN_ATTR_ATOMIC, smmu_domain->attributes)) {
WARN_ON(arm_smmu_power_on(smmu->pwr));
arm_smmu_power_off_atomic(smmu, smmu->pwr);
}
@ -3367,18 +3366,18 @@ static int arm_smmu_domain_get_attr(struct iommu_domain *domain,
ret = 0;
break;
case DOMAIN_ATTR_DYNAMIC:
*((int *)data) = !!(smmu_domain->attributes
& (1ULL << DOMAIN_ATTR_DYNAMIC));
*((int *)data) = test_bit(DOMAIN_ATTR_DYNAMIC,
smmu_domain->attributes);
ret = 0;
break;
case DOMAIN_ATTR_NON_FATAL_FAULTS:
*((int *)data) = !!(smmu_domain->attributes
& (1ULL << DOMAIN_ATTR_NON_FATAL_FAULTS));
*((int *)data) = test_bit(DOMAIN_ATTR_NON_FATAL_FAULTS,
smmu_domain->attributes);
ret = 0;
break;
case DOMAIN_ATTR_S1_BYPASS:
*((int *)data) = !!(smmu_domain->attributes
& (1ULL << DOMAIN_ATTR_S1_BYPASS));
*((int *)data) = test_bit(DOMAIN_ATTR_S1_BYPASS,
smmu_domain->attributes);
ret = 0;
break;
case DOMAIN_ATTR_SECURE_VMID:
@ -3388,7 +3387,7 @@ static int arm_smmu_domain_get_attr(struct iommu_domain *domain,
case DOMAIN_ATTR_PGTBL_INFO: {
struct iommu_pgtbl_info *info = data;
if (!(smmu_domain->attributes & (1ULL << DOMAIN_ATTR_FAST))) {
if (!test_bit(DOMAIN_ATTR_FAST, smmu_domain->attributes)) {
ret = -ENODEV;
break;
}
@ -3397,28 +3396,23 @@ static int arm_smmu_domain_get_attr(struct iommu_domain *domain,
break;
}
case DOMAIN_ATTR_FAST:
*((int *)data) = !!(smmu_domain->attributes
& (1ULL << DOMAIN_ATTR_FAST));
*((int *)data) = test_bit(DOMAIN_ATTR_FAST,
smmu_domain->attributes);
ret = 0;
break;
case DOMAIN_ATTR_USE_UPSTREAM_HINT:
*((int *)data) = !!(smmu_domain->attributes &
(1ULL << DOMAIN_ATTR_USE_UPSTREAM_HINT));
*((int *)data) = test_bit(DOMAIN_ATTR_USE_UPSTREAM_HINT,
smmu_domain->attributes);
ret = 0;
break;
case DOMAIN_ATTR_USE_LLC_NWA:
*((int *)data) = !!(smmu_domain->attributes &
(1ULL << DOMAIN_ATTR_USE_LLC_NWA));
*((int *)data) = test_bit(DOMAIN_ATTR_USE_LLC_NWA,
smmu_domain->attributes);
ret = 0;
break;
case DOMAIN_ATTR_EARLY_MAP:
*((int *)data) = !!(smmu_domain->attributes
& (1ULL << DOMAIN_ATTR_EARLY_MAP));
ret = 0;
break;
case DOMAIN_ATTR_BITMAP_IOVA_ALLOCATOR:
*((int *)data) = !!(smmu_domain->attributes
& (1ULL << DOMAIN_ATTR_BITMAP_IOVA_ALLOCATOR));
*((int *)data) = test_bit(DOMAIN_ATTR_EARLY_MAP,
smmu_domain->attributes);
ret = 0;
break;
case DOMAIN_ATTR_PAGE_TABLE_IS_COHERENT:
@ -3430,23 +3424,23 @@ static int arm_smmu_domain_get_attr(struct iommu_domain *domain,
ret = 0;
break;
case DOMAIN_ATTR_PAGE_TABLE_FORCE_COHERENT:
*((int *)data) = !!(smmu_domain->attributes
& (1ULL << DOMAIN_ATTR_PAGE_TABLE_FORCE_COHERENT));
*((int *)data) = test_bit(DOMAIN_ATTR_PAGE_TABLE_FORCE_COHERENT,
smmu_domain->attributes);
ret = 0;
break;
case DOMAIN_ATTR_CB_STALL_DISABLE:
*((int *)data) = !!(smmu_domain->attributes
& (1ULL << DOMAIN_ATTR_CB_STALL_DISABLE));
*((int *)data) = test_bit(DOMAIN_ATTR_CB_STALL_DISABLE,
smmu_domain->attributes);
ret = 0;
break;
case DOMAIN_ATTR_NO_CFRE:
*((int *)data) = !!(smmu_domain->attributes
& (1ULL << DOMAIN_ATTR_NO_CFRE));
*((int *)data) = test_bit(DOMAIN_ATTR_NO_CFRE,
smmu_domain->attributes);
ret = 0;
break;
case DOMAIN_ATTR_DEBUG:
*((int *)data) = !!(smmu_domain->attributes &
(1ULL << DOMAIN_ATTR_DEBUG));
*((int *)data) = test_bit(DOMAIN_ATTR_DEBUG,
smmu_domain->attributes);
ret = 0;
break;
default:
@ -3503,10 +3497,9 @@ static int __arm_smmu_domain_set_attr(struct iommu_domain *domain,
}
if (dynamic)
smmu_domain->attributes |= 1ULL << DOMAIN_ATTR_DYNAMIC;
set_bit(DOMAIN_ATTR_DYNAMIC, smmu_domain->attributes);
else
smmu_domain->attributes &=
~(1ULL << DOMAIN_ATTR_DYNAMIC);
clear_bit(DOMAIN_ATTR_DYNAMIC, smmu_domain->attributes);
ret = 0;
break;
}
@ -3517,8 +3510,7 @@ static int __arm_smmu_domain_set_attr(struct iommu_domain *domain,
break;
}
/* ... and it can only be set for dynamic contexts. */
if (!(smmu_domain->attributes &
(1ULL << DOMAIN_ATTR_DYNAMIC))) {
if (!test_bit(DOMAIN_ATTR_DYNAMIC, smmu_domain->attributes)) {
ret = -EINVAL;
break;
}
@ -3531,11 +3523,11 @@ static int __arm_smmu_domain_set_attr(struct iommu_domain *domain,
u32 non_fatal_faults = *((int *)data);
if (non_fatal_faults)
smmu_domain->attributes |=
1ULL << DOMAIN_ATTR_NON_FATAL_FAULTS;
set_bit(DOMAIN_ATTR_NON_FATAL_FAULTS,
smmu_domain->attributes);
else
smmu_domain->attributes &=
~(1ULL << DOMAIN_ATTR_NON_FATAL_FAULTS);
clear_bit(DOMAIN_ATTR_NON_FATAL_FAULTS,
smmu_domain->attributes);
ret = 0;
break;
}
@ -3548,11 +3540,10 @@ static int __arm_smmu_domain_set_attr(struct iommu_domain *domain,
break;
}
if (bypass)
smmu_domain->attributes |=
1ULL << DOMAIN_ATTR_S1_BYPASS;
set_bit(DOMAIN_ATTR_S1_BYPASS, smmu_domain->attributes);
else
smmu_domain->attributes &=
~(1ULL << DOMAIN_ATTR_S1_BYPASS);
clear_bit(DOMAIN_ATTR_S1_BYPASS,
smmu_domain->attributes);
ret = 0;
break;
@ -3567,10 +3558,9 @@ static int __arm_smmu_domain_set_attr(struct iommu_domain *domain,
break;
}
if (atomic_ctx)
smmu_domain->attributes |= (1ULL << DOMAIN_ATTR_ATOMIC);
set_bit(DOMAIN_ATTR_ATOMIC, smmu_domain->attributes);
else
smmu_domain->attributes &=
~(1ULL << DOMAIN_ATTR_ATOMIC);
clear_bit(DOMAIN_ATTR_ATOMIC, smmu_domain->attributes);
break;
}
case DOMAIN_ATTR_SECURE_VMID:
@ -3589,10 +3579,10 @@ static int __arm_smmu_domain_set_attr(struct iommu_domain *domain,
case DOMAIN_ATTR_FAST:
if (*((int *)data)) {
if (IS_ENABLED(CONFIG_IOMMU_IO_PGTABLE_FAST)) {
smmu_domain->attributes |=
1ULL << DOMAIN_ATTR_FAST;
smmu_domain->attributes |=
1ULL << DOMAIN_ATTR_ATOMIC;
set_bit(DOMAIN_ATTR_FAST,
smmu_domain->attributes);
set_bit(DOMAIN_ATTR_ATOMIC,
smmu_domain->attributes);
ret = 0;
} else {
ret = -ENOTSUPP;
@ -3623,7 +3613,7 @@ static int __arm_smmu_domain_set_attr2(struct iommu_domain *domain,
if (smmu_domain->smmu != NULL) {
ret = -EBUSY;
} else if (*((int *)data)) {
smmu_domain->attributes |= 1 << attr;
set_bit(attr, smmu_domain->attributes);
ret = 0;
}
} else {
@ -3635,25 +3625,22 @@ static int __arm_smmu_domain_set_attr2(struct iommu_domain *domain,
ret = 0;
if (early_map) {
smmu_domain->attributes |=
1ULL << DOMAIN_ATTR_EARLY_MAP;
set_bit(DOMAIN_ATTR_EARLY_MAP, smmu_domain->attributes);
} else {
if (smmu_domain->smmu)
ret = arm_smmu_enable_s1_translations(
smmu_domain);
if (!ret)
smmu_domain->attributes &=
~(1ULL << DOMAIN_ATTR_EARLY_MAP);
clear_bit(DOMAIN_ATTR_EARLY_MAP,
smmu_domain->attributes);
}
break;
}
case DOMAIN_ATTR_BITMAP_IOVA_ALLOCATOR:
case DOMAIN_ATTR_CB_STALL_DISABLE:
case DOMAIN_ATTR_NO_CFRE:
if (*((int *)data))
smmu_domain->attributes |=
1 << attr;
set_bit(attr, smmu_domain->attributes);
ret = 0;
break;
case DOMAIN_ATTR_PAGE_TABLE_FORCE_COHERENT: {
@ -3665,13 +3652,12 @@ static int __arm_smmu_domain_set_attr2(struct iommu_domain *domain,
"cannot change force coherent attribute while attached\n");
ret = -EBUSY;
} else if (force_coherent) {
smmu_domain->attributes |=
1ULL << DOMAIN_ATTR_PAGE_TABLE_FORCE_COHERENT;
set_bit(DOMAIN_ATTR_PAGE_TABLE_FORCE_COHERENT,
smmu_domain->attributes);
ret = 0;
} else {
smmu_domain->attributes &=
~(1ULL <<
DOMAIN_ATTR_PAGE_TABLE_FORCE_COHERENT);
clear_bit(DOMAIN_ATTR_PAGE_TABLE_FORCE_COHERENT,
smmu_domain->attributes);
ret = 0;
}
} else {
@ -3683,9 +3669,9 @@ static int __arm_smmu_domain_set_attr2(struct iommu_domain *domain,
int is_debug_domain = *((int *)data);
if (is_debug_domain)
smmu_domain->attributes |= 1ULL << DOMAIN_ATTR_DEBUG;
set_bit(DOMAIN_ATTR_DEBUG, smmu_domain->attributes);
else
smmu_domain->attributes &= ~(1ULL << DOMAIN_ATTR_DEBUG);
clear_bit(DOMAIN_ATTR_DEBUG, smmu_domain->attributes);
ret = 0;
break;
}

View file

@ -415,7 +415,7 @@ struct arm_smmu_domain {
spinlock_t cb_lock; /* Serialises ATS1* ops */
spinlock_t sync_lock; /* Serialises TLB syncs */
struct msm_io_pgtable_info pgtbl_info;
u64 attributes;
DECLARE_BITMAP(attributes, DOMAIN_ATTR_EXTENDED_MAX);
u32 secure_vmid;
struct list_head pte_info_list;
struct list_head unassign_list;

View file

@ -176,10 +176,10 @@ enum iommu_attr {
#define DOMAIN_ATTR_PAGE_TABLE_IS_COHERENT (EXTENDED_ATTR_BASE + 14)
#define DOMAIN_ATTR_PAGE_TABLE_FORCE_COHERENT (EXTENDED_ATTR_BASE + 15)
#define DOMAIN_ATTR_CB_STALL_DISABLE (EXTENDED_ATTR_BASE + 16)
#define DOMAIN_ATTR_BITMAP_IOVA_ALLOCATOR (EXTENDED_ATTR_BASE + 17)
#define DOMAIN_ATTR_USE_LLC_NWA (EXTENDED_ATTR_BASE + 18)
#define DOMAIN_ATTR_NO_CFRE (EXTENDED_ATTR_BASE + 19)
#define DOMAIN_ATTR_DEBUG (EXTENDED_ATTR_BASE + 20)
#define DOMAIN_ATTR_USE_LLC_NWA (EXTENDED_ATTR_BASE + 17)
#define DOMAIN_ATTR_NO_CFRE (EXTENDED_ATTR_BASE + 18)
#define DOMAIN_ATTR_DEBUG (EXTENDED_ATTR_BASE + 19)
#define DOMAIN_ATTR_EXTENDED_MAX (EXTENDED_ATTR_BASE + 20)
/* These are the possible reserved region types */
enum iommu_resv_type {