diff --git a/iommu_ref_model/libiommu/include/iommu_atc.h b/iommu_ref_model/libiommu/include/iommu_atc.h index 2cd952e8..c27c7a68 100644 --- a/iommu_ref_model/libiommu/include/iommu_atc.h +++ b/iommu_ref_model/libiommu/include/iommu_atc.h @@ -31,6 +31,8 @@ typedef struct { uint8_t S; uint32_t lru; uint8_t valid; + // Whether is an MSI translation + uint8_t IS_MSI; } tlb_t; // Device directory cache typedef struct { @@ -62,7 +64,7 @@ extern tlb_t tlb[TLB_SIZE]; extern void cache_ioatc_iotlb( uint64_t vpn, uint8_t GV, uint8_t PSCV, uint32_t GSCID, uint32_t PSCID, - pte_t *vs_pte, gpte_t *g_pte, uint64_t PPN, uint8_t S); + pte_t *vs_pte, gpte_t *g_pte, uint64_t PPN, uint8_t S, uint8_t is_msi); extern uint8_t lookup_ioatc_iotlb( @@ -70,7 +72,7 @@ lookup_ioatc_iotlb( uint8_t priv, uint8_t is_read, uint8_t is_write, uint8_t is_exec, uint8_t SUM, uint8_t PSCV, uint32_t PSCID, uint8_t GV, uint16_t GSCID, uint32_t *cause, uint64_t *resp_pa, uint64_t *page_sz, - pte_t *vs_pte, gpte_t *g_pte); + pte_t *vs_pte, gpte_t *g_pteu, uint8_t *is_msi); extern uint8_t lookup_ioatc_dc(uint32_t device_id, device_context_t *DC); diff --git a/iommu_ref_model/libiommu/src/iommu_atc.c b/iommu_ref_model/libiommu/src/iommu_atc.c index d8b0319e..f9d7cd7f 100644 --- a/iommu_ref_model/libiommu/src/iommu_atc.c +++ b/iommu_ref_model/libiommu/src/iommu_atc.c @@ -96,7 +96,7 @@ lookup_ioatc_pc( void cache_ioatc_iotlb( uint64_t vpn, uint8_t GV, uint8_t PSCV, uint32_t GSCID, uint32_t PSCID, - pte_t *vs_pte, gpte_t *g_pte, uint64_t PPN, uint8_t S) { + pte_t *vs_pte, gpte_t *g_pte, uint64_t PPN, uint8_t S, uint8_t IS_MSI) { uint8_t i, replace = 0; uint32_t lru = 0xFFFFFFFF; @@ -137,6 +137,9 @@ cache_ioatc_iotlb( // PPN and size tlb[replace].PPN = PPN; tlb[replace].S = S; + // Whether MSI + tlb[replace].IS_MSI = IS_MSI; + tlb[replace].valid = 1; return; } @@ -148,7 +151,7 @@ lookup_ioatc_iotlb( uint8_t priv, uint8_t is_read, uint8_t is_write, uint8_t is_exec, uint8_t SUM, uint8_t PSCV, uint32_t PSCID, uint8_t GV, uint16_t GSCID, uint32_t *cause, uint64_t *resp_pa, uint64_t *page_sz, - pte_t *vs_pte, gpte_t *g_pte) { + pte_t *vs_pte, gpte_t *g_pte, uint8_t *is_msi) { uint8_t i, hit; uint64_t vpn = iova / PAGESIZE; @@ -211,6 +214,8 @@ lookup_ioatc_iotlb( vs_pte->G = tlb[hit].G; vs_pte->U = tlb[hit].U; vs_pte->PBMT = tlb[hit].PBMT; + + *is_msi = tlb[hit].IS_MSI; return IOATC_HIT; page_fault: diff --git a/iommu_ref_model/libiommu/src/iommu_translate.c b/iommu_ref_model/libiommu/src/iommu_translate.c index 76240a6e..a2a1539d 100644 --- a/iommu_ref_model/libiommu/src/iommu_translate.c +++ b/iommu_ref_model/libiommu/src/iommu_translate.c @@ -276,7 +276,7 @@ iommu_translate_iova( check_access_perms = ( TTYP != PCIE_ATS_TRANSLATION_REQUEST ) ? 1 : 0; if ( (ioatc_status = lookup_ioatc_iotlb(req->tr.iova, check_access_perms, priv, is_read, is_write, is_exec, SUM, PSCV, PSCID, GV, GSCID, &cause, &pa, &page_sz, - &vs_pte, &g_pte)) == IOATC_FAULT ) + &vs_pte, &g_pte, &is_msi)) == IOATC_FAULT ) goto stop_and_report_fault; // Hit in IOATC - complete translation. @@ -332,15 +332,26 @@ iommu_translate_iova( // Cache the translation in the IOATC // In the IOTLB the IOVA & PPN is stored in the NAPOT format + // While IOMMUs are expected typically to cache MSI PTEs that are configured + // in basic translate mode (M = 3), they might not cache PTEs configured in + // MRIF mode (M = 1). Two reasons together justify not caching MSI PTEs in + // MRIF mode: First, the information and actions required to store an MSI to + // an MRIF are far different than normal address translation; and second, by + // their nature, MSIs to MRIFs should occur less frequently. Hence, an IOMMU might + // perform MRIF-mode processing solely as an extension of cache-miss page table + // walks, leaving its address translation cache oblivious to MRIF-mode MSI PTEs. napot_ppn = (((pa & ~(page_sz - 1)) | ((page_sz/2) - 1))/PAGESIZE); napot_iova = (((req->tr.iova & ~(page_sz - 1)) | ((page_sz/2) - 1))/PAGESIZE); napot_gpa = (((gpa & ~(page_sz - 1)) | ((page_sz/2) - 1))/PAGESIZE); - if ( req->tr.at == ADDR_TYPE_UNTRANSLATED ) { + if ( req->tr.at == ADDR_TYPE_UNTRANSLATED && + (is_msi == 0 || (is_msi == 1 && is_mrif == 0)) ) { // For Untranslated Requests cache the translations for future re-use cache_ioatc_iotlb(napot_iova, GV, PSCV, iohgatp.GSCID, PSCID, - &vs_pte, &g_pte, napot_ppn, ((page_sz > PAGESIZE) ? 1 : 0)); + &vs_pte, &g_pte, napot_ppn, + ((page_sz > PAGESIZE) ? 1 : 0), is_msi); } if ( (TTYP == PCIE_ATS_TRANSLATION_REQUEST) && + (is_msi == 0 || (is_msi == 1 && is_mrif == 0)) && ((DC.tc.T2GPA == 1 && ((g_fill_ats_trans_in_ioatc & FILL_IOATC_ATS_T2GPA) != 0) ) || ((g_fill_ats_trans_in_ioatc & FILL_IOATC_ATS_ALWAYS) != 0)) ) { // If in T2GPA mode, cache the final GPA->SPA translation as @@ -350,7 +361,7 @@ iommu_translate_iova( cache_ioatc_iotlb((DC.tc.T2GPA == 1) ? napot_gpa : napot_iova, GV, (DC.tc.T2GPA == 1) ? 0 : PSCV, iohgatp.GSCID, (DC.tc.T2GPA == 1) ? 0 : PSCID, - &vs_pte, &g_pte, napot_ppn, ((page_sz > PAGESIZE) ? 1 : 0)); + &vs_pte, &g_pte, napot_ppn, ((page_sz > PAGESIZE) ? 1 : 0), is_msi); // Return the GPA as translation response if T2GPA is 1 pa = (DC.tc.T2GPA == 1) ? gpa : pa; }