Arm SMMU updates for 5.9
- Support for SMMU-500 implementation in Marvell Armada-AP806 SoC - Support for SMMU-500 implementation in NVIDIA Tegra194 SoC - DT compatible string updates - Remove unused IOMMU_SYS_CACHE_ONLY flag -----BEGIN PGP SIGNATURE----- iQFEBAABCgAuFiEEPxTL6PPUbjXGY88ct6xw3ITBYzQFAl8VuRQQHHdpbGxAa2Vy bmVsLm9yZwAKCRC3rHDchMFjNALEB/4k1R7AV1d1lAdCpk78ymwu+FxtOCrhl7Vn VXQ2ta8K3VA0be2Y7tqXkILBwOq4I6riT3m3t1SFUsH0rZvxboia1iClj5cC8wEb 3aH++nhEkHY6FiLL78ToelGWXHdgUviUprQmifaWdDZ3O9GkWokETvTB6KFrlIF4 3ySS8Ig93g9SEclSVy4D6sYbV0CC+KADOlSKSq/Zzl7A+jPjw7nuohoes09+QrcX EGnldxcxBO0c4lq21ib7q4P5K72L9jaMBKM9Ubun2lo+oCcBaXKy938SSfIhNLYa Vz8FkGuf/JtN5S66BogBbBnlurAaxT9j1P467icLf2ULFYMapWtB =LK7r -----END PGP SIGNATURE----- Merge tag 'arm-smmu-updates' of git://git.kernel.org/pub/scm/linux/kernel/git/will/linux into arm/smmu Arm SMMU updates for 5.9 - Support for SMMU-500 implementation in Marvell Armada-AP806 SoC - Support for SMMU-500 implementation in NVIDIA Tegra194 SoC - DT compatible string updates - Remove unused IOMMU_SYS_CACHE_ONLY flag
This commit is contained in:
commit
ee79e5fbc1
|
@ -125,6 +125,9 @@ stable kernels.
|
|||
| Cavium | ThunderX2 Core | #219 | CAVIUM_TX2_ERRATUM_219 |
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
| Marvell | ARM-MMU-500 | #582743 | N/A |
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
| Freescale/NXP | LS2080A/LS1043A | A-008585 | FSL_ERRATUM_A008585 |
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
|
|
|
@ -37,7 +37,18 @@ properties:
|
|||
- enum:
|
||||
- qcom,sc7180-smmu-500
|
||||
- qcom,sdm845-smmu-500
|
||||
- qcom,sm8150-smmu-500
|
||||
- qcom,sm8250-smmu-500
|
||||
- const: arm,mmu-500
|
||||
- description: Marvell SoCs implementing "arm,mmu-500"
|
||||
items:
|
||||
- const: marvell,ap806-smmu-500
|
||||
- const: arm,mmu-500
|
||||
- description: NVIDIA SoCs that program two ARM MMU-500s identically
|
||||
items:
|
||||
- enum:
|
||||
- nvidia,tegra194-smmu
|
||||
- const: nvidia,smmu-500
|
||||
- items:
|
||||
- const: arm,mmu-500
|
||||
- const: arm,smmu-v2
|
||||
|
@ -55,7 +66,8 @@ properties:
|
|||
- cavium,smmu-v2
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
|
||||
'#global-interrupts':
|
||||
description: The number of global interrupts exposed by the device.
|
||||
|
@ -138,6 +150,23 @@ required:
|
|||
|
||||
additionalProperties: false
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- nvidia,tegra194-smmu
|
||||
then:
|
||||
properties:
|
||||
reg:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
else:
|
||||
properties:
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
examples:
|
||||
- |+
|
||||
/* SMMU with stream matching or stream indexing */
|
||||
|
|
|
@ -16810,8 +16810,10 @@ F: drivers/i2c/busses/i2c-tegra.c
|
|||
|
||||
TEGRA IOMMU DRIVERS
|
||||
M: Thierry Reding <thierry.reding@gmail.com>
|
||||
R: Krishna Reddy <vdumpa@nvidia.com>
|
||||
L: linux-tegra@vger.kernel.org
|
||||
S: Supported
|
||||
F: drivers/iommu/arm-smmu-nvidia.c
|
||||
F: drivers/iommu/tegra*
|
||||
|
||||
TEGRA KBC DRIVER
|
||||
|
|
|
@ -15,7 +15,7 @@ obj-$(CONFIG_AMD_IOMMU) += amd/iommu.o amd/init.o amd/quirks.o
|
|||
obj-$(CONFIG_AMD_IOMMU_DEBUGFS) += amd/debugfs.o
|
||||
obj-$(CONFIG_AMD_IOMMU_V2) += amd/iommu_v2.o
|
||||
obj-$(CONFIG_ARM_SMMU) += arm_smmu.o
|
||||
arm_smmu-objs += arm-smmu.o arm-smmu-impl.o arm-smmu-qcom.o
|
||||
arm_smmu-objs += arm-smmu.o arm-smmu-impl.o arm-smmu-nvidia.o arm-smmu-qcom.o
|
||||
obj-$(CONFIG_ARM_SMMU_V3) += arm-smmu-v3.o
|
||||
obj-$(CONFIG_DMAR_TABLE) += intel/dmar.o
|
||||
obj-$(CONFIG_INTEL_IOMMU) += intel/iommu.o intel/pasid.o
|
||||
|
|
|
@ -147,16 +147,57 @@ static const struct arm_smmu_impl arm_mmu500_impl = {
|
|||
.reset = arm_mmu500_reset,
|
||||
};
|
||||
|
||||
static u64 mrvl_mmu500_readq(struct arm_smmu_device *smmu, int page, int off)
|
||||
{
|
||||
/*
|
||||
* Marvell Armada-AP806 erratum #582743.
|
||||
* Split all the readq to double readl
|
||||
*/
|
||||
return hi_lo_readq_relaxed(arm_smmu_page(smmu, page) + off);
|
||||
}
|
||||
|
||||
static void mrvl_mmu500_writeq(struct arm_smmu_device *smmu, int page, int off,
|
||||
u64 val)
|
||||
{
|
||||
/*
|
||||
* Marvell Armada-AP806 erratum #582743.
|
||||
* Split all the writeq to double writel
|
||||
*/
|
||||
hi_lo_writeq_relaxed(val, arm_smmu_page(smmu, page) + off);
|
||||
}
|
||||
|
||||
static int mrvl_mmu500_cfg_probe(struct arm_smmu_device *smmu)
|
||||
{
|
||||
|
||||
/*
|
||||
* Armada-AP806 erratum #582743.
|
||||
* Hide the SMMU_IDR2.PTFSv8 fields to sidestep the AArch64
|
||||
* formats altogether and allow using 32 bits access on the
|
||||
* interconnect.
|
||||
*/
|
||||
smmu->features &= ~(ARM_SMMU_FEAT_FMT_AARCH64_4K |
|
||||
ARM_SMMU_FEAT_FMT_AARCH64_16K |
|
||||
ARM_SMMU_FEAT_FMT_AARCH64_64K);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct arm_smmu_impl mrvl_mmu500_impl = {
|
||||
.read_reg64 = mrvl_mmu500_readq,
|
||||
.write_reg64 = mrvl_mmu500_writeq,
|
||||
.cfg_probe = mrvl_mmu500_cfg_probe,
|
||||
.reset = arm_mmu500_reset,
|
||||
};
|
||||
|
||||
|
||||
struct arm_smmu_device *arm_smmu_impl_init(struct arm_smmu_device *smmu)
|
||||
{
|
||||
const struct device_node *np = smmu->dev->of_node;
|
||||
|
||||
/*
|
||||
* We will inevitably have to combine model-specific implementation
|
||||
* quirks with platform-specific integration quirks, but everything
|
||||
* we currently support happens to work out as straightforward
|
||||
* mutually-exclusive assignments.
|
||||
* Set the impl for model-specific implementation quirks first,
|
||||
* such that platform integration quirks can pick it up and
|
||||
* inherit from it if necessary.
|
||||
*/
|
||||
switch (smmu->model) {
|
||||
case ARM_MMU500:
|
||||
|
@ -168,12 +209,21 @@ struct arm_smmu_device *arm_smmu_impl_init(struct arm_smmu_device *smmu)
|
|||
break;
|
||||
}
|
||||
|
||||
/* This is implicitly MMU-400 */
|
||||
if (of_property_read_bool(np, "calxeda,smmu-secure-config-access"))
|
||||
smmu->impl = &calxeda_impl;
|
||||
|
||||
if (of_device_is_compatible(np, "nvidia,tegra194-smmu"))
|
||||
return nvidia_smmu_impl_init(smmu);
|
||||
|
||||
if (of_device_is_compatible(np, "qcom,sdm845-smmu-500") ||
|
||||
of_device_is_compatible(np, "qcom,sc7180-smmu-500"))
|
||||
of_device_is_compatible(np, "qcom,sc7180-smmu-500") ||
|
||||
of_device_is_compatible(np, "qcom,sm8150-smmu-500") ||
|
||||
of_device_is_compatible(np, "qcom,sm8250-smmu-500"))
|
||||
return qcom_smmu_impl_init(smmu);
|
||||
|
||||
if (of_device_is_compatible(np, "marvell,ap806-smmu-500"))
|
||||
smmu->impl = &mrvl_mmu500_impl;
|
||||
|
||||
return smmu;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,278 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// Copyright (C) 2019-2020 NVIDIA CORPORATION. All rights reserved.
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "arm-smmu.h"
|
||||
|
||||
/*
|
||||
* Tegra194 has three ARM MMU-500 Instances.
|
||||
* Two of them are used together and must be programmed identically for
|
||||
* interleaved IOVA accesses across them and translates accesses from
|
||||
* non-isochronous HW devices.
|
||||
* Third one is used for translating accesses from isochronous HW devices.
|
||||
* This implementation supports programming of the two instances that must
|
||||
* be programmed identically.
|
||||
* The third instance usage is through standard arm-smmu driver itself and
|
||||
* is out of scope of this implementation.
|
||||
*/
|
||||
#define NUM_SMMU_INSTANCES 2
|
||||
|
||||
struct nvidia_smmu {
|
||||
struct arm_smmu_device smmu;
|
||||
void __iomem *bases[NUM_SMMU_INSTANCES];
|
||||
};
|
||||
|
||||
static inline void __iomem *nvidia_smmu_page(struct arm_smmu_device *smmu,
|
||||
unsigned int inst, int page)
|
||||
{
|
||||
struct nvidia_smmu *nvidia_smmu;
|
||||
|
||||
nvidia_smmu = container_of(smmu, struct nvidia_smmu, smmu);
|
||||
return nvidia_smmu->bases[inst] + (page << smmu->pgshift);
|
||||
}
|
||||
|
||||
static u32 nvidia_smmu_read_reg(struct arm_smmu_device *smmu,
|
||||
int page, int offset)
|
||||
{
|
||||
void __iomem *reg = nvidia_smmu_page(smmu, 0, page) + offset;
|
||||
|
||||
return readl_relaxed(reg);
|
||||
}
|
||||
|
||||
static void nvidia_smmu_write_reg(struct arm_smmu_device *smmu,
|
||||
int page, int offset, u32 val)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < NUM_SMMU_INSTANCES; i++) {
|
||||
void __iomem *reg = nvidia_smmu_page(smmu, i, page) + offset;
|
||||
|
||||
writel_relaxed(val, reg);
|
||||
}
|
||||
}
|
||||
|
||||
static u64 nvidia_smmu_read_reg64(struct arm_smmu_device *smmu,
|
||||
int page, int offset)
|
||||
{
|
||||
void __iomem *reg = nvidia_smmu_page(smmu, 0, page) + offset;
|
||||
|
||||
return readq_relaxed(reg);
|
||||
}
|
||||
|
||||
static void nvidia_smmu_write_reg64(struct arm_smmu_device *smmu,
|
||||
int page, int offset, u64 val)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < NUM_SMMU_INSTANCES; i++) {
|
||||
void __iomem *reg = nvidia_smmu_page(smmu, i, page) + offset;
|
||||
|
||||
writeq_relaxed(val, reg);
|
||||
}
|
||||
}
|
||||
|
||||
static void nvidia_smmu_tlb_sync(struct arm_smmu_device *smmu, int page,
|
||||
int sync, int status)
|
||||
{
|
||||
unsigned int delay;
|
||||
|
||||
arm_smmu_writel(smmu, page, sync, 0);
|
||||
|
||||
for (delay = 1; delay < TLB_LOOP_TIMEOUT; delay *= 2) {
|
||||
unsigned int spin_cnt;
|
||||
|
||||
for (spin_cnt = TLB_SPIN_COUNT; spin_cnt > 0; spin_cnt--) {
|
||||
u32 val = 0;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < NUM_SMMU_INSTANCES; i++) {
|
||||
void __iomem *reg;
|
||||
|
||||
reg = nvidia_smmu_page(smmu, i, page) + status;
|
||||
val |= readl_relaxed(reg);
|
||||
}
|
||||
|
||||
if (!(val & ARM_SMMU_sTLBGSTATUS_GSACTIVE))
|
||||
return;
|
||||
|
||||
cpu_relax();
|
||||
}
|
||||
|
||||
udelay(delay);
|
||||
}
|
||||
|
||||
dev_err_ratelimited(smmu->dev,
|
||||
"TLB sync timed out -- SMMU may be deadlocked\n");
|
||||
}
|
||||
|
||||
static int nvidia_smmu_reset(struct arm_smmu_device *smmu)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < NUM_SMMU_INSTANCES; i++) {
|
||||
u32 val;
|
||||
void __iomem *reg = nvidia_smmu_page(smmu, i, ARM_SMMU_GR0) +
|
||||
ARM_SMMU_GR0_sGFSR;
|
||||
|
||||
/* clear global FSR */
|
||||
val = readl_relaxed(reg);
|
||||
writel_relaxed(val, reg);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t nvidia_smmu_global_fault_inst(int irq,
|
||||
struct arm_smmu_device *smmu,
|
||||
int inst)
|
||||
{
|
||||
u32 gfsr, gfsynr0, gfsynr1, gfsynr2;
|
||||
void __iomem *gr0_base = nvidia_smmu_page(smmu, inst, 0);
|
||||
|
||||
gfsr = readl_relaxed(gr0_base + ARM_SMMU_GR0_sGFSR);
|
||||
if (!gfsr)
|
||||
return IRQ_NONE;
|
||||
|
||||
gfsynr0 = readl_relaxed(gr0_base + ARM_SMMU_GR0_sGFSYNR0);
|
||||
gfsynr1 = readl_relaxed(gr0_base + ARM_SMMU_GR0_sGFSYNR1);
|
||||
gfsynr2 = readl_relaxed(gr0_base + ARM_SMMU_GR0_sGFSYNR2);
|
||||
|
||||
dev_err_ratelimited(smmu->dev,
|
||||
"Unexpected global fault, this could be serious\n");
|
||||
dev_err_ratelimited(smmu->dev,
|
||||
"\tGFSR 0x%08x, GFSYNR0 0x%08x, GFSYNR1 0x%08x, GFSYNR2 0x%08x\n",
|
||||
gfsr, gfsynr0, gfsynr1, gfsynr2);
|
||||
|
||||
writel_relaxed(gfsr, gr0_base + ARM_SMMU_GR0_sGFSR);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t nvidia_smmu_global_fault(int irq, void *dev)
|
||||
{
|
||||
unsigned int inst;
|
||||
irqreturn_t ret = IRQ_NONE;
|
||||
struct arm_smmu_device *smmu = dev;
|
||||
|
||||
for (inst = 0; inst < NUM_SMMU_INSTANCES; inst++) {
|
||||
irqreturn_t irq_ret;
|
||||
|
||||
irq_ret = nvidia_smmu_global_fault_inst(irq, smmu, inst);
|
||||
if (irq_ret == IRQ_HANDLED)
|
||||
ret = IRQ_HANDLED;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static irqreturn_t nvidia_smmu_context_fault_bank(int irq,
|
||||
struct arm_smmu_device *smmu,
|
||||
int idx, int inst)
|
||||
{
|
||||
u32 fsr, fsynr, cbfrsynra;
|
||||
unsigned long iova;
|
||||
void __iomem *gr1_base = nvidia_smmu_page(smmu, inst, 1);
|
||||
void __iomem *cb_base = nvidia_smmu_page(smmu, inst, smmu->numpage + idx);
|
||||
|
||||
fsr = readl_relaxed(cb_base + ARM_SMMU_CB_FSR);
|
||||
if (!(fsr & ARM_SMMU_FSR_FAULT))
|
||||
return IRQ_NONE;
|
||||
|
||||
fsynr = readl_relaxed(cb_base + ARM_SMMU_CB_FSYNR0);
|
||||
iova = readq_relaxed(cb_base + ARM_SMMU_CB_FAR);
|
||||
cbfrsynra = readl_relaxed(gr1_base + ARM_SMMU_GR1_CBFRSYNRA(idx));
|
||||
|
||||
dev_err_ratelimited(smmu->dev,
|
||||
"Unhandled context fault: fsr=0x%x, iova=0x%08lx, fsynr=0x%x, cbfrsynra=0x%x, cb=%d\n",
|
||||
fsr, iova, fsynr, cbfrsynra, idx);
|
||||
|
||||
writel_relaxed(fsr, cb_base + ARM_SMMU_CB_FSR);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t nvidia_smmu_context_fault(int irq, void *dev)
|
||||
{
|
||||
int idx;
|
||||
unsigned int inst;
|
||||
irqreturn_t ret = IRQ_NONE;
|
||||
struct arm_smmu_device *smmu;
|
||||
struct iommu_domain *domain = dev;
|
||||
struct arm_smmu_domain *smmu_domain;
|
||||
|
||||
smmu_domain = container_of(domain, struct arm_smmu_domain, domain);
|
||||
smmu = smmu_domain->smmu;
|
||||
|
||||
for (inst = 0; inst < NUM_SMMU_INSTANCES; inst++) {
|
||||
irqreturn_t irq_ret;
|
||||
|
||||
/*
|
||||
* Interrupt line is shared between all contexts.
|
||||
* Check for faults across all contexts.
|
||||
*/
|
||||
for (idx = 0; idx < smmu->num_context_banks; idx++) {
|
||||
irq_ret = nvidia_smmu_context_fault_bank(irq, smmu,
|
||||
idx, inst);
|
||||
if (irq_ret == IRQ_HANDLED)
|
||||
ret = IRQ_HANDLED;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct arm_smmu_impl nvidia_smmu_impl = {
|
||||
.read_reg = nvidia_smmu_read_reg,
|
||||
.write_reg = nvidia_smmu_write_reg,
|
||||
.read_reg64 = nvidia_smmu_read_reg64,
|
||||
.write_reg64 = nvidia_smmu_write_reg64,
|
||||
.reset = nvidia_smmu_reset,
|
||||
.tlb_sync = nvidia_smmu_tlb_sync,
|
||||
.global_fault = nvidia_smmu_global_fault,
|
||||
.context_fault = nvidia_smmu_context_fault,
|
||||
};
|
||||
|
||||
struct arm_smmu_device *nvidia_smmu_impl_init(struct arm_smmu_device *smmu)
|
||||
{
|
||||
struct resource *res;
|
||||
struct device *dev = smmu->dev;
|
||||
struct nvidia_smmu *nvidia_smmu;
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
|
||||
nvidia_smmu = devm_kzalloc(dev, sizeof(*nvidia_smmu), GFP_KERNEL);
|
||||
if (!nvidia_smmu)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
/*
|
||||
* Copy the data from struct arm_smmu_device *smmu allocated in
|
||||
* arm-smmu.c. The smmu from struct nvidia_smmu replaces the smmu
|
||||
* pointer used in arm-smmu.c once this function returns.
|
||||
* This is necessary to derive nvidia_smmu from smmu pointer passed
|
||||
* through arm_smmu_impl function calls subsequently.
|
||||
*/
|
||||
nvidia_smmu->smmu = *smmu;
|
||||
/* Instance 0 is ioremapped by arm-smmu.c. */
|
||||
nvidia_smmu->bases[0] = smmu->base;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||
if (!res)
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
nvidia_smmu->bases[1] = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(nvidia_smmu->bases[1]))
|
||||
return ERR_CAST(nvidia_smmu->bases[1]);
|
||||
|
||||
nvidia_smmu->smmu.impl = &nvidia_smmu_impl;
|
||||
|
||||
/*
|
||||
* Free the struct arm_smmu_device *smmu allocated in arm-smmu.c.
|
||||
* Once this function returns, arm-smmu.c would use arm_smmu_device
|
||||
* allocated as part of struct nvidia_smmu.
|
||||
*/
|
||||
devm_kfree(dev, smmu);
|
||||
|
||||
return &nvidia_smmu->smmu;
|
||||
}
|
|
@ -1479,7 +1479,7 @@ static int arm_smmu_cmdq_issue_cmdlist(struct arm_smmu_device *smmu,
|
|||
}
|
||||
|
||||
/*
|
||||
* Try to unlock the cmq lock. This will fail if we're the last
|
||||
* Try to unlock the cmdq lock. This will fail if we're the last
|
||||
* reader, in which case we can safely update cmdq->q.llq.cons
|
||||
*/
|
||||
if (!arm_smmu_cmdq_shared_tryunlock(cmdq)) {
|
||||
|
|
|
@ -52,9 +52,6 @@
|
|||
*/
|
||||
#define QCOM_DUMMY_VAL -1
|
||||
|
||||
#define TLB_LOOP_TIMEOUT 1000000 /* 1s! */
|
||||
#define TLB_SPIN_COUNT 10
|
||||
|
||||
#define MSI_IOVA_BASE 0x8000000
|
||||
#define MSI_IOVA_LENGTH 0x100000
|
||||
|
||||
|
@ -673,6 +670,7 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain,
|
|||
enum io_pgtable_fmt fmt;
|
||||
struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
|
||||
struct arm_smmu_cfg *cfg = &smmu_domain->cfg;
|
||||
irqreturn_t (*context_fault)(int irq, void *dev);
|
||||
|
||||
mutex_lock(&smmu_domain->init_mutex);
|
||||
if (smmu_domain->smmu)
|
||||
|
@ -835,7 +833,13 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain,
|
|||
* handler seeing a half-initialised domain state.
|
||||
*/
|
||||
irq = smmu->irqs[smmu->num_global_irqs + cfg->irptndx];
|
||||
ret = devm_request_irq(smmu->dev, irq, arm_smmu_context_fault,
|
||||
|
||||
if (smmu->impl && smmu->impl->context_fault)
|
||||
context_fault = smmu->impl->context_fault;
|
||||
else
|
||||
context_fault = arm_smmu_context_fault;
|
||||
|
||||
ret = devm_request_irq(smmu->dev, irq, context_fault,
|
||||
IRQF_SHARED, "arm-smmu-context-fault", domain);
|
||||
if (ret < 0) {
|
||||
dev_err(smmu->dev, "failed to request context IRQ %d (%u)\n",
|
||||
|
@ -1728,7 +1732,7 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu)
|
|||
unsigned int size;
|
||||
u32 id;
|
||||
bool cttw_reg, cttw_fw = smmu->features & ARM_SMMU_FEAT_COHERENT_WALK;
|
||||
int i;
|
||||
int i, ret;
|
||||
|
||||
dev_notice(smmu->dev, "probing hardware configuration...\n");
|
||||
dev_notice(smmu->dev, "SMMUv%d with:\n",
|
||||
|
@ -1891,6 +1895,12 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu)
|
|||
smmu->features |= ARM_SMMU_FEAT_FMT_AARCH64_64K;
|
||||
}
|
||||
|
||||
if (smmu->impl && smmu->impl->cfg_probe) {
|
||||
ret = smmu->impl->cfg_probe(smmu);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Now we've corralled the various formats, what'll it do? */
|
||||
if (smmu->features & ARM_SMMU_FEAT_FMT_AARCH32_S)
|
||||
smmu->pgsize_bitmap |= SZ_4K | SZ_64K | SZ_1M | SZ_16M;
|
||||
|
@ -1918,9 +1928,6 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu)
|
|||
dev_notice(smmu->dev, "\tStage-2: %lu-bit IPA -> %lu-bit PA\n",
|
||||
smmu->ipa_size, smmu->pa_size);
|
||||
|
||||
if (smmu->impl && smmu->impl->cfg_probe)
|
||||
return smmu->impl->cfg_probe(smmu);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1946,6 +1953,7 @@ static const struct of_device_id arm_smmu_of_match[] = {
|
|||
{ .compatible = "arm,mmu-401", .data = &arm_mmu401 },
|
||||
{ .compatible = "arm,mmu-500", .data = &arm_mmu500 },
|
||||
{ .compatible = "cavium,smmu-v2", .data = &cavium_smmuv2 },
|
||||
{ .compatible = "nvidia,smmu-500", .data = &arm_mmu500 },
|
||||
{ .compatible = "qcom,smmu-v2", .data = &qcom_smmuv2 },
|
||||
{ },
|
||||
};
|
||||
|
@ -2107,6 +2115,7 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
|
|||
struct arm_smmu_device *smmu;
|
||||
struct device *dev = &pdev->dev;
|
||||
int num_irqs, i, err;
|
||||
irqreturn_t (*global_fault)(int irq, void *dev);
|
||||
|
||||
smmu = devm_kzalloc(dev, sizeof(*smmu), GFP_KERNEL);
|
||||
if (!smmu) {
|
||||
|
@ -2123,10 +2132,6 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
smmu = arm_smmu_impl_init(smmu);
|
||||
if (IS_ERR(smmu))
|
||||
return PTR_ERR(smmu);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
ioaddr = res->start;
|
||||
smmu->base = devm_ioremap_resource(dev, res);
|
||||
|
@ -2138,6 +2143,10 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
|
|||
*/
|
||||
smmu->numpage = resource_size(res);
|
||||
|
||||
smmu = arm_smmu_impl_init(smmu);
|
||||
if (IS_ERR(smmu))
|
||||
return PTR_ERR(smmu);
|
||||
|
||||
num_irqs = 0;
|
||||
while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, num_irqs))) {
|
||||
num_irqs++;
|
||||
|
@ -2193,9 +2202,14 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
|
|||
smmu->num_context_irqs = smmu->num_context_banks;
|
||||
}
|
||||
|
||||
if (smmu->impl && smmu->impl->global_fault)
|
||||
global_fault = smmu->impl->global_fault;
|
||||
else
|
||||
global_fault = arm_smmu_global_fault;
|
||||
|
||||
for (i = 0; i < smmu->num_global_irqs; ++i) {
|
||||
err = devm_request_irq(smmu->dev, smmu->irqs[i],
|
||||
arm_smmu_global_fault,
|
||||
global_fault,
|
||||
IRQF_SHARED,
|
||||
"arm-smmu global fault",
|
||||
smmu);
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <linux/io-64-nonatomic-hi-lo.h>
|
||||
#include <linux/io-pgtable.h>
|
||||
#include <linux/iommu.h>
|
||||
#include <linux/irqreturn.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/types.h>
|
||||
|
@ -236,6 +237,8 @@ enum arm_smmu_cbar_type {
|
|||
/* Maximum number of context banks per SMMU */
|
||||
#define ARM_SMMU_MAX_CBS 128
|
||||
|
||||
#define TLB_LOOP_TIMEOUT 1000000 /* 1s! */
|
||||
#define TLB_SPIN_COUNT 10
|
||||
|
||||
/* Shared driver definitions */
|
||||
enum arm_smmu_arch_version {
|
||||
|
@ -387,6 +390,8 @@ struct arm_smmu_impl {
|
|||
void (*tlb_sync)(struct arm_smmu_device *smmu, int page, int sync,
|
||||
int status);
|
||||
int (*def_domain_type)(struct device *dev);
|
||||
irqreturn_t (*global_fault)(int irq, void *dev);
|
||||
irqreturn_t (*context_fault)(int irq, void *dev);
|
||||
};
|
||||
|
||||
static inline void __iomem *arm_smmu_page(struct arm_smmu_device *smmu, int n)
|
||||
|
@ -450,6 +455,7 @@ static inline void arm_smmu_writeq(struct arm_smmu_device *smmu, int page,
|
|||
arm_smmu_writeq((s), ARM_SMMU_CB((s), (n)), (o), (v))
|
||||
|
||||
struct arm_smmu_device *arm_smmu_impl_init(struct arm_smmu_device *smmu);
|
||||
struct arm_smmu_device *nvidia_smmu_impl_init(struct arm_smmu_device *smmu);
|
||||
struct arm_smmu_device *qcom_smmu_impl_init(struct arm_smmu_device *smmu);
|
||||
|
||||
int arm_mmu500_reset(struct arm_smmu_device *smmu);
|
||||
|
|
|
@ -438,9 +438,6 @@ static arm_lpae_iopte arm_lpae_prot_to_pte(struct arm_lpae_io_pgtable *data,
|
|||
else if (prot & IOMMU_CACHE)
|
||||
pte |= (ARM_LPAE_MAIR_ATTR_IDX_CACHE
|
||||
<< ARM_LPAE_PTE_ATTRINDX_SHIFT);
|
||||
else if (prot & IOMMU_SYS_CACHE_ONLY)
|
||||
pte |= (ARM_LPAE_MAIR_ATTR_IDX_INC_OCACHE
|
||||
<< ARM_LPAE_PTE_ATTRINDX_SHIFT);
|
||||
}
|
||||
|
||||
if (prot & IOMMU_CACHE)
|
||||
|
|
|
@ -31,12 +31,6 @@
|
|||
* if the IOMMU page table format is equivalent.
|
||||
*/
|
||||
#define IOMMU_PRIV (1 << 5)
|
||||
/*
|
||||
* Non-coherent masters can use this page protection flag to set cacheable
|
||||
* memory attributes for only a transparent outer level of cache, also known as
|
||||
* the last-level or system cache.
|
||||
*/
|
||||
#define IOMMU_SYS_CACHE_ONLY (1 << 6)
|
||||
|
||||
struct iommu_ops;
|
||||
struct iommu_group;
|
||||
|
|
Loading…
Reference in New Issue