Re: [PATCH v2 3/9] iommu/ioasid: Introduce ioasid_set APIs
Hi Jacob, On 9/3/20 11:07 PM, Jacob Pan wrote: > On Tue, 1 Sep 2020 13:51:26 +0200 > Auger Eric wrote: > >> Hi Jacob, >> >> On 8/22/20 6:35 AM, Jacob Pan wrote: >>> ioasid_set was introduced as an arbitrary token that are shared by >>> a >> that is > got it > >>> group of IOASIDs. For example, if IOASID #1 and #2 are allocated >>> via the same ioasid_set*, they are viewed as to belong to the same >>> set. >> two IOASIDs allocated via the same ioasid_set pointer belong to the >> same set? >>> > yes, better. > >>> For guest SVA usages, system-wide IOASID resources need to be >>> partitioned such that VMs can have its own quota and being managed >> their own > right, > >>> separately. ioasid_set is the perfect candidate for meeting such >>> requirements. This patch redefines and extends ioasid_set with the >>> following new fields: >>> - Quota >>> - Reference count >>> - Storage of its namespace >>> - The token is stored in the new ioasid_set but with optional types >>> >>> ioasid_set level APIs are introduced that wires up these new data. >> that wire > right > >>> Existing users of IOASID APIs are converted where a host IOASID set >>> is allocated for bare-metal usage. >>> >>> Signed-off-by: Liu Yi L >>> Signed-off-by: Jacob Pan >>> --- >>> drivers/iommu/intel/iommu.c | 27 ++- >>> drivers/iommu/intel/pasid.h | 1 + >>> drivers/iommu/intel/svm.c | 8 +- >>> drivers/iommu/ioasid.c | 390 >>> +--- >>> include/linux/ioasid.h | 82 -- 5 files changed, 465 >>> insertions(+), 43 deletions(-) >>> >>> diff --git a/drivers/iommu/intel/iommu.c >>> b/drivers/iommu/intel/iommu.c index a3a0b5c8921d..5813eeaa5edb >>> 100644 --- a/drivers/iommu/intel/iommu.c >>> +++ b/drivers/iommu/intel/iommu.c >>> @@ -42,6 +42,7 @@ >>> #include >>> #include >>> #include >>> +#include >>> #include >>> #include >>> #include >>> @@ -103,6 +104,9 @@ >>> */ >>> #define INTEL_IOMMU_PGSIZES(~0xFFFUL) >>> >>> +/* PASIDs used by host SVM */ >>> +struct ioasid_set *host_pasid_set; >>> + >>> static inline int agaw_to_level(int agaw) >>> { >>> return agaw + 2; >>> @@ -3103,8 +3107,8 @@ static void intel_vcmd_ioasid_free(ioasid_t >>> ioasid, void *data) >>> * Sanity check the ioasid owner is done at upper layer, >>> e.g. VFIO >>> * We can only free the PASID when all the devices are >>> unbound. */ >>> - if (ioasid_find(NULL, ioasid, NULL)) { >>> - pr_alert("Cannot free active IOASID %d\n", ioasid); >>> + if (IS_ERR(ioasid_find(host_pasid_set, ioasid, NULL))) { >>> + pr_err("Cannot free IOASID %d, not in system >>> set\n", ioasid); >> not sure the change in the trace is worth. Also you may be more >> explicit like IOASID %d to be freed cannot be found in the system >> ioasid set. > Yes, better. will do. > >> shouldn't it be rate_limited as it is originated from >> user space? > virtual command is only used in the guest kernel, not from userspace > though. But I should add ratelimited to all user originated calls. Sure I mixed things up. Sorry for the noise Eric > >>> return; >>> } >>> vcmd_free_pasid(iommu, ioasid); >>> @@ -3288,6 +3292,19 @@ static int __init init_dmars(void) >>> if (ret) >>> goto free_iommu; >>> >>> + /* PASID is needed for scalable mode irrespective to SVM */ >>> + if (intel_iommu_sm) { >>> + ioasid_install_capacity(intel_pasid_max_id); >>> + /* We should not run out of IOASIDs at boot */ >>> + host_pasid_set = ioasid_alloc_set(NULL, >>> PID_MAX_DEFAULT, >> s/PID_MAX_DEFAULT/intel_pasid_max_id? > Not really, when both baremetal and guest SVA are used on the same > system, we want to to limit the baremetal SVM PASID to the number of > host processes. host_pasid_set is for baremetal only. > > intel_pasid_max_id would take up the entire PASID resource and leave no > PASIDs for guest usages. > >>> + >>> IOASID_SET_TYPE_NULL); >> as suggested by jean-Philippe ioasid_set_alloc >>> + if (IS_ERR_OR_NULL(host_pasid_set)) { >>> + pr_err("Failed to enable host PASID >>> allocator %lu\n", >>> + PTR_ERR(host_pasid_set)); >> does not sound like the correct error message? failed to allocate the >> system ioasid_set? > right > >>> + intel_iommu_sm = 0; >>> + } >>> + } >>> + >>> /* >>> * for each drhd >>> * enable fault log >>> @@ -5149,7 +5166,7 @@ static void auxiliary_unlink_device(struct >>> dmar_domain *domain, domain->auxd_refcnt--; >>> >>> if (!domain->auxd_refcnt && domain->default_pasid > 0) >>> - ioasid_free(domain->default_pasid); >>> + ioasid_free(host_pasid_set, domain->default_pasid); >>> } >>> >>> static int aux_domain_add_dev(struct dmar_domain *domain, >>> @@ -5167,7 +5184,7 @@ static int aux_domain_add_dev(struct >>> dmar_domain *domain, int pasid; >>> >>>
Re: [PATCH v2 3/9] iommu/ioasid: Introduce ioasid_set APIs
On Tue, 1 Sep 2020 13:51:26 +0200 Auger Eric wrote: > Hi Jacob, > > On 8/22/20 6:35 AM, Jacob Pan wrote: > > ioasid_set was introduced as an arbitrary token that are shared by > > a > that is got it > > group of IOASIDs. For example, if IOASID #1 and #2 are allocated > > via the same ioasid_set*, they are viewed as to belong to the same > > set. > two IOASIDs allocated via the same ioasid_set pointer belong to the > same set? > > yes, better. > > For guest SVA usages, system-wide IOASID resources need to be > > partitioned such that VMs can have its own quota and being managed > their own right, > > separately. ioasid_set is the perfect candidate for meeting such > > requirements. This patch redefines and extends ioasid_set with the > > following new fields: > > - Quota > > - Reference count > > - Storage of its namespace > > - The token is stored in the new ioasid_set but with optional types > > > > ioasid_set level APIs are introduced that wires up these new data. > that wire right > > Existing users of IOASID APIs are converted where a host IOASID set > > is allocated for bare-metal usage. > > > > Signed-off-by: Liu Yi L > > Signed-off-by: Jacob Pan > > --- > > drivers/iommu/intel/iommu.c | 27 ++- > > drivers/iommu/intel/pasid.h | 1 + > > drivers/iommu/intel/svm.c | 8 +- > > drivers/iommu/ioasid.c | 390 > > +--- > > include/linux/ioasid.h | 82 -- 5 files changed, 465 > > insertions(+), 43 deletions(-) > > > > diff --git a/drivers/iommu/intel/iommu.c > > b/drivers/iommu/intel/iommu.c index a3a0b5c8921d..5813eeaa5edb > > 100644 --- a/drivers/iommu/intel/iommu.c > > +++ b/drivers/iommu/intel/iommu.c > > @@ -42,6 +42,7 @@ > > #include > > #include > > #include > > +#include > > #include > > #include > > #include > > @@ -103,6 +104,9 @@ > > */ > > #define INTEL_IOMMU_PGSIZES(~0xFFFUL) > > > > +/* PASIDs used by host SVM */ > > +struct ioasid_set *host_pasid_set; > > + > > static inline int agaw_to_level(int agaw) > > { > > return agaw + 2; > > @@ -3103,8 +3107,8 @@ static void intel_vcmd_ioasid_free(ioasid_t > > ioasid, void *data) > > * Sanity check the ioasid owner is done at upper layer, > > e.g. VFIO > > * We can only free the PASID when all the devices are > > unbound. */ > > - if (ioasid_find(NULL, ioasid, NULL)) { > > - pr_alert("Cannot free active IOASID %d\n", ioasid); > > + if (IS_ERR(ioasid_find(host_pasid_set, ioasid, NULL))) { > > + pr_err("Cannot free IOASID %d, not in system > > set\n", ioasid); > not sure the change in the trace is worth. Also you may be more > explicit like IOASID %d to be freed cannot be found in the system > ioasid set. Yes, better. will do. > shouldn't it be rate_limited as it is originated from > user space? virtual command is only used in the guest kernel, not from userspace though. But I should add ratelimited to all user originated calls. > > return; > > } > > vcmd_free_pasid(iommu, ioasid); > > @@ -3288,6 +3292,19 @@ static int __init init_dmars(void) > > if (ret) > > goto free_iommu; > > > > + /* PASID is needed for scalable mode irrespective to SVM */ > > + if (intel_iommu_sm) { > > + ioasid_install_capacity(intel_pasid_max_id); > > + /* We should not run out of IOASIDs at boot */ > > + host_pasid_set = ioasid_alloc_set(NULL, > > PID_MAX_DEFAULT, > s/PID_MAX_DEFAULT/intel_pasid_max_id? Not really, when both baremetal and guest SVA are used on the same system, we want to to limit the baremetal SVM PASID to the number of host processes. host_pasid_set is for baremetal only. intel_pasid_max_id would take up the entire PASID resource and leave no PASIDs for guest usages. > > + > > IOASID_SET_TYPE_NULL); > as suggested by jean-Philippe ioasid_set_alloc > > + if (IS_ERR_OR_NULL(host_pasid_set)) { > > + pr_err("Failed to enable host PASID > > allocator %lu\n", > > + PTR_ERR(host_pasid_set)); > does not sound like the correct error message? failed to allocate the > system ioasid_set? right > > + intel_iommu_sm = 0; > > + } > > + } > > + > > /* > > * for each drhd > > * enable fault log > > @@ -5149,7 +5166,7 @@ static void auxiliary_unlink_device(struct > > dmar_domain *domain, domain->auxd_refcnt--; > > > > if (!domain->auxd_refcnt && domain->default_pasid > 0) > > - ioasid_free(domain->default_pasid); > > + ioasid_free(host_pasid_set, domain->default_pasid); > > } > > > > static int aux_domain_add_dev(struct dmar_domain *domain, > > @@ -5167,7 +5184,7 @@ static int aux_domain_add_dev(struct > > dmar_domain *domain, int pasid; > > > > /* No private data needed for the default pasid */ > > - pasid = ioasid_alloc(NULL, PASID_MIN, > > + pasid = ioasid_alloc(host_pasid_set,
Re: [PATCH v2 3/9] iommu/ioasid: Introduce ioasid_set APIs
On Mon, 24 Aug 2020 11:34:29 -0700 Randy Dunlap wrote: > On 8/24/20 11:28 AM, Jean-Philippe Brucker wrote: > >> +/** > >> + * struct ioasid_set - Meta data about ioasid_set > >> + * @type: Token types and other features > > nit: doesn't follow struct order > > > >> + * @token:Unique to identify an IOASID set > >> + * @xa: XArray to store ioasid_set private IDs, can be used for > >> + *guest-host IOASID mapping, or just a private IOASID > >> namespace. > >> + * @quota:Max number of IOASIDs can be allocated within the set > >> + * @nr_ioasidsNumber of IOASIDs currently allocated in the set > > * @nr_ioasids: Number of IOASIDs currently allocated in the set > got it. thanks! > >> + * @sid: ID of the set > >> + * @ref: Reference count of the users > >> + */ > >> struct ioasid_set { > >> - int dummy; > >> + void *token; > >> + struct xarray xa; > >> + int type; > >> + int quota; > >> + int nr_ioasids; > >> + int sid; > >> + refcount_t ref; > >> + struct rcu_head rcu; > >> }; > > [Jacob Pan] ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH v2 3/9] iommu/ioasid: Introduce ioasid_set APIs
On Mon, 24 Aug 2020 11:30:47 -0700 Randy Dunlap wrote: > On 8/24/20 11:28 AM, Jean-Philippe Brucker wrote: > >> +/** > >> + * struct ioasid_data - Meta data about ioasid > >> + * > >> + * @id: Unique ID > >> + * @users Number of active users > >> + * @state Track state of the IOASID > >> + * @set Meta data of the set this IOASID belongs to > >> + * @private Private data associated with the IOASID > >> + * @rcu For free after RCU grace period > > nit: it would be nicer to follow the struct order > > and use a ':' after each struct member name, as is done for @id: > Got it, thanks. ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH v2 3/9] iommu/ioasid: Introduce ioasid_set APIs
On Mon, 24 Aug 2020 20:28:48 +0200 Jean-Philippe Brucker wrote: > On Fri, Aug 21, 2020 at 09:35:12PM -0700, Jacob Pan wrote: > > ioasid_set was introduced as an arbitrary token that are shared by a > > group of IOASIDs. For example, if IOASID #1 and #2 are allocated > > via the same ioasid_set*, they are viewed as to belong to the same > > set. > > > > For guest SVA usages, system-wide IOASID resources need to be > > partitioned such that VMs can have its own quota and being managed > > separately. ioasid_set is the perfect candidate for meeting such > > requirements. This patch redefines and extends ioasid_set with the > > following new fields: > > - Quota > > - Reference count > > - Storage of its namespace > > - The token is stored in the new ioasid_set but with optional types > > > > ioasid_set level APIs are introduced that wires up these new data. > > Existing users of IOASID APIs are converted where a host IOASID set > > is allocated for bare-metal usage. > > > > Signed-off-by: Liu Yi L > > Signed-off-by: Jacob Pan > > --- > > drivers/iommu/intel/iommu.c | 27 ++- > > drivers/iommu/intel/pasid.h | 1 + > > drivers/iommu/intel/svm.c | 8 +- > > drivers/iommu/ioasid.c | 390 > > +--- > > include/linux/ioasid.h | 82 -- 5 files changed, 465 > > insertions(+), 43 deletions(-) > > > > diff --git a/drivers/iommu/intel/iommu.c > > b/drivers/iommu/intel/iommu.c index a3a0b5c8921d..5813eeaa5edb > > 100644 --- a/drivers/iommu/intel/iommu.c > > +++ b/drivers/iommu/intel/iommu.c > > @@ -42,6 +42,7 @@ > > #include > > #include > > #include > > +#include > > #include > > #include > > #include > > @@ -103,6 +104,9 @@ > > */ > > #define INTEL_IOMMU_PGSIZES(~0xFFFUL) > > > > +/* PASIDs used by host SVM */ > > +struct ioasid_set *host_pasid_set; > > + > > static inline int agaw_to_level(int agaw) > > { > > return agaw + 2; > > @@ -3103,8 +3107,8 @@ static void intel_vcmd_ioasid_free(ioasid_t > > ioasid, void *data) > > * Sanity check the ioasid owner is done at upper layer, > > e.g. VFIO > > * We can only free the PASID when all the devices are > > unbound. */ > > - if (ioasid_find(NULL, ioasid, NULL)) { > > - pr_alert("Cannot free active IOASID %d\n", ioasid); > > + if (IS_ERR(ioasid_find(host_pasid_set, ioasid, NULL))) { > > + pr_err("Cannot free IOASID %d, not in system > > set\n", ioasid); return; > > } > > vcmd_free_pasid(iommu, ioasid); > > @@ -3288,6 +3292,19 @@ static int __init init_dmars(void) > > if (ret) > > goto free_iommu; > > > > + /* PASID is needed for scalable mode irrespective to SVM */ > > + if (intel_iommu_sm) { > > + ioasid_install_capacity(intel_pasid_max_id); > > + /* We should not run out of IOASIDs at boot */ > > + host_pasid_set = ioasid_alloc_set(NULL, > > PID_MAX_DEFAULT, > > + > > IOASID_SET_TYPE_NULL); > > + if (IS_ERR_OR_NULL(host_pasid_set)) { > > + pr_err("Failed to enable host PASID > > allocator %lu\n", > > + PTR_ERR(host_pasid_set)); > > + intel_iommu_sm = 0; > > + } > > + } > > + > > /* > > * for each drhd > > * enable fault log > > @@ -5149,7 +5166,7 @@ static void auxiliary_unlink_device(struct > > dmar_domain *domain, domain->auxd_refcnt--; > > > > if (!domain->auxd_refcnt && domain->default_pasid > 0) > > - ioasid_free(domain->default_pasid); > > + ioasid_free(host_pasid_set, domain->default_pasid); > > } > > > > static int aux_domain_add_dev(struct dmar_domain *domain, > > @@ -5167,7 +5184,7 @@ static int aux_domain_add_dev(struct > > dmar_domain *domain, int pasid; > > > > /* No private data needed for the default pasid */ > > - pasid = ioasid_alloc(NULL, PASID_MIN, > > + pasid = ioasid_alloc(host_pasid_set, PASID_MIN, > > pci_max_pasids(to_pci_dev(dev)) > > - 1, NULL); > > if (pasid == INVALID_IOASID) { > > @@ -5210,7 +5227,7 @@ static int aux_domain_add_dev(struct > > dmar_domain *domain, spin_unlock(>lock); > > spin_unlock_irqrestore(_domain_lock, flags); > > if (!domain->auxd_refcnt && domain->default_pasid > 0) > > - ioasid_free(domain->default_pasid); > > + ioasid_free(host_pasid_set, domain->default_pasid); > > > > return ret; > > } > > diff --git a/drivers/iommu/intel/pasid.h > > b/drivers/iommu/intel/pasid.h index c9850766c3a9..ccdc23446015 > > 100644 --- a/drivers/iommu/intel/pasid.h > > +++ b/drivers/iommu/intel/pasid.h > > @@ -99,6 +99,7 @@ static inline bool pasid_pte_is_present(struct > > pasid_entry *pte) } > > > > extern u32 intel_pasid_max_id; > > +extern struct ioasid_set *host_pasid_set; > > int intel_pasid_alloc_id(void *ptr, int start, int end, gfp_t gfp); > > void intel_pasid_free_id(int pasid); > > void
Re: [PATCH v2 3/9] iommu/ioasid: Introduce ioasid_set APIs
Hi, On 9/2/20 5:28 AM, Jacob Pan wrote: On Mon, 24 Aug 2020 10:24:11 +0800 Lu Baolu wrote: Hi Jacob, On 8/22/20 12:35 PM, Jacob Pan wrote: ioasid_set was introduced as an arbitrary token that are shared by a group of IOASIDs. For example, if IOASID #1 and #2 are allocated via the same ioasid_set*, they are viewed as to belong to the same set. For guest SVA usages, system-wide IOASID resources need to be partitioned such that VMs can have its own quota and being managed separately. ioasid_set is the perfect candidate for meeting such requirements. This patch redefines and extends ioasid_set with the following new fields: - Quota - Reference count - Storage of its namespace - The token is stored in the new ioasid_set but with optional types ioasid_set level APIs are introduced that wires up these new data. Existing users of IOASID APIs are converted where a host IOASID set is allocated for bare-metal usage. Signed-off-by: Liu Yi L Signed-off-by: Jacob Pan --- drivers/iommu/intel/iommu.c | 27 ++- drivers/iommu/intel/pasid.h | 1 + drivers/iommu/intel/svm.c | 8 +- drivers/iommu/ioasid.c | 390 +--- include/linux/ioasid.h | 82 -- 5 files changed, 465 insertions(+), 43 deletions(-) diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c index a3a0b5c8921d..5813eeaa5edb 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -103,6 +104,9 @@ */ #define INTEL_IOMMU_PGSIZES (~0xFFFUL) +/* PASIDs used by host SVM */ +struct ioasid_set *host_pasid_set; + static inline int agaw_to_level(int agaw) { return agaw + 2; @@ -3103,8 +3107,8 @@ static void intel_vcmd_ioasid_free(ioasid_t ioasid, void *data) * Sanity check the ioasid owner is done at upper layer, e.g. VFIO * We can only free the PASID when all the devices are unbound. */ - if (ioasid_find(NULL, ioasid, NULL)) { - pr_alert("Cannot free active IOASID %d\n", ioasid); + if (IS_ERR(ioasid_find(host_pasid_set, ioasid, NULL))) { + pr_err("Cannot free IOASID %d, not in system set\n", ioasid); return; } vcmd_free_pasid(iommu, ioasid); @@ -3288,6 +3292,19 @@ static int __init init_dmars(void) if (ret) goto free_iommu; + /* PASID is needed for scalable mode irrespective to SVM */ + if (intel_iommu_sm) { + ioasid_install_capacity(intel_pasid_max_id); + /* We should not run out of IOASIDs at boot */ + host_pasid_set = ioasid_alloc_set(NULL, PID_MAX_DEFAULT, + IOASID_SET_TYPE_NULL); + if (IS_ERR_OR_NULL(host_pasid_set)) { + pr_err("Failed to enable host PASID allocator %lu\n", + PTR_ERR(host_pasid_set)); + intel_iommu_sm = 0; + } + } + /* * for each drhd * enable fault log @@ -5149,7 +5166,7 @@ static void auxiliary_unlink_device(struct dmar_domain *domain, domain->auxd_refcnt--; if (!domain->auxd_refcnt && domain->default_pasid > 0) - ioasid_free(domain->default_pasid); + ioasid_free(host_pasid_set, domain->default_pasid); } static int aux_domain_add_dev(struct dmar_domain *domain, @@ -5167,7 +5184,7 @@ static int aux_domain_add_dev(struct dmar_domain *domain, int pasid; /* No private data needed for the default pasid */ - pasid = ioasid_alloc(NULL, PASID_MIN, + pasid = ioasid_alloc(host_pasid_set, PASID_MIN, pci_max_pasids(to_pci_dev(dev)) - 1, NULL); if (pasid == INVALID_IOASID) { @@ -5210,7 +5227,7 @@ static int aux_domain_add_dev(struct dmar_domain *domain, spin_unlock(>lock); spin_unlock_irqrestore(_domain_lock, flags); if (!domain->auxd_refcnt && domain->default_pasid > 0) - ioasid_free(domain->default_pasid); + ioasid_free(host_pasid_set, domain->default_pasid); return ret; } diff --git a/drivers/iommu/intel/pasid.h b/drivers/iommu/intel/pasid.h index c9850766c3a9..ccdc23446015 100644 --- a/drivers/iommu/intel/pasid.h +++ b/drivers/iommu/intel/pasid.h @@ -99,6 +99,7 @@ static inline bool pasid_pte_is_present(struct pasid_entry *pte) } extern u32 intel_pasid_max_id; +extern struct ioasid_set *host_pasid_set; int intel_pasid_alloc_id(void *ptr, int start, int end, gfp_t gfp); void intel_pasid_free_id(int pasid); void *intel_pasid_lookup_id(int pasid); diff --git a/drivers/iommu/intel/svm.c b/drivers/iommu/intel/svm.c index 37a9beabc0ca..634e191ca2c3 100644 --- a/drivers/iommu/intel/svm.c +++ b/drivers/iommu/intel/svm.c @@ -551,7 +551,7 @@ intel_svm_bind_mm(struct device *dev, int flags, struct svm_dev_ops *ops, pasid_max =
Re: [PATCH v2 3/9] iommu/ioasid: Introduce ioasid_set APIs
On Mon, 24 Aug 2020 10:24:11 +0800 Lu Baolu wrote: > Hi Jacob, > > On 8/22/20 12:35 PM, Jacob Pan wrote: > > ioasid_set was introduced as an arbitrary token that are shared by a > > group of IOASIDs. For example, if IOASID #1 and #2 are allocated > > via the same ioasid_set*, they are viewed as to belong to the same > > set. > > > > For guest SVA usages, system-wide IOASID resources need to be > > partitioned such that VMs can have its own quota and being managed > > separately. ioasid_set is the perfect candidate for meeting such > > requirements. This patch redefines and extends ioasid_set with the > > following new fields: > > - Quota > > - Reference count > > - Storage of its namespace > > - The token is stored in the new ioasid_set but with optional types > > > > ioasid_set level APIs are introduced that wires up these new data. > > Existing users of IOASID APIs are converted where a host IOASID set > > is allocated for bare-metal usage. > > > > Signed-off-by: Liu Yi L > > Signed-off-by: Jacob Pan > > --- > > drivers/iommu/intel/iommu.c | 27 ++- > > drivers/iommu/intel/pasid.h | 1 + > > drivers/iommu/intel/svm.c | 8 +- > > drivers/iommu/ioasid.c | 390 > > +--- > > include/linux/ioasid.h | 82 -- 5 files changed, 465 > > insertions(+), 43 deletions(-) > > > > diff --git a/drivers/iommu/intel/iommu.c > > b/drivers/iommu/intel/iommu.c index a3a0b5c8921d..5813eeaa5edb > > 100644 --- a/drivers/iommu/intel/iommu.c > > +++ b/drivers/iommu/intel/iommu.c > > @@ -42,6 +42,7 @@ > > #include > > #include > > #include > > +#include > > #include > > #include > > #include > > @@ -103,6 +104,9 @@ > >*/ > > #define INTEL_IOMMU_PGSIZES (~0xFFFUL) > > > > +/* PASIDs used by host SVM */ > > +struct ioasid_set *host_pasid_set; > > + > > static inline int agaw_to_level(int agaw) > > { > > return agaw + 2; > > @@ -3103,8 +3107,8 @@ static void intel_vcmd_ioasid_free(ioasid_t > > ioasid, void *data) > > * Sanity check the ioasid owner is done at upper layer, > > e.g. VFIO > > * We can only free the PASID when all the devices are > > unbound. */ > > - if (ioasid_find(NULL, ioasid, NULL)) { > > - pr_alert("Cannot free active IOASID %d\n", ioasid); > > + if (IS_ERR(ioasid_find(host_pasid_set, ioasid, NULL))) { > > + pr_err("Cannot free IOASID %d, not in system > > set\n", ioasid); return; > > } > > vcmd_free_pasid(iommu, ioasid); > > @@ -3288,6 +3292,19 @@ static int __init init_dmars(void) > > if (ret) > > goto free_iommu; > > > > + /* PASID is needed for scalable mode irrespective to SVM */ > > + if (intel_iommu_sm) { > > + ioasid_install_capacity(intel_pasid_max_id); > > + /* We should not run out of IOASIDs at boot */ > > + host_pasid_set = ioasid_alloc_set(NULL, > > PID_MAX_DEFAULT, > > + > > IOASID_SET_TYPE_NULL); > > + if (IS_ERR_OR_NULL(host_pasid_set)) { > > + pr_err("Failed to enable host PASID > > allocator %lu\n", > > + PTR_ERR(host_pasid_set)); > > + intel_iommu_sm = 0; > > + } > > + } > > + > > /* > > * for each drhd > > * enable fault log > > @@ -5149,7 +5166,7 @@ static void auxiliary_unlink_device(struct > > dmar_domain *domain, domain->auxd_refcnt--; > > > > if (!domain->auxd_refcnt && domain->default_pasid > 0) > > - ioasid_free(domain->default_pasid); > > + ioasid_free(host_pasid_set, domain->default_pasid); > > } > > > > static int aux_domain_add_dev(struct dmar_domain *domain, > > @@ -5167,7 +5184,7 @@ static int aux_domain_add_dev(struct > > dmar_domain *domain, int pasid; > > > > /* No private data needed for the default pasid */ > > - pasid = ioasid_alloc(NULL, PASID_MIN, > > + pasid = ioasid_alloc(host_pasid_set, PASID_MIN, > > pci_max_pasids(to_pci_dev(dev)) > > - 1, NULL); > > if (pasid == INVALID_IOASID) { > > @@ -5210,7 +5227,7 @@ static int aux_domain_add_dev(struct > > dmar_domain *domain, spin_unlock(>lock); > > spin_unlock_irqrestore(_domain_lock, flags); > > if (!domain->auxd_refcnt && domain->default_pasid > 0) > > - ioasid_free(domain->default_pasid); > > + ioasid_free(host_pasid_set, domain->default_pasid); > > > > return ret; > > } > > diff --git a/drivers/iommu/intel/pasid.h > > b/drivers/iommu/intel/pasid.h index c9850766c3a9..ccdc23446015 > > 100644 --- a/drivers/iommu/intel/pasid.h > > +++ b/drivers/iommu/intel/pasid.h > > @@ -99,6 +99,7 @@ static inline bool pasid_pte_is_present(struct > > pasid_entry *pte) } > > > > extern u32 intel_pasid_max_id; > > +extern struct ioasid_set *host_pasid_set; > > int intel_pasid_alloc_id(void *ptr, int start, int end, gfp_t > > gfp); void intel_pasid_free_id(int pasid); > > void
Re: [PATCH v2 3/9] iommu/ioasid: Introduce ioasid_set APIs
Hi Jacob, On 8/22/20 6:35 AM, Jacob Pan wrote: > ioasid_set was introduced as an arbitrary token that are shared by a that is > group of IOASIDs. For example, if IOASID #1 and #2 are allocated via the > same ioasid_set*, they are viewed as to belong to the same set. two IOASIDs allocated via the same ioasid_set pointer belong to the same set? > > For guest SVA usages, system-wide IOASID resources need to be > partitioned such that VMs can have its own quota and being managed their own > separately. ioasid_set is the perfect candidate for meeting such > requirements. This patch redefines and extends ioasid_set with the > following new fields: > - Quota > - Reference count > - Storage of its namespace > - The token is stored in the new ioasid_set but with optional types > > ioasid_set level APIs are introduced that wires up these new data. that wire > Existing users of IOASID APIs are converted where a host IOASID set is > allocated for bare-metal usage. > > Signed-off-by: Liu Yi L > Signed-off-by: Jacob Pan > --- > drivers/iommu/intel/iommu.c | 27 ++- > drivers/iommu/intel/pasid.h | 1 + > drivers/iommu/intel/svm.c | 8 +- > drivers/iommu/ioasid.c | 390 > +--- > include/linux/ioasid.h | 82 -- > 5 files changed, 465 insertions(+), 43 deletions(-) > > diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c > index a3a0b5c8921d..5813eeaa5edb 100644 > --- a/drivers/iommu/intel/iommu.c > +++ b/drivers/iommu/intel/iommu.c > @@ -42,6 +42,7 @@ > #include > #include > #include > +#include > #include > #include > #include > @@ -103,6 +104,9 @@ > */ > #define INTEL_IOMMU_PGSIZES (~0xFFFUL) > > +/* PASIDs used by host SVM */ > +struct ioasid_set *host_pasid_set; > + > static inline int agaw_to_level(int agaw) > { > return agaw + 2; > @@ -3103,8 +3107,8 @@ static void intel_vcmd_ioasid_free(ioasid_t ioasid, > void *data) >* Sanity check the ioasid owner is done at upper layer, e.g. VFIO >* We can only free the PASID when all the devices are unbound. >*/ > - if (ioasid_find(NULL, ioasid, NULL)) { > - pr_alert("Cannot free active IOASID %d\n", ioasid); > + if (IS_ERR(ioasid_find(host_pasid_set, ioasid, NULL))) { > + pr_err("Cannot free IOASID %d, not in system set\n", ioasid); not sure the change in the trace is worth. Also you may be more explicit like IOASID %d to be freed cannot be found in the system ioasid set. shouldn't it be rate_limited as it is originated from user space? > return; > } > vcmd_free_pasid(iommu, ioasid); > @@ -3288,6 +3292,19 @@ static int __init init_dmars(void) > if (ret) > goto free_iommu; > > + /* PASID is needed for scalable mode irrespective to SVM */ > + if (intel_iommu_sm) { > + ioasid_install_capacity(intel_pasid_max_id); > + /* We should not run out of IOASIDs at boot */ > + host_pasid_set = ioasid_alloc_set(NULL, PID_MAX_DEFAULT, s/PID_MAX_DEFAULT/intel_pasid_max_id? > + IOASID_SET_TYPE_NULL); as suggested by jean-Philippe ioasid_set_alloc > + if (IS_ERR_OR_NULL(host_pasid_set)) { > + pr_err("Failed to enable host PASID allocator %lu\n", > + PTR_ERR(host_pasid_set)); does not sound like the correct error message? failed to allocate the system ioasid_set? > + intel_iommu_sm = 0; > + } > + } > + > /* >* for each drhd >* enable fault log > @@ -5149,7 +5166,7 @@ static void auxiliary_unlink_device(struct dmar_domain > *domain, > domain->auxd_refcnt--; > > if (!domain->auxd_refcnt && domain->default_pasid > 0) > - ioasid_free(domain->default_pasid); > + ioasid_free(host_pasid_set, domain->default_pasid); > } > > static int aux_domain_add_dev(struct dmar_domain *domain, > @@ -5167,7 +5184,7 @@ static int aux_domain_add_dev(struct dmar_domain > *domain, > int pasid; > > /* No private data needed for the default pasid */ > - pasid = ioasid_alloc(NULL, PASID_MIN, > + pasid = ioasid_alloc(host_pasid_set, PASID_MIN, >pci_max_pasids(to_pci_dev(dev)) - 1, >NULL); don't you want to ioasid_set_put() the ioasid_set in intel_iommu_free_dmars()? > if (pasid == INVALID_IOASID) { > @@ -5210,7 +5227,7 @@ static int aux_domain_add_dev(struct dmar_domain > *domain, > spin_unlock(>lock); > spin_unlock_irqrestore(_domain_lock, flags); > if (!domain->auxd_refcnt && domain->default_pasid > 0) > - ioasid_free(domain->default_pasid); > + ioasid_free(host_pasid_set, domain->default_pasid); > > return ret; > } > diff --git a/drivers/iommu/intel/pasid.h
Re: [PATCH v2 3/9] iommu/ioasid: Introduce ioasid_set APIs
On 8/24/20 11:28 AM, Jean-Philippe Brucker wrote: >> +/** >> + * struct ioasid_set - Meta data about ioasid_set >> + * @type: Token types and other features > nit: doesn't follow struct order > >> + * @token: Unique to identify an IOASID set >> + * @xa: XArray to store ioasid_set private IDs, can be used for >> + * guest-host IOASID mapping, or just a private IOASID namespace. >> + * @quota: Max number of IOASIDs can be allocated within the set >> + * @nr_ioasids Number of IOASIDs currently allocated in the set * @nr_ioasids: Number of IOASIDs currently allocated in the set >> + * @sid:ID of the set >> + * @ref:Reference count of the users >> + */ >> struct ioasid_set { >> -int dummy; >> +void *token; >> +struct xarray xa; >> +int type; >> +int quota; >> +int nr_ioasids; >> +int sid; >> +refcount_t ref; >> +struct rcu_head rcu; >> }; -- ~Randy ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH v2 3/9] iommu/ioasid: Introduce ioasid_set APIs
On 8/24/20 11:28 AM, Jean-Philippe Brucker wrote: >> +/** >> + * struct ioasid_data - Meta data about ioasid >> + * >> + * @id: Unique ID >> + * @users Number of active users >> + * @state Track state of the IOASID >> + * @set Meta data of the set this IOASID belongs to >> + * @private Private data associated with the IOASID >> + * @rcu For free after RCU grace period > nit: it would be nicer to follow the struct order and use a ':' after each struct member name, as is done for @id: -- ~Randy ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH v2 3/9] iommu/ioasid: Introduce ioasid_set APIs
On Fri, Aug 21, 2020 at 09:35:12PM -0700, Jacob Pan wrote: > ioasid_set was introduced as an arbitrary token that are shared by a > group of IOASIDs. For example, if IOASID #1 and #2 are allocated via the > same ioasid_set*, they are viewed as to belong to the same set. > > For guest SVA usages, system-wide IOASID resources need to be > partitioned such that VMs can have its own quota and being managed > separately. ioasid_set is the perfect candidate for meeting such > requirements. This patch redefines and extends ioasid_set with the > following new fields: > - Quota > - Reference count > - Storage of its namespace > - The token is stored in the new ioasid_set but with optional types > > ioasid_set level APIs are introduced that wires up these new data. > Existing users of IOASID APIs are converted where a host IOASID set is > allocated for bare-metal usage. > > Signed-off-by: Liu Yi L > Signed-off-by: Jacob Pan > --- > drivers/iommu/intel/iommu.c | 27 ++- > drivers/iommu/intel/pasid.h | 1 + > drivers/iommu/intel/svm.c | 8 +- > drivers/iommu/ioasid.c | 390 > +--- > include/linux/ioasid.h | 82 -- > 5 files changed, 465 insertions(+), 43 deletions(-) > > diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c > index a3a0b5c8921d..5813eeaa5edb 100644 > --- a/drivers/iommu/intel/iommu.c > +++ b/drivers/iommu/intel/iommu.c > @@ -42,6 +42,7 @@ > #include > #include > #include > +#include > #include > #include > #include > @@ -103,6 +104,9 @@ > */ > #define INTEL_IOMMU_PGSIZES (~0xFFFUL) > > +/* PASIDs used by host SVM */ > +struct ioasid_set *host_pasid_set; > + > static inline int agaw_to_level(int agaw) > { > return agaw + 2; > @@ -3103,8 +3107,8 @@ static void intel_vcmd_ioasid_free(ioasid_t ioasid, > void *data) >* Sanity check the ioasid owner is done at upper layer, e.g. VFIO >* We can only free the PASID when all the devices are unbound. >*/ > - if (ioasid_find(NULL, ioasid, NULL)) { > - pr_alert("Cannot free active IOASID %d\n", ioasid); > + if (IS_ERR(ioasid_find(host_pasid_set, ioasid, NULL))) { > + pr_err("Cannot free IOASID %d, not in system set\n", ioasid); > return; > } > vcmd_free_pasid(iommu, ioasid); > @@ -3288,6 +3292,19 @@ static int __init init_dmars(void) > if (ret) > goto free_iommu; > > + /* PASID is needed for scalable mode irrespective to SVM */ > + if (intel_iommu_sm) { > + ioasid_install_capacity(intel_pasid_max_id); > + /* We should not run out of IOASIDs at boot */ > + host_pasid_set = ioasid_alloc_set(NULL, PID_MAX_DEFAULT, > + IOASID_SET_TYPE_NULL); > + if (IS_ERR_OR_NULL(host_pasid_set)) { > + pr_err("Failed to enable host PASID allocator %lu\n", > + PTR_ERR(host_pasid_set)); > + intel_iommu_sm = 0; > + } > + } > + > /* >* for each drhd >* enable fault log > @@ -5149,7 +5166,7 @@ static void auxiliary_unlink_device(struct dmar_domain > *domain, > domain->auxd_refcnt--; > > if (!domain->auxd_refcnt && domain->default_pasid > 0) > - ioasid_free(domain->default_pasid); > + ioasid_free(host_pasid_set, domain->default_pasid); > } > > static int aux_domain_add_dev(struct dmar_domain *domain, > @@ -5167,7 +5184,7 @@ static int aux_domain_add_dev(struct dmar_domain > *domain, > int pasid; > > /* No private data needed for the default pasid */ > - pasid = ioasid_alloc(NULL, PASID_MIN, > + pasid = ioasid_alloc(host_pasid_set, PASID_MIN, >pci_max_pasids(to_pci_dev(dev)) - 1, >NULL); > if (pasid == INVALID_IOASID) { > @@ -5210,7 +5227,7 @@ static int aux_domain_add_dev(struct dmar_domain > *domain, > spin_unlock(>lock); > spin_unlock_irqrestore(_domain_lock, flags); > if (!domain->auxd_refcnt && domain->default_pasid > 0) > - ioasid_free(domain->default_pasid); > + ioasid_free(host_pasid_set, domain->default_pasid); > > return ret; > } > diff --git a/drivers/iommu/intel/pasid.h b/drivers/iommu/intel/pasid.h > index c9850766c3a9..ccdc23446015 100644 > --- a/drivers/iommu/intel/pasid.h > +++ b/drivers/iommu/intel/pasid.h > @@ -99,6 +99,7 @@ static inline bool pasid_pte_is_present(struct pasid_entry > *pte) > } > > extern u32 intel_pasid_max_id; > +extern struct ioasid_set *host_pasid_set; > int intel_pasid_alloc_id(void *ptr, int start, int end, gfp_t gfp); > void intel_pasid_free_id(int pasid); > void *intel_pasid_lookup_id(int pasid); > diff --git a/drivers/iommu/intel/svm.c b/drivers/iommu/intel/svm.c > index
Re: [PATCH v2 3/9] iommu/ioasid: Introduce ioasid_set APIs
Hi Jacob, On 8/22/20 12:35 PM, Jacob Pan wrote: ioasid_set was introduced as an arbitrary token that are shared by a group of IOASIDs. For example, if IOASID #1 and #2 are allocated via the same ioasid_set*, they are viewed as to belong to the same set. For guest SVA usages, system-wide IOASID resources need to be partitioned such that VMs can have its own quota and being managed separately. ioasid_set is the perfect candidate for meeting such requirements. This patch redefines and extends ioasid_set with the following new fields: - Quota - Reference count - Storage of its namespace - The token is stored in the new ioasid_set but with optional types ioasid_set level APIs are introduced that wires up these new data. Existing users of IOASID APIs are converted where a host IOASID set is allocated for bare-metal usage. Signed-off-by: Liu Yi L Signed-off-by: Jacob Pan --- drivers/iommu/intel/iommu.c | 27 ++- drivers/iommu/intel/pasid.h | 1 + drivers/iommu/intel/svm.c | 8 +- drivers/iommu/ioasid.c | 390 +--- include/linux/ioasid.h | 82 -- 5 files changed, 465 insertions(+), 43 deletions(-) diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c index a3a0b5c8921d..5813eeaa5edb 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -103,6 +104,9 @@ */ #define INTEL_IOMMU_PGSIZES (~0xFFFUL) +/* PASIDs used by host SVM */ +struct ioasid_set *host_pasid_set; + static inline int agaw_to_level(int agaw) { return agaw + 2; @@ -3103,8 +3107,8 @@ static void intel_vcmd_ioasid_free(ioasid_t ioasid, void *data) * Sanity check the ioasid owner is done at upper layer, e.g. VFIO * We can only free the PASID when all the devices are unbound. */ - if (ioasid_find(NULL, ioasid, NULL)) { - pr_alert("Cannot free active IOASID %d\n", ioasid); + if (IS_ERR(ioasid_find(host_pasid_set, ioasid, NULL))) { + pr_err("Cannot free IOASID %d, not in system set\n", ioasid); return; } vcmd_free_pasid(iommu, ioasid); @@ -3288,6 +3292,19 @@ static int __init init_dmars(void) if (ret) goto free_iommu; + /* PASID is needed for scalable mode irrespective to SVM */ + if (intel_iommu_sm) { + ioasid_install_capacity(intel_pasid_max_id); + /* We should not run out of IOASIDs at boot */ + host_pasid_set = ioasid_alloc_set(NULL, PID_MAX_DEFAULT, + IOASID_SET_TYPE_NULL); + if (IS_ERR_OR_NULL(host_pasid_set)) { + pr_err("Failed to enable host PASID allocator %lu\n", + PTR_ERR(host_pasid_set)); + intel_iommu_sm = 0; + } + } + /* * for each drhd * enable fault log @@ -5149,7 +5166,7 @@ static void auxiliary_unlink_device(struct dmar_domain *domain, domain->auxd_refcnt--; if (!domain->auxd_refcnt && domain->default_pasid > 0) - ioasid_free(domain->default_pasid); + ioasid_free(host_pasid_set, domain->default_pasid); } static int aux_domain_add_dev(struct dmar_domain *domain, @@ -5167,7 +5184,7 @@ static int aux_domain_add_dev(struct dmar_domain *domain, int pasid; /* No private data needed for the default pasid */ - pasid = ioasid_alloc(NULL, PASID_MIN, + pasid = ioasid_alloc(host_pasid_set, PASID_MIN, pci_max_pasids(to_pci_dev(dev)) - 1, NULL); if (pasid == INVALID_IOASID) { @@ -5210,7 +5227,7 @@ static int aux_domain_add_dev(struct dmar_domain *domain, spin_unlock(>lock); spin_unlock_irqrestore(_domain_lock, flags); if (!domain->auxd_refcnt && domain->default_pasid > 0) - ioasid_free(domain->default_pasid); + ioasid_free(host_pasid_set, domain->default_pasid); return ret; } diff --git a/drivers/iommu/intel/pasid.h b/drivers/iommu/intel/pasid.h index c9850766c3a9..ccdc23446015 100644 --- a/drivers/iommu/intel/pasid.h +++ b/drivers/iommu/intel/pasid.h @@ -99,6 +99,7 @@ static inline bool pasid_pte_is_present(struct pasid_entry *pte) } extern u32 intel_pasid_max_id; +extern struct ioasid_set *host_pasid_set; int intel_pasid_alloc_id(void *ptr, int start, int end, gfp_t gfp); void intel_pasid_free_id(int pasid); void *intel_pasid_lookup_id(int pasid); diff --git a/drivers/iommu/intel/svm.c b/drivers/iommu/intel/svm.c index 37a9beabc0ca..634e191ca2c3 100644 --- a/drivers/iommu/intel/svm.c +++ b/drivers/iommu/intel/svm.c @@ -551,7 +551,7 @@ intel_svm_bind_mm(struct device *dev, int flags, struct
Re: [PATCH v2 3/9] iommu/ioasid: Introduce ioasid_set APIs
Hi Jacob, I love your patch! Perhaps something to improve: [auto build test WARNING on iommu/next] [also build test WARNING on linux/master linus/master v5.9-rc1 next-20200821] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch] url: https://github.com/0day-ci/linux/commits/Jacob-Pan/IOASID-extensions-for-guest-SVA/20200822-123111 base: https://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu.git next config: x86_64-allyesconfig (attached as .config) compiler: gcc-9 (Debian 9.3.0-15) 9.3.0 reproduce (this is a W=1 build): # save the attached .config to linux build tree make W=1 ARCH=x86_64 If you fix the issue, kindly add following tag as appropriate Reported-by: kernel test robot All warnings (new ones prefixed by >>): drivers/iommu/ioasid.c: In function 'ioasid_get_capacity': >> drivers/iommu/ioasid.c:50:10: warning: old-style function definition >> [-Wold-style-definition] 50 | ioasid_t ioasid_get_capacity() | ^~~ drivers/iommu/ioasid.c: At top level: >> drivers/iommu/ioasid.c:577:6: warning: no previous prototype for >> 'ioasid_set_get' [-Wmissing-prototypes] 577 | void ioasid_set_get(struct ioasid_set *set) | ^~ # https://github.com/0day-ci/linux/commit/59b6f319b27588b2a8a0268a4f4f09f7be458861 git remote add linux-review https://github.com/0day-ci/linux git fetch --no-tags linux-review Jacob-Pan/IOASID-extensions-for-guest-SVA/20200822-123111 git checkout 59b6f319b27588b2a8a0268a4f4f09f7be458861 vim +50 drivers/iommu/ioasid.c 49 > 50 ioasid_t ioasid_get_capacity() 51 { 52 return ioasid_capacity; 53 } 54 EXPORT_SYMBOL_GPL(ioasid_get_capacity); 55 --- 0-DAY CI Kernel Test Service, Intel Corporation https://lists.01.org/hyperkitty/list/kbuild-...@lists.01.org .config.gz Description: application/gzip ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v2 3/9] iommu/ioasid: Introduce ioasid_set APIs
ioasid_set was introduced as an arbitrary token that are shared by a group of IOASIDs. For example, if IOASID #1 and #2 are allocated via the same ioasid_set*, they are viewed as to belong to the same set. For guest SVA usages, system-wide IOASID resources need to be partitioned such that VMs can have its own quota and being managed separately. ioasid_set is the perfect candidate for meeting such requirements. This patch redefines and extends ioasid_set with the following new fields: - Quota - Reference count - Storage of its namespace - The token is stored in the new ioasid_set but with optional types ioasid_set level APIs are introduced that wires up these new data. Existing users of IOASID APIs are converted where a host IOASID set is allocated for bare-metal usage. Signed-off-by: Liu Yi L Signed-off-by: Jacob Pan --- drivers/iommu/intel/iommu.c | 27 ++- drivers/iommu/intel/pasid.h | 1 + drivers/iommu/intel/svm.c | 8 +- drivers/iommu/ioasid.c | 390 +--- include/linux/ioasid.h | 82 -- 5 files changed, 465 insertions(+), 43 deletions(-) diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c index a3a0b5c8921d..5813eeaa5edb 100644 --- a/drivers/iommu/intel/iommu.c +++ b/drivers/iommu/intel/iommu.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -103,6 +104,9 @@ */ #define INTEL_IOMMU_PGSIZES(~0xFFFUL) +/* PASIDs used by host SVM */ +struct ioasid_set *host_pasid_set; + static inline int agaw_to_level(int agaw) { return agaw + 2; @@ -3103,8 +3107,8 @@ static void intel_vcmd_ioasid_free(ioasid_t ioasid, void *data) * Sanity check the ioasid owner is done at upper layer, e.g. VFIO * We can only free the PASID when all the devices are unbound. */ - if (ioasid_find(NULL, ioasid, NULL)) { - pr_alert("Cannot free active IOASID %d\n", ioasid); + if (IS_ERR(ioasid_find(host_pasid_set, ioasid, NULL))) { + pr_err("Cannot free IOASID %d, not in system set\n", ioasid); return; } vcmd_free_pasid(iommu, ioasid); @@ -3288,6 +3292,19 @@ static int __init init_dmars(void) if (ret) goto free_iommu; + /* PASID is needed for scalable mode irrespective to SVM */ + if (intel_iommu_sm) { + ioasid_install_capacity(intel_pasid_max_id); + /* We should not run out of IOASIDs at boot */ + host_pasid_set = ioasid_alloc_set(NULL, PID_MAX_DEFAULT, + IOASID_SET_TYPE_NULL); + if (IS_ERR_OR_NULL(host_pasid_set)) { + pr_err("Failed to enable host PASID allocator %lu\n", + PTR_ERR(host_pasid_set)); + intel_iommu_sm = 0; + } + } + /* * for each drhd * enable fault log @@ -5149,7 +5166,7 @@ static void auxiliary_unlink_device(struct dmar_domain *domain, domain->auxd_refcnt--; if (!domain->auxd_refcnt && domain->default_pasid > 0) - ioasid_free(domain->default_pasid); + ioasid_free(host_pasid_set, domain->default_pasid); } static int aux_domain_add_dev(struct dmar_domain *domain, @@ -5167,7 +5184,7 @@ static int aux_domain_add_dev(struct dmar_domain *domain, int pasid; /* No private data needed for the default pasid */ - pasid = ioasid_alloc(NULL, PASID_MIN, + pasid = ioasid_alloc(host_pasid_set, PASID_MIN, pci_max_pasids(to_pci_dev(dev)) - 1, NULL); if (pasid == INVALID_IOASID) { @@ -5210,7 +5227,7 @@ static int aux_domain_add_dev(struct dmar_domain *domain, spin_unlock(>lock); spin_unlock_irqrestore(_domain_lock, flags); if (!domain->auxd_refcnt && domain->default_pasid > 0) - ioasid_free(domain->default_pasid); + ioasid_free(host_pasid_set, domain->default_pasid); return ret; } diff --git a/drivers/iommu/intel/pasid.h b/drivers/iommu/intel/pasid.h index c9850766c3a9..ccdc23446015 100644 --- a/drivers/iommu/intel/pasid.h +++ b/drivers/iommu/intel/pasid.h @@ -99,6 +99,7 @@ static inline bool pasid_pte_is_present(struct pasid_entry *pte) } extern u32 intel_pasid_max_id; +extern struct ioasid_set *host_pasid_set; int intel_pasid_alloc_id(void *ptr, int start, int end, gfp_t gfp); void intel_pasid_free_id(int pasid); void *intel_pasid_lookup_id(int pasid); diff --git a/drivers/iommu/intel/svm.c b/drivers/iommu/intel/svm.c index 37a9beabc0ca..634e191ca2c3 100644 --- a/drivers/iommu/intel/svm.c +++ b/drivers/iommu/intel/svm.c @@ -551,7 +551,7 @@ intel_svm_bind_mm(struct device *dev, int flags, struct svm_dev_ops *ops, pasid_max =