Skip to content

Commit 437f35e

Browse files
LuBaolujoergroedel
authored andcommitted
iommu/vt-d: Add first level page table interface
This adds an interface to setup the PASID entries for first level page table translation. Cc: Ashok Raj <ashok.raj@intel.com> Cc: Jacob Pan <jacob.jun.pan@linux.intel.com> Cc: Kevin Tian <kevin.tian@intel.com> Signed-off-by: Sanjay Kumar <sanjay.k.kumar@intel.com> Signed-off-by: Liu Yi L <yi.l.liu@intel.com> Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com> Reviewed-by: Ashok Raj <ashok.raj@intel.com> Signed-off-by: Joerg Roedel <jroedel@suse.de>
1 parent 7373a8c commit 437f35e

File tree

3 files changed

+92
-0
lines changed

3 files changed

+92
-0
lines changed

drivers/iommu/intel-pasid.c

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#define pr_fmt(fmt) "DMAR: " fmt
1111

1212
#include <linux/bitops.h>
13+
#include <linux/cpufeature.h>
1314
#include <linux/dmar.h>
1415
#include <linux/intel-iommu.h>
1516
#include <linux/iommu.h>
@@ -389,6 +390,26 @@ static inline void pasid_set_page_snoop(struct pasid_entry *pe, bool value)
389390
pasid_set_bits(&pe->val[1], 1 << 23, value);
390391
}
391392

393+
/*
394+
* Setup the First Level Page table Pointer field (Bit 140~191)
395+
* of a scalable mode PASID entry.
396+
*/
397+
static inline void
398+
pasid_set_flptr(struct pasid_entry *pe, u64 value)
399+
{
400+
pasid_set_bits(&pe->val[2], VTD_PAGE_MASK, value);
401+
}
402+
403+
/*
404+
* Setup the First Level Paging Mode field (Bit 130~131) of a
405+
* scalable mode PASID entry.
406+
*/
407+
static inline void
408+
pasid_set_flpm(struct pasid_entry *pe, u64 value)
409+
{
410+
pasid_set_bits(&pe->val[2], GENMASK_ULL(3, 2), value << 2);
411+
}
412+
392413
static void
393414
pasid_cache_invalidation_with_pasid(struct intel_iommu *iommu,
394415
u16 did, int pasid)
@@ -459,6 +480,65 @@ void intel_pasid_tear_down_entry(struct intel_iommu *iommu,
459480
devtlb_invalidation_with_pasid(iommu, dev, pasid);
460481
}
461482

483+
/*
484+
* Set up the scalable mode pasid table entry for first only
485+
* translation type.
486+
*/
487+
int intel_pasid_setup_first_level(struct intel_iommu *iommu,
488+
struct device *dev, pgd_t *pgd,
489+
int pasid, u16 did, int flags)
490+
{
491+
struct pasid_entry *pte;
492+
493+
if (!ecap_flts(iommu->ecap)) {
494+
pr_err("No first level translation support on %s\n",
495+
iommu->name);
496+
return -EINVAL;
497+
}
498+
499+
pte = intel_pasid_get_entry(dev, pasid);
500+
if (WARN_ON(!pte))
501+
return -EINVAL;
502+
503+
pasid_clear_entry(pte);
504+
505+
/* Setup the first level page table pointer: */
506+
pasid_set_flptr(pte, (u64)__pa(pgd));
507+
if (flags & PASID_FLAG_SUPERVISOR_MODE) {
508+
if (!ecap_srs(iommu->ecap)) {
509+
pr_err("No supervisor request support on %s\n",
510+
iommu->name);
511+
return -EINVAL;
512+
}
513+
pasid_set_sre(pte);
514+
}
515+
516+
#ifdef CONFIG_X86
517+
if (cpu_feature_enabled(X86_FEATURE_LA57))
518+
pasid_set_flpm(pte, 1);
519+
#endif /* CONFIG_X86 */
520+
521+
pasid_set_domain_id(pte, did);
522+
pasid_set_address_width(pte, iommu->agaw);
523+
pasid_set_page_snoop(pte, !!ecap_smpwc(iommu->ecap));
524+
525+
/* Setup Present and PASID Granular Transfer Type: */
526+
pasid_set_translation_type(pte, 1);
527+
pasid_set_present(pte);
528+
529+
if (!ecap_coherent(iommu->ecap))
530+
clflush_cache_range(pte, sizeof(*pte));
531+
532+
if (cap_caching_mode(iommu->cap)) {
533+
pasid_cache_invalidation_with_pasid(iommu, did, pasid);
534+
iotlb_invalidation_with_pasid(iommu, did, pasid);
535+
} else {
536+
iommu_flush_write_buffer(iommu);
537+
}
538+
539+
return 0;
540+
}
541+
462542
/*
463543
* Set up the scalable mode pasid entry for second only translation type.
464544
*/

drivers/iommu/intel-pasid.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,14 @@
2525
*/
2626
#define FLPT_DEFAULT_DID 1
2727

28+
/*
29+
* The SUPERVISOR_MODE flag indicates a first level translation which
30+
* can be used for access to kernel addresses. It is valid only for
31+
* access to the kernel's static 1:1 mapping of physical memory — not
32+
* to vmalloc or even module mappings.
33+
*/
34+
#define PASID_FLAG_SUPERVISOR_MODE BIT(0)
35+
2836
struct pasid_dir_entry {
2937
u64 val;
3038
};
@@ -51,6 +59,9 @@ struct pasid_table *intel_pasid_get_table(struct device *dev);
5159
int intel_pasid_get_dev_max_id(struct device *dev);
5260
struct pasid_entry *intel_pasid_get_entry(struct device *dev, int pasid);
5361
void intel_pasid_clear_entry(struct device *dev, int pasid);
62+
int intel_pasid_setup_first_level(struct intel_iommu *iommu,
63+
struct device *dev, pgd_t *pgd,
64+
int pasid, u16 did, int flags);
5465
int intel_pasid_setup_second_level(struct intel_iommu *iommu,
5566
struct dmar_domain *domain,
5667
struct device *dev, int pasid);

include/linux/intel-iommu.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@
178178
*/
179179

180180
#define ecap_smpwc(e) (((e) >> 48) & 0x1)
181+
#define ecap_flts(e) (((e) >> 47) & 0x1)
181182
#define ecap_slts(e) (((e) >> 46) & 0x1)
182183
#define ecap_smts(e) (((e) >> 43) & 0x1)
183184
#define ecap_dit(e) ((e >> 41) & 0x1)

0 commit comments

Comments
 (0)