@ -32,6 +32,20 @@
} \
} while ( 0 )
static inline void inc_dma_avail ( S390PCIIOMMU * iommu )
{
if ( iommu - > dma_limit ) {
iommu - > dma_limit - > avail + + ;
}
}
static inline void dec_dma_avail ( S390PCIIOMMU * iommu )
{
if ( iommu - > dma_limit ) {
iommu - > dma_limit - > avail - - ;
}
}
static void s390_set_status_code ( CPUS390XState * env ,
uint8_t r , uint64_t status_code )
{
@ -572,7 +586,8 @@ int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra)
return 0 ;
}
static void s390_pci_update_iotlb ( S390PCIIOMMU * iommu , S390IOTLBEntry * entry )
static uint32_t s390_pci_update_iotlb ( S390PCIIOMMU * iommu ,
S390IOTLBEntry * entry )
{
S390IOTLBEntry * cache = g_hash_table_lookup ( iommu - > iotlb , & entry - > iova ) ;
IOMMUTLBEntry notify = {
@ -585,14 +600,15 @@ static void s390_pci_update_iotlb(S390PCIIOMMU *iommu, S390IOTLBEntry *entry)
if ( entry - > perm = = IOMMU_NONE ) {
if ( ! cache ) {
return ;
goto out ;
}
g_hash_table_remove ( iommu - > iotlb , & entry - > iova ) ;
inc_dma_avail ( iommu ) ;
} else {
if ( cache ) {
if ( cache - > perm = = entry - > perm & &
cache - > translated_addr = = entry - > translated_addr ) {
return ;
goto out ;
}
notify . perm = IOMMU_NONE ;
@ -606,9 +622,13 @@ static void s390_pci_update_iotlb(S390PCIIOMMU *iommu, S390IOTLBEntry *entry)
cache - > len = PAGE_SIZE ;
cache - > perm = entry - > perm ;
g_hash_table_replace ( iommu - > iotlb , & cache - > iova , cache ) ;
dec_dma_avail ( iommu ) ;
}
memory_region_notify_iommu ( & iommu - > iommu_mr , 0 , notify ) ;
out :
return iommu - > dma_limit ? iommu - > dma_limit - > avail : 1 ;
}
int rpcit_service_call ( S390CPU * cpu , uint8_t r1 , uint8_t r2 , uintptr_t ra )
@ -620,6 +640,7 @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra)
S390PCIIOMMU * iommu ;
S390IOTLBEntry entry ;
hwaddr start , end ;
uint32_t dma_avail ;
if ( env - > psw . mask & PSW_MASK_PSTATE ) {
s390_program_interrupt ( env , PGM_PRIVILEGED , ra ) ;
@ -658,6 +679,11 @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra)
}
iommu = pbdev - > iommu ;
if ( iommu - > dma_limit ) {
dma_avail = iommu - > dma_limit - > avail ;
} else {
dma_avail = 1 ;
}
if ( ! iommu - > g_iota ) {
error = ERR_EVENT_INVALAS ;
goto err ;
@ -675,8 +701,9 @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra)
}
start + = entry . len ;
while ( entry . iova < start & & entry . iova < end ) {
s390_pci_update_iotlb ( iommu , & entry ) ;
while ( entry . iova < start & & entry . iova < end & &
( dma_avail > 0 | | entry . perm = = IOMMU_NONE ) ) {
dma_avail = s390_pci_update_iotlb ( iommu , & entry ) ;
entry . iova + = PAGE_SIZE ;
entry . translated_addr + = PAGE_SIZE ;
}
@ -689,7 +716,13 @@ err:
s390_pci_generate_error_event ( error , pbdev - > fh , pbdev - > fid , start , 0 ) ;
} else {
pbdev - > fmb . counter [ ZPCI_FMB_CNT_RPCIT ] + + ;
setcc ( cpu , ZPCI_PCI_LS_OK ) ;
if ( dma_avail > 0 ) {
setcc ( cpu , ZPCI_PCI_LS_OK ) ;
} else {
/* vfio DMA mappings are exhausted, trigger a RPCIT */
setcc ( cpu , ZPCI_PCI_LS_ERR ) ;
s390_set_status_code ( env , r1 , ZPCI_RPCIT_ST_INSUFF_RES ) ;
}
}
return 0 ;
}