|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH v10 7/7] vtd: use a bit field for dma_pte
From: Paul Durrant <pdurrant@xxxxxxxxxx>
As with a prior patch for context_entry, this removes the need for much
shifting, masking and several magic numbers.
Signed-off-by: Paul Durrant <pdurrant@xxxxxxxxxx>
---
Cc: Kevin Tian <kevin.tian@xxxxxxxxx>
v10:
- Remove macros in favour of direct field access
- Adjust field types
- Use write_atomic() to update the live PTE
v4:
- New in v4
---
xen/drivers/passthrough/vtd/iommu.c | 61 +++++++++++++++--------------
xen/drivers/passthrough/vtd/iommu.h | 43 ++++++--------------
xen/drivers/passthrough/vtd/utils.c | 6 +--
3 files changed, 47 insertions(+), 63 deletions(-)
diff --git a/xen/drivers/passthrough/vtd/iommu.c
b/xen/drivers/passthrough/vtd/iommu.c
index fdb472ad6515..2389b9fc708d 100644
--- a/xen/drivers/passthrough/vtd/iommu.c
+++ b/xen/drivers/passthrough/vtd/iommu.c
@@ -281,7 +281,7 @@ static u64 addr_to_dma_page_maddr(struct domain *domain,
u64 addr, int alloc)
offset = address_level_offset(addr, level);
pte = &parent[offset];
- pte_maddr = dma_pte_addr(*pte);
+ pte_maddr = pfn_to_paddr(pte->addr);
if ( !pte_maddr )
{
struct page_info *pg;
@@ -294,14 +294,14 @@ static u64 addr_to_dma_page_maddr(struct domain *domain,
u64 addr, int alloc)
break;
pte_maddr = page_to_maddr(pg);
- dma_set_pte_addr(*pte, pte_maddr);
+ pte->addr = paddr_to_pfn(pte_maddr);
+ smp_wmb();
/*
* high level table always sets r/w, last level
* page table control read/write
*/
- dma_set_pte_readable(*pte);
- dma_set_pte_writable(*pte);
+ pte->r = pte->w = true;
iommu_sync_cache(pte, sizeof(struct dma_pte));
}
@@ -351,7 +351,7 @@ static uint64_t domain_pgd_maddr(struct domain *d, unsigned
int nr_pt_levels)
{
const struct dma_pte *p = map_vtd_domain_page(pgd_maddr);
- pgd_maddr = dma_pte_addr(*p);
+ pgd_maddr = pfn_to_paddr(p->addr);
unmap_vtd_domain_page(p);
if ( !pgd_maddr )
return 0;
@@ -709,20 +709,23 @@ static void dma_pte_clear_one(struct domain *domain,
uint64_t addr,
page = (struct dma_pte *)map_vtd_domain_page(pg_maddr);
pte = page + address_level_offset(addr, 1);
- if ( !dma_pte_present(*pte) )
+ if ( !pte->r && !pte->w )
{
spin_unlock(&hd->arch.mapping_lock);
unmap_vtd_domain_page(page);
return;
}
- dma_clear_pte(*pte);
- *flush_flags |= IOMMU_FLUSHF_modified;
+ pte->r = pte->w = false;
+ smp_wmb();
+ pte->val = 0;
spin_unlock(&hd->arch.mapping_lock);
iommu_sync_cache(pte, sizeof(struct dma_pte));
unmap_vtd_domain_page(page);
+
+ *flush_flags |= IOMMU_FLUSHF_modified;
}
static int iommu_set_root_entry(struct vtd_iommu *iommu)
@@ -1751,7 +1754,7 @@ static int __must_check intel_iommu_map_page(struct
domain *d, dfn_t dfn,
unsigned int *flush_flags)
{
struct domain_iommu *hd = dom_iommu(d);
- struct dma_pte *page, *pte, old, new = {};
+ struct dma_pte *page, *pte, old, new;
u64 pg_maddr;
int rc = 0;
@@ -1775,15 +1778,12 @@ static int __must_check intel_iommu_map_page(struct
domain *d, dfn_t dfn,
page = (struct dma_pte *)map_vtd_domain_page(pg_maddr);
pte = &page[dfn_x(dfn) & LEVEL_MASK];
old = *pte;
-
- dma_set_pte_addr(new, mfn_to_maddr(mfn));
- dma_set_pte_prot(new,
- ((flags & IOMMUF_readable) ? DMA_PTE_READ : 0) |
- ((flags & IOMMUF_writable) ? DMA_PTE_WRITE : 0));
-
- /* Set the SNP on leaf page table if Snoop Control available */
- if ( iommu_snoop )
- dma_set_pte_snp(new);
+ new = (struct dma_pte){
+ .r = flags & IOMMUF_readable,
+ .w = flags & IOMMUF_writable,
+ .snp = iommu_snoop,
+ .addr = mfn_x(mfn),
+ };
if ( old.val == new.val )
{
@@ -1792,14 +1792,14 @@ static int __must_check intel_iommu_map_page(struct
domain *d, dfn_t dfn,
return 0;
}
- *pte = new;
+ write_atomic(&pte->val, new.val);
+ spin_unlock(&hd->arch.mapping_lock);
iommu_sync_cache(pte, sizeof(struct dma_pte));
- spin_unlock(&hd->arch.mapping_lock);
unmap_vtd_domain_page(page);
*flush_flags |= IOMMU_FLUSHF_added;
- if ( dma_pte_present(old) )
+ if ( old.r || old.w )
*flush_flags |= IOMMU_FLUSHF_modified;
return rc;
@@ -1851,12 +1851,12 @@ static int intel_iommu_lookup_page(struct domain *d,
dfn_t dfn, mfn_t *mfn,
unmap_vtd_domain_page(page);
spin_unlock(&hd->arch.mapping_lock);
- if ( !dma_pte_present(val) )
+ if ( !val.r && !val.w )
return -ENOENT;
- *mfn = maddr_to_mfn(dma_pte_addr(val));
- *flags = dma_pte_read(val) ? IOMMUF_readable : 0;
- *flags |= dma_pte_write(val) ? IOMMUF_writable : 0;
+ *mfn = _mfn(val.addr);
+ *flags = val.r ? IOMMUF_readable : 0;
+ *flags |= val.w ? IOMMUF_writable : 0;
return 0;
}
@@ -2611,18 +2611,18 @@ static void vtd_dump_page_table_level(paddr_t pt_maddr,
int level, paddr_t gpa,
process_pending_softirqs();
pte = &pt_vaddr[i];
- if ( !dma_pte_present(*pte) )
+ if ( !pte->r && !pte->w )
continue;
address = gpa + offset_level_address(i, level);
if ( next_level >= 1 )
- vtd_dump_page_table_level(dma_pte_addr(*pte), next_level,
+ vtd_dump_page_table_level(pfn_to_paddr(pte->addr), next_level,
address, indent + 1);
else
printk("%*sdfn: %08lx mfn: %08lx\n",
indent, "",
(unsigned long)(address >> PAGE_SHIFT_4K),
- (unsigned long)(dma_pte_addr(*pte) >> PAGE_SHIFT_4K));
+ (unsigned long)(pte->addr));
}
unmap_vtd_domain_page(pt_vaddr);
@@ -2690,8 +2690,9 @@ static int __init intel_iommu_quarantine_init(struct
domain *d)
{
struct dma_pte *pte = &parent[offset];
- dma_set_pte_addr(*pte, maddr);
- dma_set_pte_readable(*pte);
+ pte->addr = paddr_to_pfn(maddr);
+ smp_wmb();
+ pte->r = 1;
}
iommu_sync_cache(parent, PAGE_SIZE);
diff --git a/xen/drivers/passthrough/vtd/iommu.h
b/xen/drivers/passthrough/vtd/iommu.h
index 33b1abf98526..1b6123e0c947 100644
--- a/xen/drivers/passthrough/vtd/iommu.h
+++ b/xen/drivers/passthrough/vtd/iommu.h
@@ -244,38 +244,21 @@ struct context_entry {
#define level_size(l) (1 << level_to_offset_bits(l))
#define align_to_level(addr, l) ((addr + level_size(l) - 1) & level_mask(l))
-/*
- * 0: readable
- * 1: writable
- * 2-6: reserved
- * 7: super page
- * 8-11: available
- * 12-63: Host physcial address
- */
struct dma_pte {
- u64 val;
+ union {
+ uint64_t val;
+ struct {
+ bool r:1;
+ bool w:1;
+ unsigned int reserved0:1;
+ unsigned int ignored0:4;
+ bool ps:1;
+ unsigned int ignored1:3;
+ bool snp:1;
+ uint64_t addr:52;
+ };
+ };
};
-#define DMA_PTE_READ (1)
-#define DMA_PTE_WRITE (2)
-#define DMA_PTE_PROT (DMA_PTE_READ | DMA_PTE_WRITE)
-#define DMA_PTE_SP (1 << 7)
-#define DMA_PTE_SNP (1 << 11)
-#define dma_clear_pte(p) do {(p).val = 0;} while(0)
-#define dma_set_pte_readable(p) do {(p).val |= DMA_PTE_READ;} while(0)
-#define dma_set_pte_writable(p) do {(p).val |= DMA_PTE_WRITE;} while(0)
-#define dma_set_pte_superpage(p) do {(p).val |= DMA_PTE_SP;} while(0)
-#define dma_set_pte_snp(p) do {(p).val |= DMA_PTE_SNP;} while(0)
-#define dma_set_pte_prot(p, prot) do { \
- (p).val = ((p).val & ~DMA_PTE_PROT) | ((prot) & DMA_PTE_PROT); \
- } while (0)
-#define dma_pte_prot(p) ((p).val & DMA_PTE_PROT)
-#define dma_pte_read(p) (dma_pte_prot(p) & DMA_PTE_READ)
-#define dma_pte_write(p) (dma_pte_prot(p) & DMA_PTE_WRITE)
-#define dma_pte_addr(p) ((p).val & PADDR_MASK & PAGE_MASK_4K)
-#define dma_set_pte_addr(p, addr) do {\
- (p).val |= ((addr) & PAGE_MASK_4K); } while (0)
-#define dma_pte_present(p) (((p).val & DMA_PTE_PROT) != 0)
-#define dma_pte_superpage(p) (((p).val & DMA_PTE_SP) != 0)
/* interrupt remap entry */
struct iremap_entry {
diff --git a/xen/drivers/passthrough/vtd/utils.c
b/xen/drivers/passthrough/vtd/utils.c
index 4bca160bc663..a78b02e6edc4 100644
--- a/xen/drivers/passthrough/vtd/utils.c
+++ b/xen/drivers/passthrough/vtd/utils.c
@@ -161,14 +161,14 @@ void print_vtd_entries(struct vtd_iommu *iommu, int bus,
int devfn, u64 gmfn)
unmap_vtd_domain_page(l);
printk(" l%u[%03x] = %"PRIx64"\n", level, l_index, pte.val);
- if ( !dma_pte_present(pte) )
+ if ( !pte.r && !pte.w )
{
printk(" l%u[%03x] not present\n", level, l_index);
break;
}
- if ( dma_pte_superpage(pte) )
+ if ( pte.ps )
break;
- val = dma_pte_addr(pte);
+ val = pfn_to_paddr(pte.addr);
} while ( --level );
}
--
2.20.1
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |