]> xenbits.xensource.com Git - xen.git/commitdiff
xen: enable Dom0 to use SVE feature
authorLuca Fancellu <luca.fancellu@arm.com>
Wed, 31 May 2023 07:24:08 +0000 (08:24 +0100)
committerJulien Grall <jgrall@amazon.com>
Wed, 7 Jun 2023 10:21:41 +0000 (11:21 +0100)
Add a command line parameter to allow Dom0 the use of SVE resources,
the command line parameter sve=<integer>, sub argument of dom0=,
controls the feature on this domain and sets the maximum SVE vector
length for Dom0.

Add a new function, parse_signed_integer(), to parse an integer
command line argument.

Signed-off-by: Luca Fancellu <luca.fancellu@arm.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com> # !arm
Reviewed-by: Bertrand Marquis <bertrand.marquis@arm.com>
docs/misc/xen-command-line.pandoc
xen/arch/arm/arm64/sve.c
xen/arch/arm/domain_build.c
xen/arch/arm/include/asm/arm64/sve.h
xen/common/kernel.c
xen/include/xen/lib.h

index e0b89b7d331950b37b2604aef8077b6f1175d216..4060ebdc5d76c4d12c44661c318d80ce9b73b2ea 100644 (file)
@@ -777,9 +777,9 @@ Specify the bit width of the DMA heap.
 
 ### dom0
     = List of [ pv | pvh, shadow=<bool>, verbose=<bool>,
-                cpuid-faulting=<bool>, msr-relaxed=<bool> ]
+                cpuid-faulting=<bool>, msr-relaxed=<bool> ] (x86)
 
-    Applicability: x86
+    = List of [ sve=<integer> ] (Arm64)
 
 Controls for how dom0 is constructed on x86 systems.
 
@@ -838,6 +838,22 @@ Controls for how dom0 is constructed on x86 systems.
 
     If using this option is necessary to fix an issue, please report a bug.
 
+Enables features on dom0 on Arm systems.
+
+*   The `sve` integer parameter enables Arm SVE usage for Dom0 and sets the
+    maximum SVE vector length, the option is applicable only to Arm64 Dom0
+    kernels.
+    A value equal to 0 disables the feature, this is the default value.
+    Values below 0 means the feature uses the maximum SVE vector length
+    supported by hardware, if SVE is supported.
+    Values above 0 explicitly set the maximum SVE vector length for Dom0,
+    allowed values are from 128 to maximum 2048, being multiple of 128.
+    Please note that when the user explicitly specifies the value, if that value
+    is above the hardware supported maximum SVE vector length, the domain
+    creation will fail and the system will stop, the same will occur if the
+    option is provided with a positive non zero value, but the platform doesn't
+    support SVE.
+
 ### dom0-cpuid
     = List of comma separated booleans
 
index 56d8f27ea26a4f3822149d1ae682045484894848..23a9d0ba661c348304c58e439d327611483fa479 100644 (file)
@@ -13,6 +13,9 @@
 #include <asm/processor.h>
 #include <asm/system.h>
 
