Merge branches 'arm/exynos', 'ppc/pamu', 'arm/smmu', 'x86/amd' and 'iommu/fixes' into next
This commit is contained in:
commit
d6a60fc1a8
|
@ -28,6 +28,9 @@ struct dev_archdata {
|
||||||
void *iommu_table_base;
|
void *iommu_table_base;
|
||||||
} dma_data;
|
} dma_data;
|
||||||
|
|
||||||
|
#ifdef CONFIG_IOMMU_API
|
||||||
|
void *iommu_domain;
|
||||||
|
#endif
|
||||||
#ifdef CONFIG_SWIOTLB
|
#ifdef CONFIG_SWIOTLB
|
||||||
dma_addr_t max_direct_dma_addr;
|
dma_addr_t max_direct_dma_addr;
|
||||||
#endif
|
#endif
|
||||||
|
|
39
arch/powerpc/include/asm/fsl_pamu_stash.h
Normal file
39
arch/powerpc/include/asm/fsl_pamu_stash.h
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License, version 2, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2013 Freescale Semiconductor, Inc.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __FSL_PAMU_STASH_H
|
||||||
|
#define __FSL_PAMU_STASH_H
|
||||||
|
|
||||||
|
/* cache stash targets */
|
||||||
|
enum pamu_stash_target {
|
||||||
|
PAMU_ATTR_CACHE_L1 = 1,
|
||||||
|
PAMU_ATTR_CACHE_L2,
|
||||||
|
PAMU_ATTR_CACHE_L3,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This attribute allows configuring stashig specific parameters
|
||||||
|
* in the PAMU hardware.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct pamu_stash_attribute {
|
||||||
|
u32 cpu; /* cpu number */
|
||||||
|
u32 cache; /* cache to stash to: L1,L2,L3 */
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* __FSL_PAMU_STASH_H */
|
|
@ -16,6 +16,11 @@
|
||||||
|
|
||||||
struct platform_device;
|
struct platform_device;
|
||||||
|
|
||||||
|
|
||||||
|
/* FSL PCI controller BRR1 register */
|
||||||
|
#define PCI_FSL_BRR1 0xbf8
|
||||||
|
#define PCI_FSL_BRR1_VER 0xffff
|
||||||
|
|
||||||
#define PCIE_LTSSM 0x0404 /* PCIE Link Training and Status */
|
#define PCIE_LTSSM 0x0404 /* PCIE Link Training and Status */
|
||||||
#define PCIE_LTSSM_L0 0x16 /* L0 state */
|
#define PCIE_LTSSM_L0 0x16 /* L0 state */
|
||||||
#define PCIE_IP_REV_2_2 0x02080202 /* PCIE IP block version Rev2.2 */
|
#define PCIE_IP_REV_2_2 0x02080202 /* PCIE IP block version Rev2.2 */
|
||||||
|
|
|
@ -17,6 +17,16 @@ config OF_IOMMU
|
||||||
def_bool y
|
def_bool y
|
||||||
depends on OF
|
depends on OF
|
||||||
|
|
||||||
|
config FSL_PAMU
|
||||||
|
bool "Freescale IOMMU support"
|
||||||
|
depends on PPC_E500MC
|
||||||
|
select IOMMU_API
|
||||||
|
select GENERIC_ALLOCATOR
|
||||||
|
help
|
||||||
|
Freescale PAMU support. PAMU is the IOMMU present on Freescale QorIQ platforms.
|
||||||
|
PAMU can authorize memory access, remap the memory address, and remap I/O
|
||||||
|
transaction types.
|
||||||
|
|
||||||
# MSM IOMMU support
|
# MSM IOMMU support
|
||||||
config MSM_IOMMU
|
config MSM_IOMMU
|
||||||
bool "MSM IOMMU Support"
|
bool "MSM IOMMU Support"
|
||||||
|
|
|
@ -16,3 +16,4 @@ obj-$(CONFIG_TEGRA_IOMMU_SMMU) += tegra-smmu.o
|
||||||
obj-$(CONFIG_EXYNOS_IOMMU) += exynos-iommu.o
|
obj-$(CONFIG_EXYNOS_IOMMU) += exynos-iommu.o
|
||||||
obj-$(CONFIG_SHMOBILE_IOMMU) += shmobile-iommu.o
|
obj-$(CONFIG_SHMOBILE_IOMMU) += shmobile-iommu.o
|
||||||
obj-$(CONFIG_SHMOBILE_IPMMU) += shmobile-ipmmu.o
|
obj-$(CONFIG_SHMOBILE_IPMMU) += shmobile-ipmmu.o
|
||||||
|
obj-$(CONFIG_FSL_PAMU) += fsl_pamu.o fsl_pamu_domain.o
|
||||||
|
|
|
@ -456,8 +456,10 @@ static int iommu_init_device(struct device *dev)
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = init_iommu_group(dev);
|
ret = init_iommu_group(dev);
|
||||||
if (ret)
|
if (ret) {
|
||||||
|
free_dev_data(dev_data);
|
||||||
return ret;
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
if (pci_iommuv2_capable(pdev)) {
|
if (pci_iommuv2_capable(pdev)) {
|
||||||
struct amd_iommu *iommu;
|
struct amd_iommu *iommu;
|
||||||
|
|
|
@ -1384,7 +1384,7 @@ static int iommu_init_msi(struct amd_iommu *iommu)
|
||||||
if (iommu->int_enabled)
|
if (iommu->int_enabled)
|
||||||
goto enable_faults;
|
goto enable_faults;
|
||||||
|
|
||||||
if (pci_find_capability(iommu->dev, PCI_CAP_ID_MSI))
|
if (iommu->dev->msi_cap)
|
||||||
ret = iommu_setup_msi(iommu);
|
ret = iommu_setup_msi(iommu);
|
||||||
else
|
else
|
||||||
ret = -ENODEV;
|
ret = -ENODEV;
|
||||||
|
|
|
@ -56,9 +56,6 @@
|
||||||
/* Maximum number of mapping groups per SMMU */
|
/* Maximum number of mapping groups per SMMU */
|
||||||
#define ARM_SMMU_MAX_SMRS 128
|
#define ARM_SMMU_MAX_SMRS 128
|
||||||
|
|
||||||
/* Number of VMIDs per SMMU */
|
|
||||||
#define ARM_SMMU_NUM_VMIDS 256
|
|
||||||
|
|
||||||
/* SMMU global address space */
|
/* SMMU global address space */
|
||||||
#define ARM_SMMU_GR0(smmu) ((smmu)->base)
|
#define ARM_SMMU_GR0(smmu) ((smmu)->base)
|
||||||
#define ARM_SMMU_GR1(smmu) ((smmu)->base + (smmu)->pagesize)
|
#define ARM_SMMU_GR1(smmu) ((smmu)->base + (smmu)->pagesize)
|
||||||
|
@ -87,6 +84,7 @@
|
||||||
#define ARM_SMMU_PTE_AP_UNPRIV (((pteval_t)1) << 6)
|
#define ARM_SMMU_PTE_AP_UNPRIV (((pteval_t)1) << 6)
|
||||||
#define ARM_SMMU_PTE_AP_RDONLY (((pteval_t)2) << 6)
|
#define ARM_SMMU_PTE_AP_RDONLY (((pteval_t)2) << 6)
|
||||||
#define ARM_SMMU_PTE_ATTRINDX_SHIFT 2
|
#define ARM_SMMU_PTE_ATTRINDX_SHIFT 2
|
||||||
|
#define ARM_SMMU_PTE_nG (((pteval_t)1) << 11)
|
||||||
|
|
||||||
/* Stage-2 PTE */
|
/* Stage-2 PTE */
|
||||||
#define ARM_SMMU_PTE_HAP_FAULT (((pteval_t)0) << 6)
|
#define ARM_SMMU_PTE_HAP_FAULT (((pteval_t)0) << 6)
|
||||||
|
@ -223,6 +221,7 @@
|
||||||
#define ARM_SMMU_CB_FAR_LO 0x60
|
#define ARM_SMMU_CB_FAR_LO 0x60
|
||||||
#define ARM_SMMU_CB_FAR_HI 0x64
|
#define ARM_SMMU_CB_FAR_HI 0x64
|
||||||
#define ARM_SMMU_CB_FSYNR0 0x68
|
#define ARM_SMMU_CB_FSYNR0 0x68
|
||||||
|
#define ARM_SMMU_CB_S1_TLBIASID 0x610
|
||||||
|
|
||||||
#define SCTLR_S1_ASIDPNE (1 << 12)
|
#define SCTLR_S1_ASIDPNE (1 << 12)
|
||||||
#define SCTLR_CFCFG (1 << 7)
|
#define SCTLR_CFCFG (1 << 7)
|
||||||
|
@ -282,6 +281,8 @@
|
||||||
#define TTBCR2_ADDR_44 4
|
#define TTBCR2_ADDR_44 4
|
||||||
#define TTBCR2_ADDR_48 5
|
#define TTBCR2_ADDR_48 5
|
||||||
|
|
||||||
|
#define TTBRn_HI_ASID_SHIFT 16
|
||||||
|
|
||||||
#define MAIR_ATTR_SHIFT(n) ((n) << 3)
|
#define MAIR_ATTR_SHIFT(n) ((n) << 3)
|
||||||
#define MAIR_ATTR_MASK 0xff
|
#define MAIR_ATTR_MASK 0xff
|
||||||
#define MAIR_ATTR_DEVICE 0x04
|
#define MAIR_ATTR_DEVICE 0x04
|
||||||
|
@ -305,7 +306,7 @@
|
||||||
#define FSR_IGN (FSR_AFF | FSR_ASF | FSR_TLBMCF | \
|
#define FSR_IGN (FSR_AFF | FSR_ASF | FSR_TLBMCF | \
|
||||||
FSR_TLBLKF)
|
FSR_TLBLKF)
|
||||||
#define FSR_FAULT (FSR_MULTI | FSR_SS | FSR_UUT | \
|
#define FSR_FAULT (FSR_MULTI | FSR_SS | FSR_UUT | \
|
||||||
FSR_EF | FSR_PF | FSR_TF)
|
FSR_EF | FSR_PF | FSR_TF | FSR_IGN)
|
||||||
|
|
||||||
#define FSYNR0_WNR (1 << 4)
|
#define FSYNR0_WNR (1 << 4)
|
||||||
|
|
||||||
|
@ -365,21 +366,21 @@ struct arm_smmu_device {
|
||||||
u32 num_context_irqs;
|
u32 num_context_irqs;
|
||||||
unsigned int *irqs;
|
unsigned int *irqs;
|
||||||
|
|
||||||
DECLARE_BITMAP(vmid_map, ARM_SMMU_NUM_VMIDS);
|
|
||||||
|
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
struct rb_root masters;
|
struct rb_root masters;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct arm_smmu_cfg {
|
struct arm_smmu_cfg {
|
||||||
struct arm_smmu_device *smmu;
|
struct arm_smmu_device *smmu;
|
||||||
u8 vmid;
|
|
||||||
u8 cbndx;
|
u8 cbndx;
|
||||||
u8 irptndx;
|
u8 irptndx;
|
||||||
u32 cbar;
|
u32 cbar;
|
||||||
pgd_t *pgd;
|
pgd_t *pgd;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define ARM_SMMU_CB_ASID(cfg) ((cfg)->cbndx)
|
||||||
|
#define ARM_SMMU_CB_VMID(cfg) ((cfg)->cbndx + 1)
|
||||||
|
|
||||||
struct arm_smmu_domain {
|
struct arm_smmu_domain {
|
||||||
/*
|
/*
|
||||||
* A domain can span across multiple, chained SMMUs and requires
|
* A domain can span across multiple, chained SMMUs and requires
|
||||||
|
@ -533,6 +534,25 @@ static void arm_smmu_tlb_sync(struct arm_smmu_device *smmu)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void arm_smmu_tlb_inv_context(struct arm_smmu_cfg *cfg)
|
||||||
|
{
|
||||||
|
struct arm_smmu_device *smmu = cfg->smmu;
|
||||||
|
void __iomem *base = ARM_SMMU_GR0(smmu);
|
||||||
|
bool stage1 = cfg->cbar != CBAR_TYPE_S2_TRANS;
|
||||||
|
|
||||||
|
if (stage1) {
|
||||||
|
base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx);
|
||||||
|
writel_relaxed(ARM_SMMU_CB_ASID(cfg),
|
||||||
|
base + ARM_SMMU_CB_S1_TLBIASID);
|
||||||
|
} else {
|
||||||
|
base = ARM_SMMU_GR0(smmu);
|
||||||
|
writel_relaxed(ARM_SMMU_CB_VMID(cfg),
|
||||||
|
base + ARM_SMMU_GR0_TLBIVMID);
|
||||||
|
}
|
||||||
|
|
||||||
|
arm_smmu_tlb_sync(smmu);
|
||||||
|
}
|
||||||
|
|
||||||
static irqreturn_t arm_smmu_context_fault(int irq, void *dev)
|
static irqreturn_t arm_smmu_context_fault(int irq, void *dev)
|
||||||
{
|
{
|
||||||
int flags, ret;
|
int flags, ret;
|
||||||
|
@ -590,6 +610,9 @@ static irqreturn_t arm_smmu_global_fault(int irq, void *dev)
|
||||||
void __iomem *gr0_base = ARM_SMMU_GR0(smmu);
|
void __iomem *gr0_base = ARM_SMMU_GR0(smmu);
|
||||||
|
|
||||||
gfsr = readl_relaxed(gr0_base + ARM_SMMU_GR0_sGFSR);
|
gfsr = readl_relaxed(gr0_base + ARM_SMMU_GR0_sGFSR);
|
||||||
|
if (!gfsr)
|
||||||
|
return IRQ_NONE;
|
||||||
|
|
||||||
gfsynr0 = readl_relaxed(gr0_base + ARM_SMMU_GR0_sGFSYNR0);
|
gfsynr0 = readl_relaxed(gr0_base + ARM_SMMU_GR0_sGFSYNR0);
|
||||||
gfsynr1 = readl_relaxed(gr0_base + ARM_SMMU_GR0_sGFSYNR1);
|
gfsynr1 = readl_relaxed(gr0_base + ARM_SMMU_GR0_sGFSYNR1);
|
||||||
gfsynr2 = readl_relaxed(gr0_base + ARM_SMMU_GR0_sGFSYNR2);
|
gfsynr2 = readl_relaxed(gr0_base + ARM_SMMU_GR0_sGFSYNR2);
|
||||||
|
@ -601,7 +624,7 @@ static irqreturn_t arm_smmu_global_fault(int irq, void *dev)
|
||||||
gfsr, gfsynr0, gfsynr1, gfsynr2);
|
gfsr, gfsynr0, gfsynr1, gfsynr2);
|
||||||
|
|
||||||
writel(gfsr, gr0_base + ARM_SMMU_GR0_sGFSR);
|
writel(gfsr, gr0_base + ARM_SMMU_GR0_sGFSR);
|
||||||
return IRQ_NONE;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain)
|
static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain)
|
||||||
|
@ -618,14 +641,15 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain)
|
||||||
cb_base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, root_cfg->cbndx);
|
cb_base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, root_cfg->cbndx);
|
||||||
|
|
||||||
/* CBAR */
|
/* CBAR */
|
||||||
reg = root_cfg->cbar |
|
reg = root_cfg->cbar;
|
||||||
(root_cfg->vmid << CBAR_VMID_SHIFT);
|
|
||||||
if (smmu->version == 1)
|
if (smmu->version == 1)
|
||||||
reg |= root_cfg->irptndx << CBAR_IRPTNDX_SHIFT;
|
reg |= root_cfg->irptndx << CBAR_IRPTNDX_SHIFT;
|
||||||
|
|
||||||
/* Use the weakest memory type, so it is overridden by the pte */
|
/* Use the weakest memory type, so it is overridden by the pte */
|
||||||
if (stage1)
|
if (stage1)
|
||||||
reg |= (CBAR_S1_MEMATTR_WB << CBAR_S1_MEMATTR_SHIFT);
|
reg |= (CBAR_S1_MEMATTR_WB << CBAR_S1_MEMATTR_SHIFT);
|
||||||
|
else
|
||||||
|
reg |= ARM_SMMU_CB_VMID(root_cfg) << CBAR_VMID_SHIFT;
|
||||||
writel_relaxed(reg, gr1_base + ARM_SMMU_GR1_CBAR(root_cfg->cbndx));
|
writel_relaxed(reg, gr1_base + ARM_SMMU_GR1_CBAR(root_cfg->cbndx));
|
||||||
|
|
||||||
if (smmu->version > 1) {
|
if (smmu->version > 1) {
|
||||||
|
@ -687,15 +711,11 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain)
|
||||||
|
|
||||||
/* TTBR0 */
|
/* TTBR0 */
|
||||||
reg = __pa(root_cfg->pgd);
|
reg = __pa(root_cfg->pgd);
|
||||||
#ifndef __BIG_ENDIAN
|
|
||||||
writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR0_LO);
|
writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR0_LO);
|
||||||
reg = (phys_addr_t)__pa(root_cfg->pgd) >> 32;
|
reg = (phys_addr_t)__pa(root_cfg->pgd) >> 32;
|
||||||
|
if (stage1)
|
||||||
|
reg |= ARM_SMMU_CB_ASID(root_cfg) << TTBRn_HI_ASID_SHIFT;
|
||||||
writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR0_HI);
|
writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR0_HI);
|
||||||
#else
|
|
||||||
writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR0_HI);
|
|
||||||
reg = (phys_addr_t)__pa(root_cfg->pgd) >> 32;
|
|
||||||
writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR0_LO);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TTBCR
|
* TTBCR
|
||||||
|
@ -750,10 +770,6 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain)
|
||||||
writel_relaxed(reg, cb_base + ARM_SMMU_CB_S1_MAIR0);
|
writel_relaxed(reg, cb_base + ARM_SMMU_CB_S1_MAIR0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Nuke the TLB */
|
|
||||||
writel_relaxed(root_cfg->vmid, gr0_base + ARM_SMMU_GR0_TLBIVMID);
|
|
||||||
arm_smmu_tlb_sync(smmu);
|
|
||||||
|
|
||||||
/* SCTLR */
|
/* SCTLR */
|
||||||
reg = SCTLR_CFCFG | SCTLR_CFIE | SCTLR_CFRE | SCTLR_M | SCTLR_EAE_SBOP;
|
reg = SCTLR_CFCFG | SCTLR_CFIE | SCTLR_CFRE | SCTLR_M | SCTLR_EAE_SBOP;
|
||||||
if (stage1)
|
if (stage1)
|
||||||
|
@ -790,11 +806,6 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain,
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = __arm_smmu_alloc_bitmap(smmu->vmid_map, 0, ARM_SMMU_NUM_VMIDS);
|
|
||||||
if (IS_ERR_VALUE(ret))
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
root_cfg->vmid = ret;
|
|
||||||
if (smmu->features & ARM_SMMU_FEAT_TRANS_NESTED) {
|
if (smmu->features & ARM_SMMU_FEAT_TRANS_NESTED) {
|
||||||
/*
|
/*
|
||||||
* We will likely want to change this if/when KVM gets
|
* We will likely want to change this if/when KVM gets
|
||||||
|
@ -813,10 +824,9 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain,
|
||||||
ret = __arm_smmu_alloc_bitmap(smmu->context_map, start,
|
ret = __arm_smmu_alloc_bitmap(smmu->context_map, start,
|
||||||
smmu->num_context_banks);
|
smmu->num_context_banks);
|
||||||
if (IS_ERR_VALUE(ret))
|
if (IS_ERR_VALUE(ret))
|
||||||
goto out_free_vmid;
|
return ret;
|
||||||
|
|
||||||
root_cfg->cbndx = ret;
|
root_cfg->cbndx = ret;
|
||||||
|
|
||||||
if (smmu->version == 1) {
|
if (smmu->version == 1) {
|
||||||
root_cfg->irptndx = atomic_inc_return(&smmu->irptndx);
|
root_cfg->irptndx = atomic_inc_return(&smmu->irptndx);
|
||||||
root_cfg->irptndx %= smmu->num_context_irqs;
|
root_cfg->irptndx %= smmu->num_context_irqs;
|
||||||
|
@ -840,8 +850,6 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain,
|
||||||
|
|
||||||
out_free_context:
|
out_free_context:
|
||||||
__arm_smmu_free_bitmap(smmu->context_map, root_cfg->cbndx);
|
__arm_smmu_free_bitmap(smmu->context_map, root_cfg->cbndx);
|
||||||
out_free_vmid:
|
|
||||||
__arm_smmu_free_bitmap(smmu->vmid_map, root_cfg->vmid);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -850,17 +858,22 @@ static void arm_smmu_destroy_domain_context(struct iommu_domain *domain)
|
||||||
struct arm_smmu_domain *smmu_domain = domain->priv;
|
struct arm_smmu_domain *smmu_domain = domain->priv;
|
||||||
struct arm_smmu_cfg *root_cfg = &smmu_domain->root_cfg;
|
struct arm_smmu_cfg *root_cfg = &smmu_domain->root_cfg;
|
||||||
struct arm_smmu_device *smmu = root_cfg->smmu;
|
struct arm_smmu_device *smmu = root_cfg->smmu;
|
||||||
|
void __iomem *cb_base;
|
||||||
int irq;
|
int irq;
|
||||||
|
|
||||||
if (!smmu)
|
if (!smmu)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
/* Disable the context bank and nuke the TLB before freeing it. */
|
||||||
|
cb_base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, root_cfg->cbndx);
|
||||||
|
writel_relaxed(0, cb_base + ARM_SMMU_CB_SCTLR);
|
||||||
|
arm_smmu_tlb_inv_context(root_cfg);
|
||||||
|
|
||||||
if (root_cfg->irptndx != -1) {
|
if (root_cfg->irptndx != -1) {
|
||||||
irq = smmu->irqs[smmu->num_global_irqs + root_cfg->irptndx];
|
irq = smmu->irqs[smmu->num_global_irqs + root_cfg->irptndx];
|
||||||
free_irq(irq, domain);
|
free_irq(irq, domain);
|
||||||
}
|
}
|
||||||
|
|
||||||
__arm_smmu_free_bitmap(smmu->vmid_map, root_cfg->vmid);
|
|
||||||
__arm_smmu_free_bitmap(smmu->context_map, root_cfg->cbndx);
|
__arm_smmu_free_bitmap(smmu->context_map, root_cfg->cbndx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -959,6 +972,11 @@ static void arm_smmu_free_pgtables(struct arm_smmu_domain *smmu_domain)
|
||||||
static void arm_smmu_domain_destroy(struct iommu_domain *domain)
|
static void arm_smmu_domain_destroy(struct iommu_domain *domain)
|
||||||
{
|
{
|
||||||
struct arm_smmu_domain *smmu_domain = domain->priv;
|
struct arm_smmu_domain *smmu_domain = domain->priv;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Free the domain resources. We assume that all devices have
|
||||||
|
* already been detached.
|
||||||
|
*/
|
||||||
arm_smmu_destroy_domain_context(domain);
|
arm_smmu_destroy_domain_context(domain);
|
||||||
arm_smmu_free_pgtables(smmu_domain);
|
arm_smmu_free_pgtables(smmu_domain);
|
||||||
kfree(smmu_domain);
|
kfree(smmu_domain);
|
||||||
|
@ -1199,7 +1217,7 @@ static int arm_smmu_alloc_init_pte(struct arm_smmu_device *smmu, pmd_t *pmd,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stage == 1) {
|
if (stage == 1) {
|
||||||
pteval |= ARM_SMMU_PTE_AP_UNPRIV;
|
pteval |= ARM_SMMU_PTE_AP_UNPRIV | ARM_SMMU_PTE_nG;
|
||||||
if (!(flags & IOMMU_WRITE) && (flags & IOMMU_READ))
|
if (!(flags & IOMMU_WRITE) && (flags & IOMMU_READ))
|
||||||
pteval |= ARM_SMMU_PTE_AP_RDONLY;
|
pteval |= ARM_SMMU_PTE_AP_RDONLY;
|
||||||
|
|
||||||
|
@ -1415,13 +1433,9 @@ static size_t arm_smmu_unmap(struct iommu_domain *domain, unsigned long iova,
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
struct arm_smmu_domain *smmu_domain = domain->priv;
|
struct arm_smmu_domain *smmu_domain = domain->priv;
|
||||||
struct arm_smmu_cfg *root_cfg = &smmu_domain->root_cfg;
|
|
||||||
struct arm_smmu_device *smmu = root_cfg->smmu;
|
|
||||||
void __iomem *gr0_base = ARM_SMMU_GR0(smmu);
|
|
||||||
|
|
||||||
ret = arm_smmu_handle_mapping(smmu_domain, iova, 0, size, 0);
|
ret = arm_smmu_handle_mapping(smmu_domain, iova, 0, size, 0);
|
||||||
writel_relaxed(root_cfg->vmid, gr0_base + ARM_SMMU_GR0_TLBIVMID);
|
arm_smmu_tlb_inv_context(&smmu_domain->root_cfg);
|
||||||
arm_smmu_tlb_sync(smmu);
|
|
||||||
return ret ? ret : size;
|
return ret ? ret : size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1544,6 +1558,7 @@ static struct iommu_ops arm_smmu_ops = {
|
||||||
static void arm_smmu_device_reset(struct arm_smmu_device *smmu)
|
static void arm_smmu_device_reset(struct arm_smmu_device *smmu)
|
||||||
{
|
{
|
||||||
void __iomem *gr0_base = ARM_SMMU_GR0(smmu);
|
void __iomem *gr0_base = ARM_SMMU_GR0(smmu);
|
||||||
|
void __iomem *sctlr_base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB_SCTLR;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
u32 scr0 = readl_relaxed(gr0_base + ARM_SMMU_GR0_sCR0);
|
u32 scr0 = readl_relaxed(gr0_base + ARM_SMMU_GR0_sCR0);
|
||||||
|
|
||||||
|
@ -1553,6 +1568,10 @@ static void arm_smmu_device_reset(struct arm_smmu_device *smmu)
|
||||||
writel_relaxed(S2CR_TYPE_BYPASS, gr0_base + ARM_SMMU_GR0_S2CR(i));
|
writel_relaxed(S2CR_TYPE_BYPASS, gr0_base + ARM_SMMU_GR0_S2CR(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Make sure all context banks are disabled */
|
||||||
|
for (i = 0; i < smmu->num_context_banks; ++i)
|
||||||
|
writel_relaxed(0, sctlr_base + ARM_SMMU_CB(smmu, i));
|
||||||
|
|
||||||
/* Invalidate the TLB, just in case */
|
/* Invalidate the TLB, just in case */
|
||||||
writel_relaxed(0, gr0_base + ARM_SMMU_GR0_STLBIALL);
|
writel_relaxed(0, gr0_base + ARM_SMMU_GR0_STLBIALL);
|
||||||
writel_relaxed(0, gr0_base + ARM_SMMU_GR0_TLBIALLH);
|
writel_relaxed(0, gr0_base + ARM_SMMU_GR0_TLBIALLH);
|
||||||
|
@ -1906,7 +1925,7 @@ static int arm_smmu_device_remove(struct platform_device *pdev)
|
||||||
of_node_put(master->of_node);
|
of_node_put(master->of_node);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!bitmap_empty(smmu->vmid_map, ARM_SMMU_NUM_VMIDS))
|
if (!bitmap_empty(smmu->context_map, ARM_SMMU_MAX_CBS))
|
||||||
dev_err(dev, "removing device with active domains!\n");
|
dev_err(dev, "removing device with active domains!\n");
|
||||||
|
|
||||||
for (i = 0; i < smmu->num_global_irqs; ++i)
|
for (i = 0; i < smmu->num_global_irqs; ++i)
|
||||||
|
|
|
@ -247,50 +247,6 @@ static void __sysmmu_set_prefbuf(void __iomem *sfrbase, unsigned long base,
|
||||||
__raw_writel(size - 1 + base, sfrbase + REG_PB0_EADDR + idx * 8);
|
__raw_writel(size - 1 + base, sfrbase + REG_PB0_EADDR + idx * 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
void exynos_sysmmu_set_prefbuf(struct device *dev,
|
|
||||||
unsigned long base0, unsigned long size0,
|
|
||||||
unsigned long base1, unsigned long size1)
|
|
||||||
{
|
|
||||||
struct sysmmu_drvdata *data = dev_get_drvdata(dev->archdata.iommu);
|
|
||||||
unsigned long flags;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
BUG_ON((base0 + size0) <= base0);
|
|
||||||
BUG_ON((size1 > 0) && ((base1 + size1) <= base1));
|
|
||||||
|
|
||||||
read_lock_irqsave(&data->lock, flags);
|
|
||||||
if (!is_sysmmu_active(data))
|
|
||||||
goto finish;
|
|
||||||
|
|
||||||
for (i = 0; i < data->nsfrs; i++) {
|
|
||||||
if ((readl(data->sfrbases[i] + REG_MMU_VERSION) >> 28) == 3) {
|
|
||||||
if (!sysmmu_block(data->sfrbases[i]))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (size1 == 0) {
|
|
||||||
if (size0 <= SZ_128K) {
|
|
||||||
base1 = base0;
|
|
||||||
size1 = size0;
|
|
||||||
} else {
|
|
||||||
size1 = size0 -
|
|
||||||
ALIGN(size0 / 2, SZ_64K);
|
|
||||||
size0 = size0 - size1;
|
|
||||||
base1 = base0 + size0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
__sysmmu_set_prefbuf(
|
|
||||||
data->sfrbases[i], base0, size0, 0);
|
|
||||||
__sysmmu_set_prefbuf(
|
|
||||||
data->sfrbases[i], base1, size1, 1);
|
|
||||||
|
|
||||||
sysmmu_unblock(data->sfrbases[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finish:
|
|
||||||
read_unlock_irqrestore(&data->lock, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void __set_fault_handler(struct sysmmu_drvdata *data,
|
static void __set_fault_handler(struct sysmmu_drvdata *data,
|
||||||
sysmmu_fault_handler_t handler)
|
sysmmu_fault_handler_t handler)
|
||||||
{
|
{
|
||||||
|
|
1309
drivers/iommu/fsl_pamu.c
Normal file
1309
drivers/iommu/fsl_pamu.c
Normal file
File diff suppressed because it is too large
Load diff
410
drivers/iommu/fsl_pamu.h
Normal file
410
drivers/iommu/fsl_pamu.h
Normal file
|
@ -0,0 +1,410 @@
|
||||||
|
/*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License, version 2, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2013 Freescale Semiconductor, Inc.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __FSL_PAMU_H
|
||||||
|
#define __FSL_PAMU_H
|
||||||
|
|
||||||
|
#include <asm/fsl_pamu_stash.h>
|
||||||
|
|
||||||
|
/* Bit Field macros
|
||||||
|
* v = bit field variable; m = mask, m##_SHIFT = shift, x = value to load
|
||||||
|
*/
|
||||||
|
#define set_bf(v, m, x) (v = ((v) & ~(m)) | (((x) << (m##_SHIFT)) & (m)))
|
||||||
|
#define get_bf(v, m) (((v) & (m)) >> (m##_SHIFT))
|
||||||
|
|
||||||
|
/* PAMU CCSR space */
|
||||||
|
#define PAMU_PGC 0x00000000 /* Allows all peripheral accesses */
|
||||||
|
#define PAMU_PE 0x40000000 /* enable PAMU */
|
||||||
|
|
||||||
|
/* PAMU_OFFSET to the next pamu space in ccsr */
|
||||||
|
#define PAMU_OFFSET 0x1000
|
||||||
|
|
||||||
|
#define PAMU_MMAP_REGS_BASE 0
|
||||||
|
|
||||||
|
struct pamu_mmap_regs {
|
||||||
|
u32 ppbah;
|
||||||
|
u32 ppbal;
|
||||||
|
u32 pplah;
|
||||||
|
u32 pplal;
|
||||||
|
u32 spbah;
|
||||||
|
u32 spbal;
|
||||||
|
u32 splah;
|
||||||
|
u32 splal;
|
||||||
|
u32 obah;
|
||||||
|
u32 obal;
|
||||||
|
u32 olah;
|
||||||
|
u32 olal;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* PAMU Error Registers */
|
||||||
|
#define PAMU_POES1 0x0040
|
||||||
|
#define PAMU_POES2 0x0044
|
||||||
|
#define PAMU_POEAH 0x0048
|
||||||
|
#define PAMU_POEAL 0x004C
|
||||||
|
#define PAMU_AVS1 0x0050
|
||||||
|
#define PAMU_AVS1_AV 0x1
|
||||||
|
#define PAMU_AVS1_OTV 0x6
|
||||||
|
#define PAMU_AVS1_APV 0x78
|
||||||
|
#define PAMU_AVS1_WAV 0x380
|
||||||
|
#define PAMU_AVS1_LAV 0x1c00
|
||||||
|
#define PAMU_AVS1_GCV 0x2000
|
||||||
|
#define PAMU_AVS1_PDV 0x4000
|
||||||
|
#define PAMU_AV_MASK (PAMU_AVS1_AV | PAMU_AVS1_OTV | PAMU_AVS1_APV | PAMU_AVS1_WAV \
|
||||||
|
| PAMU_AVS1_LAV | PAMU_AVS1_GCV | PAMU_AVS1_PDV)
|
||||||
|
#define PAMU_AVS1_LIODN_SHIFT 16
|
||||||
|
#define PAMU_LAV_LIODN_NOT_IN_PPAACT 0x400
|
||||||
|
|
||||||
|
#define PAMU_AVS2 0x0054
|
||||||
|
#define PAMU_AVAH 0x0058
|
||||||
|
#define PAMU_AVAL 0x005C
|
||||||
|
#define PAMU_EECTL 0x0060
|
||||||
|
#define PAMU_EEDIS 0x0064
|
||||||
|
#define PAMU_EEINTEN 0x0068
|
||||||
|
#define PAMU_EEDET 0x006C
|
||||||
|
#define PAMU_EEATTR 0x0070
|
||||||
|
#define PAMU_EEAHI 0x0074
|
||||||
|
#define PAMU_EEALO 0x0078
|
||||||
|
#define PAMU_EEDHI 0X007C
|
||||||
|
#define PAMU_EEDLO 0x0080
|
||||||
|
#define PAMU_EECC 0x0084
|
||||||
|
#define PAMU_UDAD 0x0090
|
||||||
|
|
||||||
|
/* PAMU Revision Registers */
|
||||||
|
#define PAMU_PR1 0x0BF8
|
||||||
|
#define PAMU_PR2 0x0BFC
|
||||||
|
|
||||||
|
/* PAMU version mask */
|
||||||
|
#define PAMU_PR1_MASK 0xffff
|
||||||
|
|
||||||
|
/* PAMU Capabilities Registers */
|
||||||
|
#define PAMU_PC1 0x0C00
|
||||||
|
#define PAMU_PC2 0x0C04
|
||||||
|
#define PAMU_PC3 0x0C08
|
||||||
|
#define PAMU_PC4 0x0C0C
|
||||||
|
|
||||||
|
/* PAMU Control Register */
|
||||||
|
#define PAMU_PC 0x0C10
|
||||||
|
|
||||||
|
/* PAMU control defs */
|
||||||
|
#define PAMU_CONTROL 0x0C10
|
||||||
|
#define PAMU_PC_PGC 0x80000000 /* PAMU gate closed bit */
|
||||||
|
#define PAMU_PC_PE 0x40000000 /* PAMU enable bit */
|
||||||
|
#define PAMU_PC_SPCC 0x00000010 /* sPAACE cache enable */
|
||||||
|
#define PAMU_PC_PPCC 0x00000001 /* pPAACE cache enable */
|
||||||
|
#define PAMU_PC_OCE 0x00001000 /* OMT cache enable */
|
||||||
|
|
||||||
|
#define PAMU_PFA1 0x0C14
|
||||||
|
#define PAMU_PFA2 0x0C18
|
||||||
|
|
||||||
|
#define PAMU_PC2_MLIODN(X) ((X) >> 16)
|
||||||
|
#define PAMU_PC3_MWCE(X) (((X) >> 21) & 0xf)
|
||||||
|
|
||||||
|
/* PAMU Interrupt control and Status Register */
|
||||||
|
#define PAMU_PICS 0x0C1C
|
||||||
|
#define PAMU_ACCESS_VIOLATION_STAT 0x8
|
||||||
|
#define PAMU_ACCESS_VIOLATION_ENABLE 0x4
|
||||||
|
|
||||||
|
/* PAMU Debug Registers */
|
||||||
|
#define PAMU_PD1 0x0F00
|
||||||
|
#define PAMU_PD2 0x0F04
|
||||||
|
#define PAMU_PD3 0x0F08
|
||||||
|
#define PAMU_PD4 0x0F0C
|
||||||
|
|
||||||
|
#define PAACE_AP_PERMS_DENIED 0x0
|
||||||
|
#define PAACE_AP_PERMS_QUERY 0x1
|
||||||
|
#define PAACE_AP_PERMS_UPDATE 0x2
|
||||||
|
#define PAACE_AP_PERMS_ALL 0x3
|
||||||
|
|
||||||
|
#define PAACE_DD_TO_HOST 0x0
|
||||||
|
#define PAACE_DD_TO_IO 0x1
|
||||||
|
#define PAACE_PT_PRIMARY 0x0
|
||||||
|
#define PAACE_PT_SECONDARY 0x1
|
||||||
|
#define PAACE_V_INVALID 0x0
|
||||||
|
#define PAACE_V_VALID 0x1
|
||||||
|
#define PAACE_MW_SUBWINDOWS 0x1
|
||||||
|
|
||||||
|
#define PAACE_WSE_4K 0xB
|
||||||
|
#define PAACE_WSE_8K 0xC
|
||||||
|
#define PAACE_WSE_16K 0xD
|
||||||
|
#define PAACE_WSE_32K 0xE
|
||||||
|
#define PAACE_WSE_64K 0xF
|
||||||
|
#define PAACE_WSE_128K 0x10
|
||||||
|
#define PAACE_WSE_256K 0x11
|
||||||
|
#define PAACE_WSE_512K 0x12
|
||||||
|
#define PAACE_WSE_1M 0x13
|
||||||
|
#define PAACE_WSE_2M 0x14
|
||||||
|
#define PAACE_WSE_4M 0x15
|
||||||
|
#define PAACE_WSE_8M 0x16
|
||||||
|
#define PAACE_WSE_16M 0x17
|
||||||
|
#define PAACE_WSE_32M 0x18
|
||||||
|
#define PAACE_WSE_64M 0x19
|
||||||
|
#define PAACE_WSE_128M 0x1A
|
||||||
|
#define PAACE_WSE_256M 0x1B
|
||||||
|
#define PAACE_WSE_512M 0x1C
|
||||||
|
#define PAACE_WSE_1G 0x1D
|
||||||
|
#define PAACE_WSE_2G 0x1E
|
||||||
|
#define PAACE_WSE_4G 0x1F
|
||||||
|
|
||||||
|
#define PAACE_DID_PCI_EXPRESS_1 0x00
|
||||||
|
#define PAACE_DID_PCI_EXPRESS_2 0x01
|
||||||
|
#define PAACE_DID_PCI_EXPRESS_3 0x02
|
||||||
|
#define PAACE_DID_PCI_EXPRESS_4 0x03
|
||||||
|
#define PAACE_DID_LOCAL_BUS 0x04
|
||||||
|
#define PAACE_DID_SRIO 0x0C
|
||||||
|
#define PAACE_DID_MEM_1 0x10
|
||||||
|
#define PAACE_DID_MEM_2 0x11
|
||||||
|
#define PAACE_DID_MEM_3 0x12
|
||||||
|
#define PAACE_DID_MEM_4 0x13
|
||||||
|
#define PAACE_DID_MEM_1_2 0x14
|
||||||
|
#define PAACE_DID_MEM_3_4 0x15
|
||||||
|
#define PAACE_DID_MEM_1_4 0x16
|
||||||
|
#define PAACE_DID_BM_SW_PORTAL 0x18
|
||||||
|
#define PAACE_DID_PAMU 0x1C
|
||||||
|
#define PAACE_DID_CAAM 0x21
|
||||||
|
#define PAACE_DID_QM_SW_PORTAL 0x3C
|
||||||
|
#define PAACE_DID_CORE0_INST 0x80
|
||||||
|
#define PAACE_DID_CORE0_DATA 0x81
|
||||||
|
#define PAACE_DID_CORE1_INST 0x82
|
||||||
|
#define PAACE_DID_CORE1_DATA 0x83
|
||||||
|
#define PAACE_DID_CORE2_INST 0x84
|
||||||
|
#define PAACE_DID_CORE2_DATA 0x85
|
||||||
|
#define PAACE_DID_CORE3_INST 0x86
|
||||||
|
#define PAACE_DID_CORE3_DATA 0x87
|
||||||
|
#define PAACE_DID_CORE4_INST 0x88
|
||||||
|
#define PAACE_DID_CORE4_DATA 0x89
|
||||||
|
#define PAACE_DID_CORE5_INST 0x8A
|
||||||
|
#define PAACE_DID_CORE5_DATA 0x8B
|
||||||
|
#define PAACE_DID_CORE6_INST 0x8C
|
||||||
|
#define PAACE_DID_CORE6_DATA 0x8D
|
||||||
|
#define PAACE_DID_CORE7_INST 0x8E
|
||||||
|
#define PAACE_DID_CORE7_DATA 0x8F
|
||||||
|
#define PAACE_DID_BROADCAST 0xFF
|
||||||
|
|
||||||
|
#define PAACE_ATM_NO_XLATE 0x00
|
||||||
|
#define PAACE_ATM_WINDOW_XLATE 0x01
|
||||||
|
#define PAACE_ATM_PAGE_XLATE 0x02
|
||||||
|
#define PAACE_ATM_WIN_PG_XLATE \
|
||||||
|
(PAACE_ATM_WINDOW_XLATE | PAACE_ATM_PAGE_XLATE)
|
||||||
|
#define PAACE_OTM_NO_XLATE 0x00
|
||||||
|
#define PAACE_OTM_IMMEDIATE 0x01
|
||||||
|
#define PAACE_OTM_INDEXED 0x02
|
||||||
|
#define PAACE_OTM_RESERVED 0x03
|
||||||
|
|
||||||
|
#define PAACE_M_COHERENCE_REQ 0x01
|
||||||
|
|
||||||
|
#define PAACE_PID_0 0x0
|
||||||
|
#define PAACE_PID_1 0x1
|
||||||
|
#define PAACE_PID_2 0x2
|
||||||
|
#define PAACE_PID_3 0x3
|
||||||
|
#define PAACE_PID_4 0x4
|
||||||
|
#define PAACE_PID_5 0x5
|
||||||
|
#define PAACE_PID_6 0x6
|
||||||
|
#define PAACE_PID_7 0x7
|
||||||
|
|
||||||
|
#define PAACE_TCEF_FORMAT0_8B 0x00
|
||||||
|
#define PAACE_TCEF_FORMAT1_RSVD 0x01
|
||||||
|
/*
|
||||||
|
* Hard coded value for the PAACT size to accomodate
|
||||||
|
* maximum LIODN value generated by u-boot.
|
||||||
|
*/
|
||||||
|
#define PAACE_NUMBER_ENTRIES 0x500
|
||||||
|
/* Hard coded value for the SPAACT size */
|
||||||
|
#define SPAACE_NUMBER_ENTRIES 0x800
|
||||||
|
|
||||||
|
#define OME_NUMBER_ENTRIES 16
|
||||||
|
|
||||||
|
/* PAACE Bit Field Defines */
|
||||||
|
#define PPAACE_AF_WBAL 0xfffff000
|
||||||
|
#define PPAACE_AF_WBAL_SHIFT 12
|
||||||
|
#define PPAACE_AF_WSE 0x00000fc0
|
||||||
|
#define PPAACE_AF_WSE_SHIFT 6
|
||||||
|
#define PPAACE_AF_MW 0x00000020
|
||||||
|
#define PPAACE_AF_MW_SHIFT 5
|
||||||
|
|
||||||
|
#define SPAACE_AF_LIODN 0xffff0000
|
||||||
|
#define SPAACE_AF_LIODN_SHIFT 16
|
||||||
|
|
||||||
|
#define PAACE_AF_AP 0x00000018
|
||||||
|
#define PAACE_AF_AP_SHIFT 3
|
||||||
|
#define PAACE_AF_DD 0x00000004
|
||||||
|
#define PAACE_AF_DD_SHIFT 2
|
||||||
|
#define PAACE_AF_PT 0x00000002
|
||||||
|
#define PAACE_AF_PT_SHIFT 1
|
||||||
|
#define PAACE_AF_V 0x00000001
|
||||||
|
#define PAACE_AF_V_SHIFT 0
|
||||||
|
|
||||||
|
#define PAACE_DA_HOST_CR 0x80
|
||||||
|
#define PAACE_DA_HOST_CR_SHIFT 7
|
||||||
|
|
||||||
|
#define PAACE_IA_CID 0x00FF0000
|
||||||
|
#define PAACE_IA_CID_SHIFT 16
|
||||||
|
#define PAACE_IA_WCE 0x000000F0
|
||||||
|
#define PAACE_IA_WCE_SHIFT 4
|
||||||
|
#define PAACE_IA_ATM 0x0000000C
|
||||||
|
#define PAACE_IA_ATM_SHIFT 2
|
||||||
|
#define PAACE_IA_OTM 0x00000003
|
||||||
|
#define PAACE_IA_OTM_SHIFT 0
|
||||||
|
|
||||||
|
#define PAACE_WIN_TWBAL 0xfffff000
|
||||||
|
#define PAACE_WIN_TWBAL_SHIFT 12
|
||||||
|
#define PAACE_WIN_SWSE 0x00000fc0
|
||||||
|
#define PAACE_WIN_SWSE_SHIFT 6
|
||||||
|
|
||||||
|
/* PAMU Data Structures */
|
||||||
|
/* primary / secondary paact structure */
|
||||||
|
struct paace {
|
||||||
|
/* PAACE Offset 0x00 */
|
||||||
|
u32 wbah; /* only valid for Primary PAACE */
|
||||||
|
u32 addr_bitfields; /* See P/S PAACE_AF_* */
|
||||||
|
|
||||||
|
/* PAACE Offset 0x08 */
|
||||||
|
/* Interpretation of first 32 bits dependent on DD above */
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
/* Destination ID, see PAACE_DID_* defines */
|
||||||
|
u8 did;
|
||||||
|
/* Partition ID */
|
||||||
|
u8 pid;
|
||||||
|
/* Snoop ID */
|
||||||
|
u8 snpid;
|
||||||
|
/* coherency_required : 1 reserved : 7 */
|
||||||
|
u8 coherency_required; /* See PAACE_DA_* */
|
||||||
|
} to_host;
|
||||||
|
struct {
|
||||||
|
/* Destination ID, see PAACE_DID_* defines */
|
||||||
|
u8 did;
|
||||||
|
u8 reserved1;
|
||||||
|
u16 reserved2;
|
||||||
|
} to_io;
|
||||||
|
} domain_attr;
|
||||||
|
|
||||||
|
/* Implementation attributes + window count + address & operation translation modes */
|
||||||
|
u32 impl_attr; /* See PAACE_IA_* */
|
||||||
|
|
||||||
|
/* PAACE Offset 0x10 */
|
||||||
|
/* Translated window base address */
|
||||||
|
u32 twbah;
|
||||||
|
u32 win_bitfields; /* See PAACE_WIN_* */
|
||||||
|
|
||||||
|
/* PAACE Offset 0x18 */
|
||||||
|
/* first secondary paace entry */
|
||||||
|
u32 fspi; /* only valid for Primary PAACE */
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
u8 ioea;
|
||||||
|
u8 moea;
|
||||||
|
u8 ioeb;
|
||||||
|
u8 moeb;
|
||||||
|
} immed_ot;
|
||||||
|
struct {
|
||||||
|
u16 reserved;
|
||||||
|
u16 omi;
|
||||||
|
} index_ot;
|
||||||
|
} op_encode;
|
||||||
|
|
||||||
|
/* PAACE Offsets 0x20-0x38 */
|
||||||
|
u32 reserved[8]; /* not currently implemented */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* OME : Operation mapping entry
|
||||||
|
* MOE : Mapped Operation Encodings
|
||||||
|
* The operation mapping table is table containing operation mapping entries (OME).
|
||||||
|
* The index of a particular OME is programmed in the PAACE entry for translation
|
||||||
|
* in bound I/O operations corresponding to an LIODN. The OMT is used for translation
|
||||||
|
* specifically in case of the indexed translation mode. Each OME contains a 128
|
||||||
|
* byte mapped operation encoding (MOE), where each byte represents an MOE.
|
||||||
|
*/
|
||||||
|
#define NUM_MOE 128
|
||||||
|
struct ome {
|
||||||
|
u8 moe[NUM_MOE];
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
#define PAACT_SIZE (sizeof(struct paace) * PAACE_NUMBER_ENTRIES)
|
||||||
|
#define SPAACT_SIZE (sizeof(struct paace) * SPAACE_NUMBER_ENTRIES)
|
||||||
|
#define OMT_SIZE (sizeof(struct ome) * OME_NUMBER_ENTRIES)
|
||||||
|
|
||||||
|
#define PAMU_PAGE_SHIFT 12
|
||||||
|
#define PAMU_PAGE_SIZE 4096ULL
|
||||||
|
|
||||||
|
#define IOE_READ 0x00
|
||||||
|
#define IOE_READ_IDX 0x00
|
||||||
|
#define IOE_WRITE 0x81
|
||||||
|
#define IOE_WRITE_IDX 0x01
|
||||||
|
#define IOE_EREAD0 0x82 /* Enhanced read type 0 */
|
||||||
|
#define IOE_EREAD0_IDX 0x02 /* Enhanced read type 0 */
|
||||||
|
#define IOE_EWRITE0 0x83 /* Enhanced write type 0 */
|
||||||
|
#define IOE_EWRITE0_IDX 0x03 /* Enhanced write type 0 */
|
||||||
|
#define IOE_DIRECT0 0x84 /* Directive type 0 */
|
||||||
|
#define IOE_DIRECT0_IDX 0x04 /* Directive type 0 */
|
||||||
|
#define IOE_EREAD1 0x85 /* Enhanced read type 1 */
|
||||||
|
#define IOE_EREAD1_IDX 0x05 /* Enhanced read type 1 */
|
||||||
|
#define IOE_EWRITE1 0x86 /* Enhanced write type 1 */
|
||||||
|
#define IOE_EWRITE1_IDX 0x06 /* Enhanced write type 1 */
|
||||||
|
#define IOE_DIRECT1 0x87 /* Directive type 1 */
|
||||||
|
#define IOE_DIRECT1_IDX 0x07 /* Directive type 1 */
|
||||||
|
#define IOE_RAC 0x8c /* Read with Atomic clear */
|
||||||
|
#define IOE_RAC_IDX 0x0c /* Read with Atomic clear */
|
||||||
|
#define IOE_RAS 0x8d /* Read with Atomic set */
|
||||||
|
#define IOE_RAS_IDX 0x0d /* Read with Atomic set */
|
||||||
|
#define IOE_RAD 0x8e /* Read with Atomic decrement */
|
||||||
|
#define IOE_RAD_IDX 0x0e /* Read with Atomic decrement */
|
||||||
|
#define IOE_RAI 0x8f /* Read with Atomic increment */
|
||||||
|
#define IOE_RAI_IDX 0x0f /* Read with Atomic increment */
|
||||||
|
|
||||||
|
#define EOE_READ 0x00
|
||||||
|
#define EOE_WRITE 0x01
|
||||||
|
#define EOE_RAC 0x0c /* Read with Atomic clear */
|
||||||
|
#define EOE_RAS 0x0d /* Read with Atomic set */
|
||||||
|
#define EOE_RAD 0x0e /* Read with Atomic decrement */
|
||||||
|
#define EOE_RAI 0x0f /* Read with Atomic increment */
|
||||||
|
#define EOE_LDEC 0x10 /* Load external cache */
|
||||||
|
#define EOE_LDECL 0x11 /* Load external cache with stash lock */
|
||||||
|
#define EOE_LDECPE 0x12 /* Load external cache with preferred exclusive */
|
||||||
|
#define EOE_LDECPEL 0x13 /* Load external cache with preferred exclusive and lock */
|
||||||
|
#define EOE_LDECFE 0x14 /* Load external cache with forced exclusive */
|
||||||
|
#define EOE_LDECFEL 0x15 /* Load external cache with forced exclusive and lock */
|
||||||
|
#define EOE_RSA 0x16 /* Read with stash allocate */
|
||||||
|
#define EOE_RSAU 0x17 /* Read with stash allocate and unlock */
|
||||||
|
#define EOE_READI 0x18 /* Read with invalidate */
|
||||||
|
#define EOE_RWNITC 0x19 /* Read with no intention to cache */
|
||||||
|
#define EOE_WCI 0x1a /* Write cache inhibited */
|
||||||
|
#define EOE_WWSA 0x1b /* Write with stash allocate */
|
||||||
|
#define EOE_WWSAL 0x1c /* Write with stash allocate and lock */
|
||||||
|
#define EOE_WWSAO 0x1d /* Write with stash allocate only */
|
||||||
|
#define EOE_WWSAOL 0x1e /* Write with stash allocate only and lock */
|
||||||
|
#define EOE_VALID 0x80
|
||||||
|
|
||||||
|
/* Function prototypes */
|
||||||
|
int pamu_domain_init(void);
|
||||||
|
int pamu_enable_liodn(int liodn);
|
||||||
|
int pamu_disable_liodn(int liodn);
|
||||||
|
void pamu_free_subwins(int liodn);
|
||||||
|
int pamu_config_ppaace(int liodn, phys_addr_t win_addr, phys_addr_t win_size,
|
||||||
|
u32 omi, unsigned long rpn, u32 snoopid, uint32_t stashid,
|
||||||
|
u32 subwin_cnt, int prot);
|
||||||
|
int pamu_config_spaace(int liodn, u32 subwin_cnt, u32 subwin_addr,
|
||||||
|
phys_addr_t subwin_size, u32 omi, unsigned long rpn,
|
||||||
|
uint32_t snoopid, u32 stashid, int enable, int prot);
|
||||||
|
|
||||||
|
u32 get_stash_id(u32 stash_dest_hint, u32 vcpu);
|
||||||
|
void get_ome_index(u32 *omi_index, struct device *dev);
|
||||||
|
int pamu_update_paace_stash(int liodn, u32 subwin, u32 value);
|
||||||
|
int pamu_disable_spaace(int liodn, u32 subwin);
|
||||||
|
u32 pamu_get_max_subwin_cnt(void);
|
||||||
|
|
||||||
|
#endif /* __FSL_PAMU_H */
|
1172
drivers/iommu/fsl_pamu_domain.c
Normal file
1172
drivers/iommu/fsl_pamu_domain.c
Normal file
File diff suppressed because it is too large
Load diff
85
drivers/iommu/fsl_pamu_domain.h
Normal file
85
drivers/iommu/fsl_pamu_domain.h
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
/*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License, version 2, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2013 Freescale Semiconductor, Inc.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __FSL_PAMU_DOMAIN_H
|
||||||
|
#define __FSL_PAMU_DOMAIN_H
|
||||||
|
|
||||||
|
#include "fsl_pamu.h"
|
||||||
|
|
||||||
|
struct dma_window {
|
||||||
|
phys_addr_t paddr;
|
||||||
|
u64 size;
|
||||||
|
int valid;
|
||||||
|
int prot;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct fsl_dma_domain {
|
||||||
|
/*
|
||||||
|
* Indicates the geometry size for the domain.
|
||||||
|
* This would be set when the geometry is
|
||||||
|
* configured for the domain.
|
||||||
|
*/
|
||||||
|
dma_addr_t geom_size;
|
||||||
|
/*
|
||||||
|
* Number of windows assocaited with this domain.
|
||||||
|
* During domain initialization, it is set to the
|
||||||
|
* the maximum number of subwindows allowed for a LIODN.
|
||||||
|
* Minimum value for this is 1 indicating a single PAMU
|
||||||
|
* window, without any sub windows. Value can be set/
|
||||||
|
* queried by set_attr/get_attr API for DOMAIN_ATTR_WINDOWS.
|
||||||
|
* Value can only be set once the geometry has been configured.
|
||||||
|
*/
|
||||||
|
u32 win_cnt;
|
||||||
|
/*
|
||||||
|
* win_arr contains information of the configured
|
||||||
|
* windows for a domain. This is allocated only
|
||||||
|
* when the number of windows for the domain are
|
||||||
|
* set.
|
||||||
|
*/
|
||||||
|
struct dma_window *win_arr;
|
||||||
|
/* list of devices associated with the domain */
|
||||||
|
struct list_head devices;
|
||||||
|
/* dma_domain states:
|
||||||
|
* mapped - A particular mapping has been created
|
||||||
|
* within the configured geometry.
|
||||||
|
* enabled - DMA has been enabled for the given
|
||||||
|
* domain. This translates to setting of the
|
||||||
|
* valid bit for the primary PAACE in the PAMU
|
||||||
|
* PAACT table. Domain geometry should be set and
|
||||||
|
* it must have a valid mapping before DMA can be
|
||||||
|
* enabled for it.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int mapped;
|
||||||
|
int enabled;
|
||||||
|
/* stash_id obtained from the stash attribute details */
|
||||||
|
u32 stash_id;
|
||||||
|
struct pamu_stash_attribute dma_stash;
|
||||||
|
u32 snoop_id;
|
||||||
|
struct iommu_domain *iommu_domain;
|
||||||
|
spinlock_t domain_lock;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* domain-device relationship */
|
||||||
|
struct device_domain_info {
|
||||||
|
struct list_head link; /* link to domain siblings */
|
||||||
|
struct device *dev;
|
||||||
|
u32 liodn;
|
||||||
|
struct fsl_dma_domain *domain; /* pointer to domain */
|
||||||
|
};
|
||||||
|
#endif /* __FSL_PAMU_DOMAIN_H */
|
|
@ -890,56 +890,54 @@ static int dma_pte_clear_range(struct dmar_domain *domain,
|
||||||
return order;
|
return order;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void dma_pte_free_level(struct dmar_domain *domain, int level,
|
||||||
|
struct dma_pte *pte, unsigned long pfn,
|
||||||
|
unsigned long start_pfn, unsigned long last_pfn)
|
||||||
|
{
|
||||||
|
pfn = max(start_pfn, pfn);
|
||||||
|
pte = &pte[pfn_level_offset(pfn, level)];
|
||||||
|
|
||||||
|
do {
|
||||||
|
unsigned long level_pfn;
|
||||||
|
struct dma_pte *level_pte;
|
||||||
|
|
||||||
|
if (!dma_pte_present(pte) || dma_pte_superpage(pte))
|
||||||
|
goto next;
|
||||||
|
|
||||||
|
level_pfn = pfn & level_mask(level - 1);
|
||||||
|
level_pte = phys_to_virt(dma_pte_addr(pte));
|
||||||
|
|
||||||
|
if (level > 2)
|
||||||
|
dma_pte_free_level(domain, level - 1, level_pte,
|
||||||
|
level_pfn, start_pfn, last_pfn);
|
||||||
|
|
||||||
|
/* If range covers entire pagetable, free it */
|
||||||
|
if (!(start_pfn > level_pfn ||
|
||||||
|
last_pfn < level_pfn + level_size(level))) {
|
||||||
|
dma_clear_pte(pte);
|
||||||
|
domain_flush_cache(domain, pte, sizeof(*pte));
|
||||||
|
free_pgtable_page(level_pte);
|
||||||
|
}
|
||||||
|
next:
|
||||||
|
pfn += level_size(level);
|
||||||
|
} while (!first_pte_in_page(++pte) && pfn <= last_pfn);
|
||||||
|
}
|
||||||
|
|
||||||
/* free page table pages. last level pte should already be cleared */
|
/* free page table pages. last level pte should already be cleared */
|
||||||
static void dma_pte_free_pagetable(struct dmar_domain *domain,
|
static void dma_pte_free_pagetable(struct dmar_domain *domain,
|
||||||
unsigned long start_pfn,
|
unsigned long start_pfn,
|
||||||
unsigned long last_pfn)
|
unsigned long last_pfn)
|
||||||
{
|
{
|
||||||
int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
|
int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
|
||||||
struct dma_pte *first_pte, *pte;
|
|
||||||
int total = agaw_to_level(domain->agaw);
|
|
||||||
int level;
|
|
||||||
unsigned long tmp;
|
|
||||||
int large_page = 2;
|
|
||||||
|
|
||||||
BUG_ON(addr_width < BITS_PER_LONG && start_pfn >> addr_width);
|
BUG_ON(addr_width < BITS_PER_LONG && start_pfn >> addr_width);
|
||||||
BUG_ON(addr_width < BITS_PER_LONG && last_pfn >> addr_width);
|
BUG_ON(addr_width < BITS_PER_LONG && last_pfn >> addr_width);
|
||||||
BUG_ON(start_pfn > last_pfn);
|
BUG_ON(start_pfn > last_pfn);
|
||||||
|
|
||||||
/* We don't need lock here; nobody else touches the iova range */
|
/* We don't need lock here; nobody else touches the iova range */
|
||||||
level = 2;
|
dma_pte_free_level(domain, agaw_to_level(domain->agaw),
|
||||||
while (level <= total) {
|
domain->pgd, 0, start_pfn, last_pfn);
|
||||||
tmp = align_to_level(start_pfn, level);
|
|
||||||
|
|
||||||
/* If we can't even clear one PTE at this level, we're done */
|
|
||||||
if (tmp + level_size(level) - 1 > last_pfn)
|
|
||||||
return;
|
|
||||||
|
|
||||||
do {
|
|
||||||
large_page = level;
|
|
||||||
first_pte = pte = dma_pfn_level_pte(domain, tmp, level, &large_page);
|
|
||||||
if (large_page > level)
|
|
||||||
level = large_page + 1;
|
|
||||||
if (!pte) {
|
|
||||||
tmp = align_to_level(tmp + 1, level + 1);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
if (dma_pte_present(pte)) {
|
|
||||||
free_pgtable_page(phys_to_virt(dma_pte_addr(pte)));
|
|
||||||
dma_clear_pte(pte);
|
|
||||||
}
|
|
||||||
pte++;
|
|
||||||
tmp += level_size(level);
|
|
||||||
} while (!first_pte_in_page(pte) &&
|
|
||||||
tmp + level_size(level) - 1 <= last_pfn);
|
|
||||||
|
|
||||||
domain_flush_cache(domain, first_pte,
|
|
||||||
(void *)pte - (void *)first_pte);
|
|
||||||
|
|
||||||
} while (tmp && tmp + level_size(level) - 1 <= last_pfn);
|
|
||||||
level++;
|
|
||||||
}
|
|
||||||
/* free pgd */
|
/* free pgd */
|
||||||
if (start_pfn == 0 && last_pfn == DOMAIN_MAX_PFN(domain->gaw)) {
|
if (start_pfn == 0 && last_pfn == DOMAIN_MAX_PFN(domain->gaw)) {
|
||||||
free_pgtable_page(domain->pgd);
|
free_pgtable_page(domain->pgd);
|
||||||
|
|
|
@ -58,10 +58,26 @@ struct iommu_domain {
|
||||||
#define IOMMU_CAP_CACHE_COHERENCY 0x1
|
#define IOMMU_CAP_CACHE_COHERENCY 0x1
|
||||||
#define IOMMU_CAP_INTR_REMAP 0x2 /* isolates device intrs */
|
#define IOMMU_CAP_INTR_REMAP 0x2 /* isolates device intrs */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Following constraints are specifc to FSL_PAMUV1:
|
||||||
|
* -aperture must be power of 2, and naturally aligned
|
||||||
|
* -number of windows must be power of 2, and address space size
|
||||||
|
* of each window is determined by aperture size / # of windows
|
||||||
|
* -the actual size of the mapped region of a window must be power
|
||||||
|
* of 2 starting with 4KB and physical address must be naturally
|
||||||
|
* aligned.
|
||||||
|
* DOMAIN_ATTR_FSL_PAMUV1 corresponds to the above mentioned contraints.
|
||||||
|
* The caller can invoke iommu_domain_get_attr to check if the underlying
|
||||||
|
* iommu implementation supports these constraints.
|
||||||
|
*/
|
||||||
|
|
||||||
enum iommu_attr {
|
enum iommu_attr {
|
||||||
DOMAIN_ATTR_GEOMETRY,
|
DOMAIN_ATTR_GEOMETRY,
|
||||||
DOMAIN_ATTR_PAGING,
|
DOMAIN_ATTR_PAGING,
|
||||||
DOMAIN_ATTR_WINDOWS,
|
DOMAIN_ATTR_WINDOWS,
|
||||||
|
DOMAIN_ATTR_FSL_PAMU_STASH,
|
||||||
|
DOMAIN_ATTR_FSL_PAMU_ENABLE,
|
||||||
|
DOMAIN_ATTR_FSL_PAMUV1,
|
||||||
DOMAIN_ATTR_MAX,
|
DOMAIN_ATTR_MAX,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue