|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH 5/7] amd-iommu: introduce new get/set_iommu_pde_info() functions...
...and use set_iommu_pde_info() in set_iommu_pde_present().
set_iommu_pde_info() only sets the address and read/write flags in the PDE,
leaving the (PTE-only) FC bit, level value and presence bit to be
subsequently set by set_iommu_pde_present(). A memory barrier is added to
ensure that the presence bit is last to be set.
A subsequent patch will make further use of get_iommu_pde_info().
Signed-off-by: Paul Durrant <paul.durrant@xxxxxxxxxx>
---
Cc: Suravee Suthikulpanit <suravee.suthikulpanit@xxxxxxx>
Cc: Brian Woods <brian.woods@xxxxxxx>
---
xen/drivers/passthrough/amd/iommu_map.c | 88 +++++++++++++++++++++------------
1 file changed, 56 insertions(+), 32 deletions(-)
diff --git a/xen/drivers/passthrough/amd/iommu_map.c
b/xen/drivers/passthrough/amd/iommu_map.c
index a186c8d28b..fecde9d645 100644
--- a/xen/drivers/passthrough/amd/iommu_map.c
+++ b/xen/drivers/passthrough/amd/iommu_map.c
@@ -45,15 +45,10 @@ void clear_iommu_pte_present(unsigned long l1_mfn, unsigned
long dfn)
unmap_domain_page(table);
}
-static bool set_iommu_pde_present(uint32_t *pde, unsigned long next_mfn,
- unsigned int next_level,
- bool iw, bool ir)
+static void get_iommu_pde_info(uint32_t *pde, uint64_t *maddr, bool *iw,
+ bool *ir)
{
- uint64_t addr_lo, addr_hi, maddr_old, maddr_next;
- uint32_t entry;
- bool need_flush = false;
-
- maddr_next = (uint64_t)next_mfn << PAGE_SHIFT;
+ uint64_t addr_lo, addr_hi;
addr_hi = get_field_from_reg_u32(pde[1],
IOMMU_PTE_ADDR_HIGH_MASK,
@@ -61,45 +56,74 @@ static bool set_iommu_pde_present(uint32_t *pde, unsigned
long next_mfn,
addr_lo = get_field_from_reg_u32(pde[0],
IOMMU_PTE_ADDR_LOW_MASK,
IOMMU_PTE_ADDR_LOW_SHIFT);
+ *maddr = (addr_hi << 32) | (addr_lo << PAGE_SHIFT);
- maddr_old = (addr_hi << 32) | (addr_lo << PAGE_SHIFT);
+ if ( iw )
+ *iw = !!get_field_from_reg_u32(pde[1],
+ IOMMU_PDE_IO_WRITE_PERMISSION_MASK,
+ IOMMU_PDE_IO_WRITE_PERMISSION_SHIFT);
+
+ if ( ir )
+ *ir = !!get_field_from_reg_u32(pde[1],
+ IOMMU_PDE_IO_READ_PERMISSION_MASK,
+ IOMMU_PDE_IO_READ_PERMISSION_SHIFT);
+}
+
+static bool set_iommu_pde_info(uint32_t *pde, uint64_t maddr, bool iw,
+ bool ir)
+{
+ uint64_t addr_lo, addr_hi, maddr_old;
- if ( maddr_old != maddr_next )
- need_flush = 1;
+ get_iommu_pde_info(pde, &maddr_old, NULL, NULL);
- addr_lo = maddr_next & DMA_32BIT_MASK;
- addr_hi = maddr_next >> 32;
+ addr_lo = (maddr & DMA_32BIT_MASK) >> PAGE_SHIFT;
+ addr_hi = maddr >> 32;
- /* enable read/write permissions,which will be enforced at the PTE */
set_field_in_reg_u32((uint32_t)addr_hi, 0,
IOMMU_PDE_ADDR_HIGH_MASK,
- IOMMU_PDE_ADDR_HIGH_SHIFT, &entry);
- set_field_in_reg_u32(iw, entry,
+ IOMMU_PDE_ADDR_HIGH_SHIFT, &pde[1]);
+ set_field_in_reg_u32(iw, pde[1],
IOMMU_PDE_IO_WRITE_PERMISSION_MASK,
- IOMMU_PDE_IO_WRITE_PERMISSION_SHIFT, &entry);
- set_field_in_reg_u32(ir, entry,
+ IOMMU_PDE_IO_WRITE_PERMISSION_SHIFT, &pde[1]);
+ set_field_in_reg_u32(ir, pde[1],
IOMMU_PDE_IO_READ_PERMISSION_MASK,
- IOMMU_PDE_IO_READ_PERMISSION_SHIFT, &entry);
+ IOMMU_PDE_IO_READ_PERMISSION_SHIFT, &pde[1]);
+ set_field_in_reg_u32((uint32_t)addr_lo, 0,
+ IOMMU_PDE_ADDR_LOW_MASK,
+ IOMMU_PDE_ADDR_LOW_SHIFT, &pde[0]);
+
+ return maddr != maddr_old;
+}
+
+static bool set_iommu_pde_present(uint32_t *pde, unsigned long next_mfn,
+ unsigned int next_level,
+ bool_t iw, bool_t ir)
+{
+ bool need_flush = set_iommu_pde_info(pde, next_mfn << PAGE_SHIFT, iw,
+ ir);
- /* FC bit should be enabled in PTE, this helps to solve potential
- * issues with ATS devices
+ /*
+ * FC bit should be enabled in PTE, this helps to solve potential
+ * issues with ATS devices.
*/
if ( next_level == IOMMU_PAGING_MODE_LEVEL_0 )
- set_field_in_reg_u32(IOMMU_CONTROL_ENABLED, entry,
- IOMMU_PTE_FC_MASK, IOMMU_PTE_FC_SHIFT, &entry);
- pde[1] = entry;
+ set_field_in_reg_u32(IOMMU_CONTROL_ENABLED, pde[1],
+ IOMMU_PTE_FC_MASK, IOMMU_PTE_FC_SHIFT,
+ &pde[1]);
/* mark next level as 'present' */
- set_field_in_reg_u32((uint32_t)addr_lo >> PAGE_SHIFT, 0,
- IOMMU_PDE_ADDR_LOW_MASK,
- IOMMU_PDE_ADDR_LOW_SHIFT, &entry);
- set_field_in_reg_u32(next_level, entry,
+ set_field_in_reg_u32(next_level, pde[0],
IOMMU_PDE_NEXT_LEVEL_MASK,
- IOMMU_PDE_NEXT_LEVEL_SHIFT, &entry);
- set_field_in_reg_u32(IOMMU_CONTROL_ENABLED, entry,
+ IOMMU_PDE_NEXT_LEVEL_SHIFT, &pde[0]);
+
+ /*
+ * Make sure all other bits are written before the entry is made
+ * present.
+ */
+ smp_mb();
+ set_field_in_reg_u32(IOMMU_CONTROL_ENABLED, pde[0],
IOMMU_PDE_PRESENT_MASK,
- IOMMU_PDE_PRESENT_SHIFT, &entry);
- pde[0] = entry;
+ IOMMU_PDE_PRESENT_SHIFT, &pde[0]);
return need_flush;
}
--
2.11.0
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |