@ -36,17 +36,6 @@ enum sPAPRTCEAccess {
SPAPR_TCE_RW = 3 ,
} ;
struct sPAPRTCETable {
uint32_t liobn ;
uint32_t window_size ;
sPAPRTCE * table ;
bool bypass ;
int fd ;
MemoryRegion iommu ;
QLIST_ENTRY ( sPAPRTCETable ) list ;
} ;
QLIST_HEAD ( spapr_tce_tables , sPAPRTCETable ) spapr_tce_tables ;
static sPAPRTCETable * spapr_tce_find_by_liobn ( uint32_t liobn )
@ -96,7 +85,7 @@ static IOMMUTLBEntry spapr_tce_translate_iommu(MemoryRegion *iommu, hwaddr addr)
return ( IOMMUTLBEntry ) { . perm = IOMMU_NONE } ;
}
tce = tcet - > table [ addr > > SPAPR_TCE_PAGE_SHIFT ] . tce ;
tce = tcet - > table [ addr > > SPAPR_TCE_PAGE_SHIFT ] ;
# ifdef DEBUG_TCE
fprintf ( stderr , " -> *paddr=0x%llx, *len=0x%llx \n " ,
@ -112,55 +101,97 @@ static IOMMUTLBEntry spapr_tce_translate_iommu(MemoryRegion *iommu, hwaddr addr)
} ;
}
static int spapr_tce_table_pre_load ( void * opaque )
{
sPAPRTCETable * tcet = SPAPR_TCE_TABLE ( opaque ) ;
tcet - > nb_table = tcet - > window_size > > SPAPR_TCE_PAGE_SHIFT ;
return 0 ;
}
static const VMStateDescription vmstate_spapr_tce_table = {
. name = " spapr_iommu " ,
. version_id = 1 ,
. minimum_version_id = 1 ,
. minimum_version_id_old = 1 ,
. pre_load = spapr_tce_table_pre_load ,
. fields = ( VMStateField [ ] ) {
/* Sanity check */
VMSTATE_UINT32_EQUAL ( liobn , sPAPRTCETable ) ,
VMSTATE_UINT32_EQUAL ( window_size , sPAPRTCETable ) ,
/* IOMMU state */
VMSTATE_BOOL ( bypass , sPAPRTCETable ) ,
VMSTATE_VARRAY_UINT32 ( table , sPAPRTCETable , nb_table , 0 , vmstate_info_uint64 , uint64_t ) ,
VMSTATE_END_OF_LIST ( )
} ,
} ;
static MemoryRegionIOMMUOps spapr_iommu_ops = {
. translate = spapr_tce_translate_iommu ,
} ;
sPAPRTCETable * spapr_tce_new_table ( DeviceState * owner , uint32_t liobn , size_t window_size )
static int spapr_tce_table_realiz e( DeviceState * dev )
{
sPAPRTCETable * tcet ;
if ( spapr_tce_find_by_liobn ( liobn ) ) {
fprintf ( stderr , " Attempted to create TCE table with duplicate "
" LIOBN 0x%x \n " , liobn ) ;
return NULL ;
}
if ( ! window_size ) {
return NULL ;
}
tcet = g_malloc0 ( sizeof ( * tcet ) ) ;
tcet - > liobn = liobn ;
tcet - > window_size = window_size ;
sPAPRTCETable * tcet = SPAPR_TCE_TABLE ( dev ) ;
if ( kvm_enabled ( ) ) {
tcet - > table = kvmppc_create_spapr_tce ( liobn ,
window_size ,
tcet - > table = kvmppc_create_spapr_tce ( tcet - > liobn ,
tcet - > window_size ,
& tcet - > fd ) ;
}
if ( ! tcet - > table ) {
size_t table_size = ( window_size > > SPAPR_TCE_PAGE_SHIFT )
* sizeof ( sPAPRTCE ) ;
size_t table_size = ( tcet - > window_size > > SPAPR_TCE_PAGE_SHIFT )
* sizeof ( uint64_t ) ;
tcet - > table = g_malloc0 ( table_size ) ;
}
tcet - > nb_table = tcet - > window_size > > SPAPR_TCE_PAGE_SHIFT ;
# ifdef DEBUG_TCE
fprintf ( stderr , " spapr_iommu: New TCE table @ %p, liobn=0x%x, "
" table @ %p, fd=%d \n " , tcet , liobn , tcet - > table , tcet - > fd ) ;
# endif
memory_region_init_iommu ( & tcet - > iommu , OBJECT ( owner ) , & spapr_iommu_ops ,
memory_region_init_iommu ( & tcet - > iommu , OBJECT ( dev ) , & spapr_iommu_ops ,
" iommu-spapr " , UINT64_MAX ) ;
QLIST_INSERT_HEAD ( & spapr_tce_tables , tcet , list ) ;
return 0 ;
}
sPAPRTCETable * spapr_tce_new_table ( DeviceState * owner , uint32_t liobn , size_t window_size )
{
sPAPRTCETable * tcet ;
if ( spapr_tce_find_by_liobn ( liobn ) ) {
fprintf ( stderr , " Attempted to create TCE table with duplicate "
" LIOBN 0x%x \n " , liobn ) ;
return NULL ;
}
if ( ! window_size ) {
return NULL ;
}
tcet = SPAPR_TCE_TABLE ( object_new ( TYPE_SPAPR_TCE_TABLE ) ) ;
tcet - > liobn = liobn ;
tcet - > window_size = window_size ;
object_property_add_child ( OBJECT ( owner ) , " tce-table " , OBJECT ( tcet ) , NULL ) ;
qdev_init_nofail ( DEVICE ( tcet ) ) ;
return tcet ;
}
void spapr_tce_free ( sPAPRTCETable * tcet )
static void spapr_tce_table_finalize ( Object * obj )
{
sPAPRTCETable * tcet = SPAPR_TCE_TABLE ( obj ) ;
QLIST_REMOVE ( tcet , list ) ;
if ( ! kvm_enabled ( ) | |
@ -168,8 +199,6 @@ void spapr_tce_free(sPAPRTCETable *tcet)
tcet - > window_size ) ! = 0 ) ) {
g_free ( tcet - > table ) ;
}
g_free ( tcet ) ;
}
MemoryRegion * spapr_tce_get_iommu ( sPAPRTCETable * tcet )
@ -182,10 +211,11 @@ void spapr_tce_set_bypass(sPAPRTCETable *tcet, bool bypass)
tcet - > bypass = bypass ;
}
void spapr_tce_reset ( sPAPRTCETable * tcet )
static void spapr_tce_reset ( DeviceState * dev )
{
sPAPRTCETable * tcet = SPAPR_TCE_TABLE ( dev ) ;
size_t table_size = ( tcet - > window_size > > SPAPR_TCE_PAGE_SHIFT )
* sizeof ( sPAPRTCE ) ;
* sizeof ( uint64_t ) ;
tcet - > bypass = false ;
memset ( tcet - > table , 0 , table_size ) ;
@ -194,7 +224,6 @@ void spapr_tce_reset(sPAPRTCETable *tcet)
static target_ulong put_tce_emu ( sPAPRTCETable * tcet , target_ulong ioba ,
target_ulong tce )
{
sPAPRTCE * tcep ;
IOMMUTLBEntry entry ;
if ( ioba > = tcet - > window_size ) {
@ -203,8 +232,7 @@ static target_ulong put_tce_emu(sPAPRTCETable *tcet, target_ulong ioba,
return H_PARAMETER ;
}
tcep = tcet - > table + ( ioba > > SPAPR_TCE_PAGE_SHIFT ) ;
tcep - > tce = tce ;
tcet - > table [ ioba > > SPAPR_TCE_PAGE_SHIFT ] = tce ;
entry . target_as = & address_space_memory ,
entry . iova = ioba & ~ SPAPR_TCE_PAGE_MASK ;
@ -238,14 +266,6 @@ static target_ulong h_put_tce(PowerPCCPU *cpu, sPAPREnvironment *spapr,
return H_PARAMETER ;
}
void spapr_iommu_init ( void )
{
QLIST_INIT ( & spapr_tce_tables ) ;
/* hcall-tce */
spapr_register_hypercall ( H_PUT_TCE , h_put_tce ) ;
}
int spapr_dma_dt ( void * fdt , int node_off , const char * propname ,
uint32_t liobn , uint64_t window , uint32_t size )
{
@ -286,3 +306,31 @@ int spapr_tcet_dma_dt(void *fdt, int node_off, const char *propname,
return spapr_dma_dt ( fdt , node_off , propname ,
tcet - > liobn , 0 , tcet - > window_size ) ;
}
static void spapr_tce_table_class_init ( ObjectClass * klass , void * data )
{
DeviceClass * dc = DEVICE_CLASS ( klass ) ;
dc - > vmsd = & vmstate_spapr_tce_table ;
dc - > init = spapr_tce_table_realize ;
dc - > reset = spapr_tce_reset ;
QLIST_INIT ( & spapr_tce_tables ) ;
/* hcall-tce */
spapr_register_hypercall ( H_PUT_TCE , h_put_tce ) ;
}
static TypeInfo spapr_tce_table_info = {
. name = TYPE_SPAPR_TCE_TABLE ,
. parent = TYPE_DEVICE ,
. instance_size = sizeof ( sPAPRTCETable ) ,
. class_init = spapr_tce_table_class_init ,
. instance_finalize = spapr_tce_table_finalize ,
} ;
static void register_types ( void )
{
type_register_static ( & spapr_tce_table_info ) ;
}
type_init ( register_types ) ;