+/* opt_dom0_sve: allow Dom0 to use SVE and set maximum vector length. */
+int __initdata opt_dom0_sve;
+
 extern unsigned int sve_get_hw_vl(void);
 
 /*
@@ -152,6 +155,23 @@ void sve_restore_state(struct vcpu *v)
     sve_load_ctx(v->arch.vfp.sve_zreg_ctx_end, v->arch.vfp.fpregs, 1);
 }
 
+bool __init sve_domctl_vl_param(int val, unsigned int *out)
+{
+    /*
+     * Negative SVE parameter value means to use the maximum supported
+     * vector length, otherwise if a positive value is provided, check if the
+     * vector length is a multiple of 128
+     */
+    if ( val < 0 )
+        *out = get_sys_vl_len();
+    else if ( (val % SVE_VL_MULTIPLE_VAL) == 0 )
+        *out = val;
+    else
+        return false;
+
+    return true;
+}
+
 /*
  * Local variables:
  * mode: C
index e2f0639914238d49ac6cdd89eee10a417493be1e..14b42120a9b1a902466f0459e1fd8cb0853b36fd 100644 (file)
@@ -62,6 +62,22 @@ custom_param("dom0_mem", parse_dom0_mem);
 
 int __init parse_arch_dom0_param(const char *s, const char *e)
 {
+    long long val;
+
+    if ( !parse_signed_integer("sve", s, e, &val) )
+    {
+#ifdef CONFIG_ARM64_SVE
+        if ( (val >= INT_MIN) && (val <= INT_MAX) )
+            opt_dom0_sve = val;
+        else
+            printk(XENLOG_INFO "'sve=%lld' value out of range!\n", val);
+
+        return 0;
+#else
+        panic("'sve' property found, but CONFIG_ARM64_SVE not selected");
+#endif
+    }
+
     return -EINVAL;
 }
 
@@ -4134,6 +4150,16 @@ void __init create_dom0(void)
     if ( iommu_enabled )
         dom0_cfg.flags |= XEN_DOMCTL_CDF_iommu;
 
+    if ( opt_dom0_sve )
+    {
+        unsigned int vl;
+
+        if ( sve_domctl_vl_param(opt_dom0_sve, &vl) )
+            dom0_cfg.arch.sve_vl = sve_encode_vl(vl);
+        else
+            panic("SVE vector length error\n");
+    }
+
     dom0 = domain_create(0, &dom0_cfg, CDF_privileged | CDF_directmap);
     if ( IS_ERR(dom0) )
         panic("Error creating domain 0 (rc = %ld)\n", PTR_ERR(dom0));
index 65b46685d263b791b83b50c83dba68074fd8fda8..a71d6a295dcc39741119a22396026ee8e566366c 100644 (file)
@@ -21,14 +21,22 @@ static inline unsigned int sve_decode_vl(unsigned int sve_vl)
     return sve_vl * SVE_VL_MULTIPLE_VAL;
 }
 
+static inline unsigned int sve_encode_vl(unsigned int sve_vl_bits)
+{
+    return sve_vl_bits / SVE_VL_MULTIPLE_VAL;
+}
+
 register_t compute_max_zcr(void);
 int sve_context_init(struct vcpu *v);
 void sve_context_free(struct vcpu *v);
 void sve_save_state(struct vcpu *v);
 void sve_restore_state(struct vcpu *v);
+bool sve_domctl_vl_param(int val, unsigned int *out);
 
 #ifdef CONFIG_ARM64_SVE
 
+extern int opt_dom0_sve;
+
 static inline bool is_sve_domain(const struct domain *d)
 {
     return d->arch.sve_vl > 0;
@@ -38,6 +46,8 @@ unsigned int get_sys_vl_len(void);
 
 #else /* !CONFIG_ARM64_SVE */
 
+#define opt_dom0_sve     0
+
 static inline bool is_sve_domain(const struct domain *d)
 {
     return false;
index b8b845763d9dc07458780373ffdaf8a005a74fd2..fd975ae21ebc7b4de2788680a7173b493471c002 100644 (file)
@@ -314,6 +314,34 @@ int parse_boolean(const char *name, const char *s, const char *e)
     return -1;
 }
 
+int __init parse_signed_integer(const char *name, const char *s, const char *e,
+                                long long *val)
+{
+    size_t slen, nlen;
+    const char *str;
+    long long pval;
+
+    slen = e ? ({ ASSERT(e >= s); e - s; }) : strlen(s);
+    nlen = strlen(name);
+
+    if ( !e )
+        e = s + slen;
+
+    /* Check that this is the name we're looking for and a value was provided */
+    if ( slen <= nlen || strncmp(s, name, nlen) || s[nlen] != '=' )
+        return -1;
+
+    pval = simple_strtoll(&s[nlen + 1], &str, 10);
+
+    /* Number not recognised */
+    if ( str != e )
+        return -2;
+
+    *val = pval;
+
+    return 0;
+}
+
 int cmdline_strcmp(const char *frag, const char *name)
 {
     for ( ; ; frag++, name++ )
index 75ae7489b9f0c64b89f6045c2dfaf8407c898aaf..67fc7c1d7e3624f1baee70b18311d0c5315378c1 100644 (file)
@@ -94,6 +94,16 @@ int parse_bool(const char *s, const char *e);
  */
 int parse_boolean(const char *name, const char *s, const char *e);
 
+/**
+ * Given a specific name, parses a string of the form:
+ *   $NAME=<integer number>
+ * returning 0 and a value in val, for a recognised integer.
+ * Returns -1 for name not found, general errors, or -2 if name is found but
+ * not recognised number.
+ */
+int parse_signed_integer(const char *name, const char *s, const char *e,
+                         long long *val);
+
 /**
  * Very similar to strcmp(), but will declare a match if the NUL in 'name'
  * lines up with comma, colon, semicolon or equals in 'frag'.  Designed for