SMMU: basic driver for init and probing

Introducing the driver in kernel for detecting SMMU features
and initialise the hardware.

Signed-off-by: Oliver Scott <Oliver.Scott@data61.csiro.au>
This commit is contained in:
Qian Ge 2019-09-10 14:54:35 +10:00 committed by Oliver Scott
parent 4fd7cb0360
commit 1a9756f65b
22 changed files with 668 additions and 37 deletions

View file

@ -203,6 +203,7 @@ config_set(KernelArchArmV6 ARCH_ARM_V6 "${KernelArchArmV6}")
config_set(KernelArchArmV7a ARCH_ARM_V7A "${KernelArchArmV7a}")
config_set(KernelArchArmV7ve ARCH_ARM_V7VE "${KernelArchArmV7ve}")
config_set(KernelArchArmV8a ARCH_ARM_V8A "${KernelArchArmV8a}")
config_set(KernelArmSMMU ARM_SMMU "${KernelArmSMMU}")
set(KernelPlatformSupportsMCS "${KernelPlatformSupportsMCS}" CACHE INTERNAL "" FORCE)
# Check for v7ve before v7a as v7ve is a superset and we want to set the

View file

@ -23,7 +23,7 @@ block small_frame_cap {
field_high capFMappedAddress 20
field capFIsDevice 1
#ifdef CONFIG_ARM_SMMU
#ifdef CONFIG_TK1_SMMU
field capFIsIOSpace 1
field capFMappedASIDHigh 6
#else
@ -102,7 +102,7 @@ block vcpu_cap {
}
#endif
#ifdef CONFIG_ARM_SMMU
#ifdef CONFIG_TK1_SMMU
-- IO space caps
-- each module has an engine that can be enabled
-- the clients use the same module can be separately enabled
@ -175,7 +175,7 @@ tagged_union cap capType {
#endif /* CONFIG_ARM_HYPERVISOR_SUPPORT */
-- we use the same names as for x86 IOMMU caps
#ifdef CONFIG_ARM_SMMU
#ifdef CONFIG_TK1_SMMU
tag io_space_cap 0x1f
tag io_page_table_cap 0x2f
#endif

View file

@ -298,7 +298,7 @@ static inline word_t CONST cap_get_archCapSizeBits(cap_t cap)
case cap_vcpu_cap:
return VCPU_SIZE_BITS;
#endif
#ifdef CONFIG_ARM_SMMU
#ifdef CONFIG_TK1_SMMU
case cap_io_page_table_cap:
return seL4_IOPageTableBits;
#endif
@ -340,7 +340,7 @@ static inline bool_t CONST cap_get_archCapIsPhysical(cap_t cap)
return true;
#endif
#ifdef CONFIG_ARM_SMMU
#ifdef CONFIG_TK1_SMMU
case cap_io_page_table_cap:
return true;
#endif
@ -380,7 +380,7 @@ static inline void *CONST cap_get_archCapPtr(cap_t cap)
return VCPU_PTR(cap_vcpu_cap_get_capVCPUPtr(cap));
#endif
#ifdef CONFIG_ARM_SMMU
#ifdef CONFIG_TK1_SMMU
case cap_io_page_table_cap:
return (void *)(cap_io_page_table_cap_get_capIOPTBasePtr(cap));
#endif

View file

@ -39,7 +39,7 @@ static inline void handleReservedIRQ(irq_t irq)
}
#endif
#ifdef CONFIG_ARM_SMMU
#ifdef CONFIG_TK1_SMMU
if (IRQT_TO_IRQ(irq) == INTERRUPT_SMMU) {
plat_smmu_handle_interrupt();
return;

View file

@ -10,7 +10,7 @@
#include <api/failures.h>
#include <object/structures.h>
#ifdef CONFIG_ARM_SMMU
#ifdef CONFIG_TK1_SMMU
seL4_SlotRegion create_iospace_caps(cap_t root_cnode_cap);
exception_t decodeARMIOPTInvocation(word_t invLabel, uint32_t length, cte_t *slot, cap_t cap, extra_caps_t excaps,
@ -65,6 +65,6 @@ static inline void clearIOPageDirectory(cap_t cap)
{
}
#endif /* end of !CONFIG_ARM_SMMU */
#endif /* end of !CONFIG_TK1_SMMU */

View file

@ -0,0 +1,306 @@
/*
* Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
*
* SPDX-License-Identifier: GPL-2.0-only
*/
#pragma once
#include <plat/machine/devices_gen.h>
/*the paddr address of the TX2 SMMU*/
#define SMMU_TX2_PADDR 0x12000000
#define SMMU_PAGE_4KB 0x1000
#define SMMU_PAGE_64KB 0x10000
/*the high-level physical address layout according to SMMU definition*/
#define SMMU_GLOBAL_SIZE(num_page, page_size) ((num_page) * (page_size))
#define SMMU_CB_SIZE(num_page, page_size) ((num_page) * (page_size))
#define SMMU_CB_BASE_PADDR(global_size) (SMMU_TX2_PADDR + (global_size))
/*SMMU's physical address space layout, defined by SMMU v2 standard*/
#define SMMU_GR0_PADDR SMMU_TX2_PADDR
#define SMMU_GR1_PADDR(page_size) ((SMMU_GR0_PADDR) + 1 * (page_size))
#define SMMU_GID_PADDR(page_size) ((SMMU_GR0_PADDR) + 2 * (page_size))
#define SMMU_PM_PADDR(page_size) ((SMMU_GR0_PADDR) + 3 * (page_size))
#define SMMU_SSD_PADDR(page_size) ((SMMU_GR0_PADDR) + 4 * (page_size))
#define SMMU_CBn_PADDR(cb_base, n ,page_size) ((cb_base) + n * (page_size))
/* SMMU's virtual address space layout in kernel address space,
* mapped by boot code.*/
#define SMMU_GR0_PPTR SMMU_PPTR
#define SMMU_GR1_PPTR (SMMU_PPTR + 1 * (SMMU_PAGE_4KB))
#define SMMU_GID_PPTR (SMMU_PPTR + 2 * (SMMU_PAGE_4KB))
#define SMMU_PM_PPTR (SMMU_PPTR + 3 * (SMMU_PAGE_4KB))
#define SMMU_SSD_PPTR (SMMU_PPTR + 4 * (SMMU_PAGE_4KB))
#define SSMU_CB_BASE_PPTR (SMMU_PPTR + 5 * (SMMU_PAGE_4KB))
#define SMMU_CBn_BASE_PPTR(n) ((SSMU_CB_BASE_PPTR) + (n) * (SMMU_PAGE_4KB))
/*global register space 0 registers*/
#define SMMU_sCR0 0x000
#define SMMU_SCR1 0x004
#define SMMU_sCR2 0x008
#define SMMU_sACR 0x010
#define SMMU_IDR0 0x020
#define SMMU_IDR1 0x024
#define SMMU_IDR2 0x028
#define SMMU_IDR3 0x02c
#define SMMU_IDR4 0x030
#define SMMU_IDR5 0x034
#define SMMU_IDR6 0x038
#define SMMU_IDR7 0x03c
#define SMMU_sGFAR 0x040
#define SMMU_sGFSR 0x048
#define SMMU_sGFSRRESTORE 0x04c
#define SMMU_sGFSYNR0 0x050
#define SMMU_sGFSYNR1 0x054
#define SMMU_sGFSYNR2 0x058
#define SMMU_STLBIALL 0x060
#define SMMU_TLBIVMID 0x064
#define SMMU_TLBIALLNSNH 0x068
#define SMMU_TLBIALLH 0x06c
#define SMMU_sTLBGSYNC 0x070
#define SMMU_sTLBGSTATUS 0x074
#define SMMU_TLBIVAH 0x078
#define SMMU_STLBIVALM 0x0a0
#define SMMU_STLBIVAM 0x0a8
#define SMMU_TLBIVALH64 0x0b0
#define SMMU_TLBIVMIDS1 0x0b8
#define SMMU_STLBIALLM 0x0bc
#define SMMU_TLBIVAH64 0x0c0
#define SMMU_sGATS1UR 0x100
#define SMMU_sGATS1UW 0x108
#define SMMU_sGATS1PR 0x110
#define SMMU_sGATS1PW 0x118
#define SMMU_sGATS12UR 0x120
#define SMMU_sGATS12UW 0x128
#define SMMU_sGATS12PR 0x130
#define SMMU_sGATS12PW 0x138
#define SMMU_sGPAR 0x180
#define SMMU_sGATSR 0x188
/*SMMU_SMRn, stream matching register 0 to 127*/
#define SMMU_SMRn(n) (0x800 + (n) * 0x4)
/*SMMU_S2CRn, stream-to-context register 0 to 127*/
#define SMMU_S2CRn(n) (0xc00 + (n) * 0x4)
/*global register space 1*/
/*SMMU_CBARn, context bank attribute register 0 to 127*/
#define SMMU_CBARn(n) (0x000 + (n) * 0x4)
/*SMMU_CBFRSYNRAn, context bank fault restricted syndrome register A 0 to 127*/
#define SMMU_CBFRSYNRAn(n) (0x400 + (n) * 0x4)
/*SMMU_CBA2Rn, context bank attribute registers 0 to 127*/
#define SMMU_CBA2Rn(n) (0x800 + (n) * 0x4)
/*stage 1 and stage 2 translation context bank address space*/
#define SMMU_CBn_SCTLR 0x000
#define SMMU_CBn_ACTLR 0x004
#define SMMU_CBn_RESUME 0x008
#define SMMU_CBn_TCR2 0x010
#define SMMU_CBn_TTBR0 0x020
#define SMMU_CBn_TTBR1 0x028
#define SMMU_CBn_TCR 0x030
#define SMMU_CBn_CONTEXTIDR 0x034
/*the SMMU_CBn_MAIRm registers are used for AArch32 Long-descriptor or the AArch64*/
#define SMMU_CBn_MAIR0 0x038
#define SMMU_CBn_MAIR1 0x03c
/*the SMMU_CBn_PRRR and SMMU_CBn_NMRR registers are used for AArch32*/
#define SMMU_CBn_PRRR 0x038
#define SMMU_CBn_NMRR 0x03c
#define SMMU_CBn_PAR 0x050
#define SMMU_CBn_FSR 0x058
#define SMMU_CBn_FSRRESTORE 0x05c
#define SMMU_CBn_FAR 0x060
#define SMMU_CBn_FSYNR0 0x068
#define SMMU_CBn_FSYNR1 0x06c
#define SMMU_CBn_IPAFAR 0x070
#define SMMU_CBn_TLBIVA 0x600
#define SMMU_CBn_TLBIVAA 0x608
#define SMMU_CBn_TLBIASID 0x610
#define SMMU_CBn_TLBIALL 0x618
#define SMMU_CBn_TLBIVAL 0x620
#define SMMU_CBn_TLBIVAAL 0x628
#define SMMU_CBn_TLBIIPAS2 0x630
#define SMMU_CBn_TLBIIPAS2L 0x638
#define SMMU_CBn_TLBSYNC 0x7f0
#define SMMU_CBn_TLBSTATUS 0x7f4
/*SMMU_CR0 non-secure register 0 bit assignments*/
#define CR0_VMID16EN BIT(31)
#define CR0_HYPMODE BIT(30)
#define CR0_WACFG (0x3 << 26)
#define CR0_RACFG (0x3 << 24)
#define CR0_SHCFG (0x3 << 22)
#define CR0_SMCFCFG BIT(21)
#define CR0_MTCFG BIT(20)
#define CR0_MemAttr (0xf << 16)
#define CR0_BSU (0x3 << 14)
#define CR0_FB BIT(13)
#define CR0_PTM BIT(12)
#define CR0_VMIDPNE BIT(11)
#define CR0_USFCFG BIT(10)
#define CR0_GSE BIT(9)
#define CR0_STALLD BIT(8)
#define CR0_TRANSIENTCFG (0x3 << 6)
#define CR0_GCFGFIE BIT(5)
#define CR0_GCFGFRE BIT(4)
#define CR0_EXIDENABLE BIT(3)
#define CR0_GFIE BIT(2)
#define CR0_GFRE BIT(1)
#define CR0_CLIENTPD BIT(0)
/*SMMU_IDR0 (read only) read mask*/
#define IDR0_SES BIT(31)
#define IDR0_S1TS BIT(30)
#define IDR0_S2TS BIT(29)
#define IDR0_NTS BIT(28)
#define IDR0_SMS BIT(27)
#define IDR0_ATOSNS BIT(26)
#define IDR0_PTFS (0x3 << 24)
#define IDR0_PTFS_VAL(v) ((v) >> 24)
#define IDR0_NUMIRPT (0xff << 16)
#define IDR0_NUMIRPT_VAL(v) ((v) >> 16)
#define IDR0_EXSMRGS BIT(15)
#define IDR0_CTTW BIT(14)
#define IDR0_BTM BIT(13)
#define IDR0_NUMSIDB (0xf << 9)
#define IDR0_NUMSIDB_VAL(v) ((v) >> 9)
#define IDR0_EXIDS BIT(8)
#define IDR0_NUMSMRG 0xff
/*PTFS bits*/
#define PTFS_AARCH32S_AARCH32L 0x0
#define PTFS_AARCH32L_ONLY 0x1
#define PTFS_NO_AARCH32 0x2
/*SMMU_IDR1 (read only) read mask*/
#define IDR1_PAGESIZE BIT(31)
#define IDR1_NUMPAGENDXB (0x7 << 28)
#define IDR1_NUMPAGENDXB_VAL(v) ((v) >> 28)
#define IDR1_HAFDBS (0x3 << 24)
#define IDR1_NUMS2CB (0xff << 16)
#define IDR1_NUMS2CB_VAL(v) ((v) >> 16)
#define IDR1_SMCD BIT(15)
#define IDR1_SSDTP (0x3 << 12)
#define IDR1_NUMSSDNDXB (0xf << 8)
#define IDR1_NUMCB 0xff
/*SMMU_IDR2 (read only) read mask*/
#define IDR2_VMID16S BIT(15)
#define IDR2_PTFSV8_64 BIT(14)
#define IDR2_PTFSV8_16 BIT(13)
#define IDR2_PTFSV8_4 BIT(12)
#define IDR2_OAS (0xf << 4)
#define IDR2_OAS_VAL(v) ((v) >> 4)
#define IDR2_IAS 0xf
/*OAS bits*/
#define IDR2_OAS_32 0x0
#define IDR2_OAS_36 0x1
#define IDR2_OAS_40 0x2
#define IDR2_OAS_42 0x3
#define IDR2_OAS_44 0x4
#define IDR2_OAS_48 0x5
/*IAS bits*/
#define IDR2_IAS_32 0x0
#define IDR2_IAS_36 0x1
#define IDR2_IAS_40 0x2
#define IDR2_IAS_42 0x3
#define IDR2_IAS_44 0x4
#define IDR2_IAS_48 0x5
/*SMMU_IDR7*/
#define IDR7_MAJOR (0xf << 4)
#define IDR7_MAJOR_VAL(v) ((v) >> 4)
#define IDR7_MINOR (0xf)
/*SMMU_sGFSR r/w bit mask, write 1 to clear*/
#define GFSR_MULTI BIT(31)
#define GFSR_UUT BIT(8)
#define GFSR_PF BIT(7)
#define GFSR_EF BIT(6)
#define GFSR_CAF BIT(5)
#define GFSR_UCIF BIT(4)
#define GFSR_UCBF BIT(3)
#define GFSR_SMCF BIT(2)
#define GFSR_USF BIT(1)
#define GFSR_ICF BIT(0)
/*SMMU_S2CRn, r/w bit mask for translation context*/
#define S2CR_TRANSIENTCFG_SET(v) ((v) << 28)
#define S2CR_INSTCFG_SET(v) ((v) << 26)
#define S2CR_PRIVCFG_SET(v) ((v) << 24)
#define S2CR_WACFG_SET(v) ((v) << 22)
#define S2CR_RACFG_SET(v) ((v) << 20)
#define S2CR_NSCFG_SET(v) ((v) << 18)
#define S2CR_TYPE_SET(v) ((v) << 16)
#define S2CR_MemAttr_SET(v) ((v) << 12)
#define S2CR_MTCFG_SET(v) ((v) << 11)
#define S2CR_EXIDVALID_SET(v) ((v) << 10)
#define S2CR_SHCFG_SET(v) ((v) << 8)
#define S2CR_CBNDX_SET(v) ((v) & 0xff)
/*SMMU_S2CRn PRIVCFG values*/
#define S2CR_PRIVCFG_DEFAULT 0x0
/*SMMU_S2CRn type values*/
#define S2CR_TYPE_CB 0x0
#define S2CR_TYPE_BYPASS 0x1
#define S2CR_TYPE_FAULT 0x2
/*SMMU_SMRn, r/w bit mask for stream match*/
#define SMR_VALID_SET(v) ((v) << 30)
#define SMR_MASK_SET(v) ((v) << 16)
#define SMR_ID_SET(v) ((v) & 0x7fff)
/*valid /invalid*/
#define SMR_VALID_EN 0x1
#define SMR_VALID_DIS 0x0
/*SMMU_ACR, SMMU-500*/
#define ACR_CACHE_LOCK BIT(26)
#define ACR_S2CRB_TLBEN BIT(10)
#define ACR_SMTNMB_TLBEN BIT(8)
/*SMMU_CBn_FSR, write 1 to clear*/
#define CBn_FSR_MULTI BIT(31)
#define CBn_FSR_SS BIT(30)
#define CBn_FSR_UUT BIT(8)
#define CBn_FSR_ASF BIT(7)
#define CBn_FSR_TLBLKF BIT(6)
#define CBn_FSR_TLBLMCF BIT(5)
#define CBn_FSR_EF BIT(4)
#define CBn_FSR_PF BIT(3)
#define CBn_FSR_AFF BIT(2)
#define CBn_FSR_TF BIT(1)
#define CBn_FSR_CLEAR_ALL (CBn_FSR_MULTI | CBn_FSR_SS | \
CBn_FSR_UUT | CBn_FSR_ASF | CBn_FSR_TLBLKF | \
CBn_FSR_TLBLMCF | CBn_FSR_EF | CBn_FSR_PF | \
CBn_FSR_AFF | CBn_FSR_TF)
/*SMMU_CBn_ACTLR defined in SMMU500*/
#define CBn_ACTLR_CPRE BIT(1)
#define CBn_ACTLR_CMTLB BIT(0)
/*mask for invalidate all TLB entries, used by GR0 registers*/
#define SMMU_TLB_INVALL_MASK 0xffffffff
/*mask for init the TLB sync msg*/
#define SMMU_TLB_SYNC_MASK 0xffffffff
/*TLB sync status used in SMMU_sTLBGSTATUS and SMMU_CBn_TLBSTATUS*/
#define TLBSTATUS_GSACTIVE BIT(0)
/*the kernel loops N times before declear a TLB invalidation failure*/
#define TLBSYNC_LOOP 1000
void plat_smmu_init(void);

View file

@ -8,7 +8,7 @@
#include <config.h>
#ifdef CONFIG_ARM_SMMU
#ifdef CONFIG_TK1_SMMU
#include <types.h>
#include <plat/machine/hardware_gen.h>
@ -157,7 +157,7 @@ void plat_smmu_ptc_flush_all(void);
iopde_t *plat_smmu_lookup_iopd_by_asid(uint32_t asid);
void plat_smmu_handle_interrupt(void);
#else /* !CONFIG_ARM_SMMU */
#else /* !CONFIG_TK1_SMMU */
/* dummy functions */
static inline void plat_smmu_handle_interrupt(void)
@ -165,5 +165,5 @@ static inline void plat_smmu_handle_interrupt(void)
return;
}
#endif /* CONFIG_ARM_SMMU */
#endif /* CONFIG_TK1_SMMU */

View file

@ -45,11 +45,11 @@
</interface>
<interface name="seL4_ARM_IOPageTable" manual_name="I/O Page Table"
cap_description="Capability to the I/O page table being operated on.">
<method id="ARMIOPageTableMap" name="Map" condition="defined(CONFIG_ARM_SMMU)">
<method id="ARMIOPageTableMap" name="Map" condition="defined(CONFIG_TK1_SMMU)">
<param dir="in" name="iospace" type="seL4_ARM_IOSpace"/>
<param dir="in" name="ioaddr" type="seL4_Word"/>
</method>
<method id="ARMIOPageTableUnmap" name="Unmap" condition="defined(CONFIG_ARM_SMMU)">
<method id="ARMIOPageTableUnmap" name="Unmap" condition="defined(CONFIG_TK1_SMMU)">
</method>
</interface>
<interface name="seL4_ARM_Page" manual_name="Page"
@ -92,7 +92,7 @@
Removes an existing mapping.
</description>
</method>
<method id="ARMPageMapIO" name="MapIO" condition="defined(CONFIG_ARM_SMMU)" manual_name="Map I/O">
<method id="ARMPageMapIO" name="MapIO" condition="defined(CONFIG_TK1_SMMU)" manual_name="Map I/O">
<brief>
</brief>

View file

@ -22,7 +22,7 @@ typedef enum _object {
#ifdef CONFIG_ARM_HYPERVISOR_SUPPORT
seL4_ARM_VCPUObject,
#endif
#ifdef CONFIG_ARM_SMMU
#ifdef CONFIG_TK1_SMMU
seL4_ARM_IOPageTableObject,
#endif
seL4_ObjectTypeCount
@ -34,7 +34,7 @@ typedef seL4_Word object_t;
#define seL4_ARM_VCPUObject 0xfffe
#endif
#ifndef CONFIG_ARM_SMMU
#ifndef CONFIG_TK1_SMMU
#define seL4_ARM_IOPageTableObject 0xffff
#endif

View file

@ -215,7 +215,7 @@ typedef enum {
#define seL4_PageDirBits 14
#define seL4_VSpaceBits seL4_PageDirBits
#ifdef CONFIG_ARM_SMMU
#ifdef CONFIG_TK1_SMMU
#define seL4_NumASIDPoolsBits 6
#else
#define seL4_NumASIDPoolsBits 7

View file

@ -478,7 +478,7 @@ static BOOT_CODE cap_t create_it_frame_cap(pptr_t pptr, vptr_t vptr, asid_t asid
wordFromVMRights(VMReadWrite), /* capFVMRights */
vptr, /* capFMappedAddress */
false, /* capFIsDevice */
#ifdef CONFIG_ARM_SMMU
#ifdef CONFIG_TK1_SMMU
0, /* IOSpace */
#endif
ASID_HIGH(asid), /* capFMappedASIDHigh */
@ -1031,7 +1031,7 @@ bool_t CONST isValidVTableRoot(cap_t cap)
bool_t CONST isIOSpaceFrameCap(cap_t cap)
{
#ifdef CONFIG_ARM_SMMU
#ifdef CONFIG_TK1_SMMU
return cap_get_capType(cap) == cap_small_frame_cap && cap_small_frame_cap_get_capFIsIOSpace(cap);
#else
return false;
@ -2427,7 +2427,7 @@ static exception_t decodeARMFrameInvocation(word_t invLabel, word_t length,
}
case ARMPageUnmap: {
#ifdef CONFIG_ARM_SMMU
#ifdef CONFIG_TK1_SMMU
if (isIOSpaceFrameCap(cap)) {
setThreadState(NODE_STATE(ksCurThread), ThreadState_Restart);
return performPageInvocationUnmapIO(cap, cte);
@ -2439,7 +2439,7 @@ static exception_t decodeARMFrameInvocation(word_t invLabel, word_t length,
}
}
#ifdef CONFIG_ARM_SMMU
#ifdef CONFIG_TK1_SMMU
case ARMPageMapIO: {
return decodeARMIOMapInvocation(invLabel, length, cte, cap, excaps, buffer);
}

View file

@ -87,7 +87,7 @@ deriveCap_ret_t Arch_deriveCap(cte_t *slot, cap_t cap)
return ret;
#endif
#ifdef CONFIG_ARM_SMMU
#ifdef CONFIG_TK1_SMMU
case cap_io_space_cap:
ret.cap = cap;
ret.status = EXCEPTION_NONE;
@ -170,7 +170,7 @@ finaliseCap_ret_t Arch_finaliseCap(cap_t cap, bool_t final)
case cap_small_frame_cap:
if (cap_small_frame_cap_get_capFMappedASID(cap)) {
#ifdef CONFIG_ARM_SMMU
#ifdef CONFIG_TK1_SMMU
if (isIOSpaceFrameCap(cap)) {
unmapIOPage(cap);
break;
@ -225,7 +225,7 @@ finaliseCap_ret_t Arch_finaliseCap(cap_t cap, bool_t final)
break;
#endif
#ifdef CONFIG_ARM_SMMU
#ifdef CONFIG_TK1_SMMU
case cap_io_space_cap:
if (final) {
clearIOPageDirectory(cap);
@ -300,7 +300,7 @@ bool_t CONST Arch_sameRegionAs(cap_t cap_a, cap_t cap_b)
break;
#endif
#ifdef CONFIG_ARM_SMMU
#ifdef CONFIG_TK1_SMMU
case cap_io_space_cap:
if (cap_get_capType(cap_b) == cap_io_space_cap) {
return cap_io_space_cap_get_capModuleID(cap_a) ==
@ -362,7 +362,7 @@ word_t Arch_getObjectSize(word_t t)
return PTE_SIZE_BITS + PT_INDEX_BITS;
case seL4_ARM_PageDirectoryObject:
return PDE_SIZE_BITS + PD_INDEX_BITS;
#ifdef CONFIG_ARM_SMMU
#ifdef CONFIG_TK1_SMMU
case seL4_ARM_IOPageTableObject:
return seL4_IOPageTableBits;
#endif
@ -396,7 +396,7 @@ cap_t Arch_createObject(object_t t, void *regionBase, word_t userSize, bool_t de
return cap_small_frame_cap_new(
ASID_LOW(asidInvalid), VMReadWrite,
0, !!deviceMemory,
#ifdef CONFIG_ARM_SMMU
#ifdef CONFIG_TK1_SMMU
0,
#endif
ASID_HIGH(asidInvalid),
@ -514,7 +514,7 @@ cap_t Arch_createObject(object_t t, void *regionBase, word_t userSize, bool_t de
return cap_vcpu_cap_new(VCPU_REF(regionBase));
#endif
#ifdef CONFIG_ARM_SMMU
#ifdef CONFIG_TK1_SMMU
case seL4_ARM_IOPageTableObject:
/* When the untyped was zeroed it was cleaned to the PoU, but the SMMUs
* typically pull directly from RAM, so we do a futher clean to RAM here */
@ -540,9 +540,9 @@ exception_t Arch_decodeInvocation(word_t invLabel, word_t length, cptr_t cptr,
/* The C parser cannot handle a switch statement with only a default
* case. So we need to do some gymnastics to remove the switch if
* there are no other cases */
#if defined(CONFIG_ARM_SMMU) || defined(CONFIG_ARM_HYPERVISOR_SUPPORT)
#if defined(CONFIG_TK1_SMMU) || defined(CONFIG_ARM_HYPERVISOR_SUPPORT)
switch (cap_get_capType(cap)) {
#ifdef CONFIG_ARM_SMMU
#ifdef CONFIG_TK1_SMMU
case cap_io_space_cap:
return decodeARMIOSpaceInvocation(invLabel, cap);
case cap_io_page_table_cap:

View file

@ -114,7 +114,13 @@ config_option(
)
config_option(
KernelArmSMMU ARM_SMMU "Enable SystemMMU for the Tegra TK1 SoC"
KernelArmSMMU ARM_SMMU "Enable SystemMMU"
DEFAULT OFF
DEPENDS "KernelPlatformTx2"
)
config_option(
KernelTk1SMMU TK1_SMMU "Enable SystemMMU for the Tegra TK1 SoC"
DEFAULT OFF
DEPENDS "KernelPlatformTK1"
)

View file

@ -98,7 +98,7 @@ BOOT_CODE static void init_irqs(cap_t root_cnode_cap)
setIRQState(IRQReserved, CORE_IRQ_TO_IRQT(0, INTERRUPT_VGIC_MAINTENANCE));
setIRQState(IRQReserved, CORE_IRQ_TO_IRQT(0, INTERRUPT_VTIMER_EVENT));
#endif
#ifdef CONFIG_ARM_SMMU
#ifdef CONFIG_TK1_SMMU
setIRQState(IRQReserved, CORE_IRQ_TO_IRQT(0, INTERRUPT_SMMU));
#endif
@ -225,6 +225,9 @@ BOOT_CODE static void init_plat(void)
{
initIRQController();
initL2Cache();
#ifdef CONFIG_ARM_SMMU
plat_smmu_init();
#endif
}
#ifdef ENABLE_SMP_SUPPORT
@ -397,7 +400,7 @@ static BOOT_CODE bool_t try_init_kernel(
*(seL4_BootInfoHeader *)(rootserver.extra_bi + extra_bi_offset) = header;
}
if (config_set(CONFIG_ARM_SMMU)) {
if (config_set(CONFIG_TK1_SMMU)) {
ndks_boot.bi_frame->ioSpaceCaps = create_iospace_caps(root_cnode_cap);
if (ndks_boot.bi_frame->ioSpaceCaps.start == 0 &&
ndks_boot.bi_frame->ioSpaceCaps.end == 0) {

View file

@ -6,7 +6,7 @@
#include <config.h>
#ifdef CONFIG_ARM_SMMU
#ifdef CONFIG_TK1_SMMU
#include <api/syscall.h>
#include <machine/io.h>
@ -475,4 +475,4 @@ exception_t decodeARMIOSpaceInvocation(word_t invLabel, cap_t cap)
current_syscall_error.type = seL4_IllegalOperation;
return EXCEPTION_SYSCALL_ERROR;
}
#endif /* end of CONFIG_ARM_SMMU */
#endif /* end of CONFIG_TK1_SMMU */

View file

@ -17,4 +17,5 @@ macro(register_driver compatibility_strings match_strings)
endmacro()
include(src/drivers/serial/config.cmake)
include(src/drivers/smmu/config.cmake)
include(src/drivers/timer/config.cmake)

View file

@ -0,0 +1,13 @@
#
# Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
#
# SPDX-License-Identifier: GPL-2.0-only
#
cmake_minimum_required(VERSION 3.7.2)
register_driver(
compatibility_strings "arm,mmu-500"
PREFIX src/drivers/smmu
CFILES "smmuv2.c"
)

297
src/drivers/smmu/smmuv2.c Normal file
View file

@ -0,0 +1,297 @@
/*
* Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
*
* SPDX-License-Identifier: GPL-2.0-only
*/
#include <config.h>
#include <types.h>
#include <plat/machine/devices_gen.h>
#include <drivers/smmu/smmuv2.h>
/*supported stages of translations*/
#define STAGE1_TRANS (1 << 0)
#define STAGE2_TRANS (1 << 1)
#define NESTED_TRANS (1 << 2)
/*supported translation table formats*/
#define AARCH32S_FMT (1 << 0)
#define AARCH32L_FMT (1 << 1)
#define NO_AARCH32_FMT (1 << 2)
#define TRANS_PAGES_4KB (1 << 3)
#define TRANS_PAGES_16KB (1 << 4)
#define TRANS_PAGES_64KB (1 << 5)
struct smmu_feature {
bool_t stream_match; /*stream match register funtionality included*/
bool_t trans_op; /*address translation operations supported*/
bool_t cotable_walk; /*coherent translation table walk*/
bool_t broadcast_tlb; /*broadcast TLB maintenance*/
bool_t vmid16; /*16 bits VMIDs are supported*/
uint32_t supported_trans; /*supported translation stages*/
uint32_t supported_fmt; /*supported translation formats*/
uint32_t num_cfault_ints; /*supported number of context fault interrupts*/
uint32_t num_stream_ids; /*number of stream IDs*/
uint32_t num_stream_map_groups; /*num stream mapping register groups*/
uint32_t smmu_page_size; /*page size in SMMU register address space*/
uint32_t smmu_num_pages; /*number of pages in global or context bank address space*/
uint32_t num_s2_cbanks; /*cbanks that support stage 2 only*/
uint32_t num_cbanks; /*total number of context banks*/
uint32_t pa_size; /*PA address size*/
uint32_t ipa_size; /*IPA address size*/
pptr_t cb_base; /*base of context bank address space*/
};
static struct smmu_feature smmu_dev_knowledge;
static inline uint32_t smmu_read_reg32(pptr_t base, uint32_t index)
{
return *(volatile uint32_t*)(base + index);
}
static inline void smmu_write_reg32(pptr_t base, uint32_t index, uint32_t val)
{
*(volatile uint32_t*) (base + index) = val;
}
static inline uint64_t smmu_read_reg64(pptr_t base, uint32_t index)
{
return *(volatile uint64_t*) (base + index);
}
static inline void smmu_write_reg64(pptr_t base, uint32_t index, uint64_t val)
{
*(volatile uint64_t *) (base + index) = val;
}
static void smmu_tlb_sync(pptr_t base, uint32_t sync, uint32_t status)
{
int count = 0;
smmu_write_reg32(base, sync, SMMU_TLB_SYNC_MASK);
while (count < TLBSYNC_LOOP) {
/*pulling the active flag, reading the TLB command state.*/
if (!(smmu_read_reg32(base, status) & TLBSTATUS_GSACTIVE))
break;
count++;
}
}
BOOT_CODE static void smmu_mapping_init(void)
{
/*Creating mapping for the rest of SMMU address space.
* the code assumes registers in each SMMU page are located in a 4K page
* even though the alignement of the (physical) pages can be 64K.
* We make this assumption to compact the SMMU virtual address window.*/
/* This is a temporary solution. A correct solution should be adjust
* the virutal address space layout of the kernel, leaving enough virtual
* address space to SMMU windows. For example, SMMU on TX2 requires a 8M space
* in total, including those empty areas resulted from the 64K alignment.
* Also, kernel requires device space to be configured statically. To
* support populate device space using HW config, we need to modify
* kernel_frame_t and map_kernel_frame, allowing devices mapped in a
* seperate page table using HW config.*/
/*the current implementation has been only tested on the TX2 platform*/
/*init the GR1 region, start: smmu_pptr + 4K, size 4K*/
map_kernel_frame(SMMU_GR1_PADDR(smmu_dev_knowledge.smmu_page_size),
SMMU_GR1_PPTR,
VMKernelOnly,
vm_attributes_new(true, false, false));
/*GID registers*/
map_kernel_frame(SMMU_GID_PADDR(smmu_dev_knowledge.smmu_page_size),
SMMU_GID_PPTR,
VMKernelOnly,
vm_attributes_new(true, false, false));
/*PM registers*/
map_kernel_frame(SMMU_PM_PADDR(smmu_dev_knowledge.smmu_page_size),
SMMU_PM_PPTR,
VMKernelOnly,
vm_attributes_new(true, false, false));
/*SSD registers*/
map_kernel_frame(SMMU_SSD_PADDR(smmu_dev_knowledge.smmu_page_size),
SMMU_SSD_PPTR,
VMKernelOnly,
vm_attributes_new(true, false, false));
/*map the context banks, each bank maps to a 4K page*/
for (int i = 0; i < smmu_dev_knowledge.num_cbanks; i++) {
map_kernel_frame(SMMU_CBn_PADDR(smmu_dev_knowledge.cb_base, i, smmu_dev_knowledge.smmu_page_size),
SMMU_CBn_BASE_PPTR(i),
VMKernelOnly,
vm_attributes_new(true, false, false));
}
}
BOOT_CODE static void smmu_config_prob(void)
{
uint32_t reg, field;
/*ID0*/
reg = smmu_read_reg32(SMMU_GR0_PPTR, SMMU_IDR0);
/*stages supported*/
if (reg & IDR0_S1TS)
smmu_dev_knowledge.supported_trans |= STAGE1_TRANS;
if (reg & IDR0_S2TS)
smmu_dev_knowledge.supported_trans |= STAGE2_TRANS;
if (reg & IDR0_NTS)
smmu_dev_knowledge.supported_trans |= NESTED_TRANS;
/*stream matching register*/
if (reg & IDR0_SMS)
smmu_dev_knowledge.stream_match = true;
/*address translation operation*/
if ((reg & IDR0_ATOSNS) == 0)
smmu_dev_knowledge.trans_op = true;
/*AARCH32 translation format support*/
field = IDR0_PTFS_VAL(reg & IDR0_PTFS);
if (field == PTFS_AARCH32S_AARCH32L) {
smmu_dev_knowledge.supported_fmt |= AARCH32L_FMT;
smmu_dev_knowledge.supported_fmt |= AARCH32S_FMT;
} else if (field == PTFS_AARCH32L_ONLY) {
smmu_dev_knowledge.supported_fmt |= AARCH32L_FMT;
} else {
smmu_dev_knowledge.supported_fmt |= NO_AARCH32_FMT;
}
/*number of context fault intrrupts
* However, in smmuv2, each context bank has dedicated interrupt pin
* hence no requirement to specify implemented interrupts here.*/
smmu_dev_knowledge.num_cfault_ints = IDR0_NUMIRPT_VAL(reg & IDR0_NUMIRPT);
/*coherent translation table walk*/
if (reg & IDR0_CTTW)
smmu_dev_knowledge.cotable_walk = true;
/*broadcast TLB maintenance*/
if (reg & IDR0_BTM)
smmu_dev_knowledge.broadcast_tlb = true;
/*number of stream IDs*/
smmu_dev_knowledge.num_stream_ids = (1 << IDR0_NUMSIDB_VAL(reg & IDR0_NUMSIDB)) - 1;
/*number of stream mapping register groups*/
smmu_dev_knowledge.num_stream_map_groups = reg & IDR0_NUMSMRG;
/*ID1*/
reg = smmu_read_reg32(SMMU_GR0_PPTR, SMMU_IDR1);
/*smmu page size*/
if (reg & IDR1_PAGESIZE )
smmu_dev_knowledge.smmu_page_size = SMMU_PAGE_64KB;
else
smmu_dev_knowledge.smmu_page_size = SMMU_PAGE_4KB;
/*smmu num pages, 2^(numdxb + 1)*/
field = IDR1_NUMPAGENDXB_VAL(reg & IDR1_NUMPAGENDXB);
smmu_dev_knowledge.smmu_num_pages = 1 << (field + 1);
/*num of stage 2 context banks*/
smmu_dev_knowledge.num_s2_cbanks = IDR1_NUMS2CB_VAL(reg & IDR1_NUMS2CB);
/*total num of context banks*/
smmu_dev_knowledge.num_cbanks = reg & IDR1_NUMCB;
/*calcuate the context bank base*/
smmu_dev_knowledge.cb_base = SMMU_CB_BASE_PADDR(
SMMU_GLOBAL_SIZE(smmu_dev_knowledge.smmu_num_pages, smmu_dev_knowledge.smmu_page_size));
/*ID2*/
reg = smmu_read_reg32(SMMU_GR0_PPTR, SMMU_IDR2);
/*VNID16S*/
if (reg & IDR2_VMID16S)
smmu_dev_knowledge.vmid16 = true;
/*PTFSV8_64KB*/
if (reg & IDR2_PTFSV8_64)
smmu_dev_knowledge.supported_fmt |= TRANS_PAGES_64KB;
/*PTFSV8_16KB*/
if (reg & IDR2_PTFSV8_16)
smmu_dev_knowledge.supported_fmt |= TRANS_PAGES_16KB;
/*PTFSV8_64KB*/
if (reg & IDR2_PTFSV8_4)
smmu_dev_knowledge.supported_fmt |= TRANS_PAGES_4KB;
/*OAS*/
smmu_dev_knowledge.pa_size = IDR2_OAS_VAL(reg & IDR2_OAS);
/*IAS*/
smmu_dev_knowledge.ipa_size = reg & IDR2_IAS;
}
BOOT_CODE static void smmu_dev_reset(void)
{
uint32_t reg;
pptr_t cb_bank_ptr;
uint32_t major;
/*clear the global FSR by writing back the read value*/
reg = smmu_read_reg32(SMMU_GR0_PPTR, SMMU_sGFSR);
smmu_write_reg32(SMMU_GR0_PPTR, SMMU_sGFSR, reg);
/*reset stream to context config as using context banks*/
reg = S2CR_PRIVCFG_SET(S2CR_PRIVCFG_DEFAULT);
reg |= S2CR_TYPE_SET(S2CR_TYPE_CB);
/*the number of stream-to-context is realted to the stream indexing method*/
if (smmu_dev_knowledge.stream_match) {
/*stream matching*/
for (int i = 0; i < smmu_dev_knowledge.num_stream_map_groups; i++)
smmu_write_reg32(SMMU_GR0_PPTR, SMMU_S2CRn(i), reg);
/*reset the stream match registers as invalid*/
reg = SMR_VALID_SET(SMR_VALID_DIS);
for (int i = 0; i < smmu_dev_knowledge.num_stream_map_groups; i++)
smmu_write_reg32(SMMU_GR0_PPTR, SMMU_SMRn(i), reg);
} else {
/*stream ID*/
for (int i = 0; i < smmu_dev_knowledge.num_stream_ids; i++)
smmu_write_reg32(SMMU_GR0_PPTR, SMMU_S2CRn(i), reg);
}
/*special init requested by the smmu-500: start*/
reg = smmu_read_reg32(SMMU_GR0_PPTR, SMMU_IDR7);
major = IDR7_MAJOR_VAL(reg & IDR7_MAJOR);
/*init the auxiliary configuration register*/
reg = smmu_read_reg32(SMMU_GR0_PPTR, SMMU_sACR);
/*unlock the write access to SMMU_CBn_ACTLR,
only provided in version 2 and above*/
if (major >= 2)
reg &= ~ACR_CACHE_LOCK;
/*enable the TLB to cache bypassing*/
reg |= ACR_S2CRB_TLBEN | ACR_SMTNMB_TLBEN;
smmu_write_reg32(SMMU_GR0_PPTR, SMMU_sACR, reg);
/*special init requested by the smmu-500: end*/
for (int i = 0; i < smmu_dev_knowledge.num_cbanks; i++) {
cb_bank_ptr = SMMU_CBn_BASE_PPTR(i);
/*disable context banks and clear the context bank fault registers*/
smmu_write_reg32(cb_bank_ptr, SMMU_CBn_SCTLR, 0);
smmu_write_reg32(cb_bank_ptr, SMMU_CBn_FSR, CBn_FSR_CLEAR_ALL);
/*special init requested by the smmu-500: start*/
/*disable MMU-500's next page prefetch due to errata 841119 and 826419*/
reg = smmu_read_reg32(cb_bank_ptr, SMMU_CBn_ACTLR);
reg &= ~CBn_ACTLR_CPRE;
smmu_write_reg32(cb_bank_ptr, SMMU_CBn_ACTLR, reg);
/*special init requested by the smmu-500: end*/
}
/*invalidate TLB */
smmu_write_reg32(SMMU_GR0_PPTR, SMMU_TLBIALLH, SMMU_TLB_INVALL_MASK);
smmu_write_reg32(SMMU_GR0_PPTR, SMMU_TLBIALLNSNH, SMMU_TLB_INVALL_MASK);
reg = smmu_read_reg32(SMMU_GR0_PPTR, SMMU_sCR0);
/*enable global fault reporting*/
reg |= CR0_GFRE | CR0_GFIE | CR0_GCFGFRE | CR0_GCFGFIE;
/*raise fault for any transaction that does not match to
any stream mapping table entires*/
reg |= CR0_USFCFG;
/*raise fault for stream match conflict*/
reg |= CR0_SMCFCFG;
/*disable the VMID private name space*/
reg &= ~CR0_VMIDPNE;
/*TLB is maintained together with the rest of the system*/
reg &= ~CR0_PTM;
/*enable force TLB broadcast on bypassing transactions*/
reg |= CR0_FB;
/*enable client access, ie transaction enforced by SMMU*/
reg &= ~CR0_CLIENTPD;
/*Not upgrade barrier*/
reg &= ~CR0_BSU;
/*syn above issued TLB operations*/
smmu_tlb_sync(SMMU_GR0_PPTR, SMMU_sTLBGSYNC, SMMU_sTLBGSTATUS);
/*enable the SMMU*/
smmu_write_reg32(SMMU_GR0_PPTR, SMMU_sCR0, reg);
}
BOOT_CODE void plat_smmu_init(void)
{
smmu_config_prob();
smmu_mapping_init();
smmu_dev_reset();
}

View file

@ -7,7 +7,7 @@
#include <types.h>
#include <config.h>
#ifdef CONFIG_ARM_SMMU
#ifdef CONFIG_TK1_SMMU
#include <plat/machine/smmu.h>
#include <linker.h>

View file

@ -14,6 +14,7 @@ if(KernelPlatformTx2)
# the 44-bit PA for Cortex-A57 cores would need to be downgraded to 40bit.
set(KernelArmCortexA57 ON)
set(KernelArchArmV8a ON)
set(KernelArmSMMU ON)
config_set(KernelARMPlatform ARM_PLAT tx2)
config_set(KernelArmMach MACH "nvidia")
list(APPEND KernelDTSList "tools/dts/tx2.dts")
@ -27,6 +28,7 @@ if(KernelPlatformTx2)
CLK_SHIFT 57u
CLK_MAGIC 4611686019u
KERNEL_WCET 10u
SMMU drivers/smmu/smmuv2.h
)
endif()

View file

@ -14,6 +14,7 @@
seL4,kernel-devices =
"serial0",
&{/interrupt-controller@3881000},
&{/iommu@12000000},
&{/timer};
};

View file

@ -117,6 +117,7 @@ devices:
# Tegra SMMU (memory-controllers/nvidia,tegra30-mc.txt)
- compatible:
- nvidia,tegra124-mc
- arm,mmu-500
regions:
- index: 0
kernel: SMMU_PPTR