diff mbox

[v11,13/23] x86: refactor psr: CDP: implement CPU init flow.

Message ID 1493801063-38513-14-git-send-email-yi.y.sun@linux.intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Yi Sun May 3, 2017, 8:44 a.m. UTC
This patch implements the CPU init flow for CDP. The flow is almost
same as L3 CAT.

Signed-off-by: Yi Sun <yi.y.sun@linux.intel.com>
---
v11:
    - changes about 'feat_props'.
      (suggested by Jan Beulich)
    - remove MSR restore action which is unnecessary.
      (suggested by Jan Beulich)
    - modify commit message.
v10:
    - fix comment.
      (suggested by Jan Beulich)
    - use swith in 'cat_init_feature' to handle different feature types.
      (suggested by Jan Beulich)
    - changes about 'props'.
      (suggested by Jan Beulich)
    - restore MSRs to default value when cpu online.
      (suggested by Jan Beulich)
    - remove feat_mask.
      (suggested by Jan Beulich)
v9:
    - modify commit message to describe flow clearer.
    - handle cpu offline and online again case to read MSRs registers values
      back and save them into cos array to make user can get real data.
    - modify error handling process in 'psr_cpu_prepare' to reduce redundant
      codes.
    - modify 'get_cdp_data' and 'get_cdp_code' to make them standard.
      (suggested by Roger Pau and Jan Beulich)
    - encapsulate CDP operations into 'cat_init_feature' to reduce redundant
      codes.
      (suggested by Roger Pau)
    - reuse 'cat_get_cos_max' for CDP.
      (suggested by Roger Pau)
    - handle 'PSR_CDP' in psr_presmp_init to make init work can be done when
      there is only 'psr=cdp' in cmdline.
    - remove unnecessary comment.
      (suggested by Jan Beulich)
    - move CDP related codes in 'cpu_init_work' into 'psr_cpu_init'.
      (suggested by Jan Beulich)
    - add codes to handle CDP's 'cos_num'.
      (suggested by Jan Beulich)
    - fix coding style issue.
      (suggested by Jan Beulich)
    - do not free resources when allocation fails in 'psr_cpu_prepare'.
      (suggested by Jan Beulich)
    - changes about 'uint64_t' to 'uint32_t'.
      (suggested by Jan Beulich)
v7:
    - initialize 'l3_cdp'.
      (suggested by Konrad Rzeszutek Wilk)
v6:
    - use 'cpuid_leaf'.
      (suggested by Konrad Rzeszutek Wilk and Jan Beulich)
v5:
    - remove codes to free 'feat_l3_cdp' in 'free_feature'.
      (suggested by Jan Beulich)
    - encapsulate cpuid registers into 'struct cpuid_leaf_regs'.
      (suggested by Jan Beulich)
    - print socket info when 'opt_cpu_info' is true.
      (suggested by Jan Beulich)
    - rename 'l3_cdp_get_max_cos_max' to 'l3_cdp_get_cos_max'.
      (suggested by Jan Beulich)
    - rename 'dat[]' to 'data[]'.
      (suggested by Jan Beulich)
    - move 'cpu_prepare_work' contents into 'psr_cpu_prepare'.
      (suggested by Jan Beulich)
v4:
    - create this patch to make codes easier to understand.
      (suggested by Jan Beulich)
---
 xen/arch/x86/psr.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 68 insertions(+), 9 deletions(-)

Comments

Jan Beulich May 31, 2017, 9:37 a.m. UTC | #1
>>> On 03.05.17 at 10:44, <yi.y.sun@linux.intel.com> wrote:
> @@ -150,11 +151,28 @@ static DEFINE_PER_CPU(struct psr_assoc, psr_assoc);
>   * array creation. It is used to transiently store a spare node.
>   */
>  static struct feat_node *feat_l3_cat;
> +static struct feat_node *feat_l3_cdp;
>  
>  /* Common functions */
>  #define cat_default_val(len) (0xffffffff >> (32 - (len)))
>  
>  /*
> + * get_cdp_data - get DATA COS register value from input COS ID.
> + * @feat:        the feature node.
> + * @cos:         the COS ID.
> + */
> +#define get_cdp_data(feat, cos)              \
> +            ( (feat)->cos_reg_val[(cos) * 2] )

Stray blanks inside parentheses.

> +/*
> + * get_cdp_code - get CODE COS register value from input COS ID.
> + * @feat:        the feature node.
> + * @cos:         the COS ID.
> + */
> +#define get_cdp_code(feat, cos)              \
> +            ( (feat)->cos_reg_val[(cos) * 2 + 1] )

Same here. In fact, while I'm not going to ask to remove the
parentheses, this is the one case where an expression a macro
expands to does not strictly need an outer pair of parentheses,
as suffix expressions have highest precedence anyway.

> @@ -249,6 +267,25 @@ static void cat_init_feature(const struct cpuid_leaf *regs,
>  
>          break;
>  
> +    case PSR_SOCKET_L3_CDP:
> +    {
> +        unsigned long val;

As MSR values are specifically 64-bit ones, I think uint64_t would
be more appropriate here. Depending on intended later additions to
this function it may also be worthwhile making this a switch-wide
variable.

> +        /* Cut half of cos_max when CDP is enabled. */
> +        feat->cos_max >>= 1;
> +
> +        /* We only write mask1 since mask0 is always all ones by default. */

Is this, btw, just reset state or even guaranteed after offlining
and re-onlining a CPU?

> +        wrmsrl(MSR_IA32_PSR_L3_MASK(1), cat_default_val(feat->cbm_len));
> +        rdmsrl(MSR_IA32_PSR_L3_QOS_CFG, val);
> +        wrmsrl(MSR_IA32_PSR_L3_QOS_CFG, val | (1 << PSR_L3_QOS_CDP_ENABLE_BIT));

1u at the very least, perhaps even 1ull.

Jan
Yi Sun June 2, 2017, 7:26 a.m. UTC | #2
On 17-05-31 03:37:48, Jan Beulich wrote:
> >>> On 03.05.17 at 10:44, <yi.y.sun@linux.intel.com> wrote:
> > @@ -150,11 +151,28 @@ static DEFINE_PER_CPU(struct psr_assoc, psr_assoc);
> > @@ -249,6 +267,25 @@ static void cat_init_feature(const struct cpuid_leaf *regs,
> >  
> >          break;
> >  
> > +    case PSR_SOCKET_L3_CDP:
> > +    {
> > +        unsigned long val;
> 
> As MSR values are specifically 64-bit ones, I think uint64_t would
> be more appropriate here. Depending on intended later additions to
> this function it may also be worthwhile making this a switch-wide
> variable.
> 
This variable is only used in this case. Will change it to uint64_t.

> > +        /* Cut half of cos_max when CDP is enabled. */
> > +        feat->cos_max >>= 1;
> > +
> > +        /* We only write mask1 since mask0 is always all ones by default. */
> 
> Is this, btw, just reset state or even guaranteed after offlining
> and re-onlining a CPU?
> 
Below MSRs are all per socket. So, we just need reset them when socket is
online.

> > +        wrmsrl(MSR_IA32_PSR_L3_MASK(1), cat_default_val(feat->cbm_len));
> > +        rdmsrl(MSR_IA32_PSR_L3_QOS_CFG, val);
> > +        wrmsrl(MSR_IA32_PSR_L3_QOS_CFG, val | (1 << PSR_L3_QOS_CDP_ENABLE_BIT));
> 
> 1u at the very least, perhaps even 1ull.
> 
Thanks!

> Jan
Jan Beulich June 6, 2017, 7:45 a.m. UTC | #3
>>> On 02.06.17 at 09:26, <yi.y.sun@linux.intel.com> wrote:
> On 17-05-31 03:37:48, Jan Beulich wrote:
>> >>> On 03.05.17 at 10:44, <yi.y.sun@linux.intel.com> wrote:
>> > +        /* Cut half of cos_max when CDP is enabled. */
>> > +        feat->cos_max >>= 1;
>> > +
>> > +        /* We only write mask1 since mask0 is always all ones by default. */
>> 
>> Is this, btw, just reset state or even guaranteed after offlining
>> and re-onlining a CPU?
>> 
> Below MSRs are all per socket. So, we just need reset them when socket is
> online.

Which I hope you've understood then means the comment and
presumably also the code here need further refinement.

Jan
Yi Sun June 6, 2017, 8:13 a.m. UTC | #4
On 17-06-06 01:45:11, Jan Beulich wrote:
> >>> On 02.06.17 at 09:26, <yi.y.sun@linux.intel.com> wrote:
> > On 17-05-31 03:37:48, Jan Beulich wrote:
> >> >>> On 03.05.17 at 10:44, <yi.y.sun@linux.intel.com> wrote:
> >> > +        /* Cut half of cos_max when CDP is enabled. */
> >> > +        feat->cos_max >>= 1;
> >> > +
> >> > +        /* We only write mask1 since mask0 is always all ones by default. */
> >> 
> >> Is this, btw, just reset state or even guaranteed after offlining
> >> and re-onlining a CPU?
> >> 
> > Below MSRs are all per socket. So, we just need reset them when socket is
> > online.
> 
> Which I hope you've understood then means the comment and
> presumably also the code here need further refinement.
> 
Spec states it below. So, the mask0 is guranteed.
"the default mask in IA32_L3_MASK_0 - which is all “1”s (on reset)"

> Jan
Jan Beulich June 6, 2017, 8:38 a.m. UTC | #5
>>> On 06.06.17 at 10:13, <yi.y.sun@linux.intel.com> wrote:
> On 17-06-06 01:45:11, Jan Beulich wrote:
>> >>> On 02.06.17 at 09:26, <yi.y.sun@linux.intel.com> wrote:
>> > On 17-05-31 03:37:48, Jan Beulich wrote:
>> >> >>> On 03.05.17 at 10:44, <yi.y.sun@linux.intel.com> wrote:
>> >> > +        /* Cut half of cos_max when CDP is enabled. */
>> >> > +        feat->cos_max >>= 1;
>> >> > +
>> >> > +        /* We only write mask1 since mask0 is always all ones by default. */
>> >> 
>> >> Is this, btw, just reset state or even guaranteed after offlining
>> >> and re-onlining a CPU?
>> >> 
>> > Below MSRs are all per socket. So, we just need reset them when socket is
>> > online.
>> 
>> Which I hope you've understood then means the comment and
>> presumably also the code here need further refinement.
>> 
> Spec states it below. So, the mask0 is guranteed.
> "the default mask in IA32_L3_MASK_0 - which is all “1”s (on reset)"

Sigh. I did ask very clearly (and this is still visible above) about
the case where the CPU did _not_ undergo a reset cycle.

Jan
Yi Sun June 7, 2017, 1:31 a.m. UTC | #6
On 17-06-06 02:38:27, Jan Beulich wrote:
> >>> On 06.06.17 at 10:13, <yi.y.sun@linux.intel.com> wrote:
> > On 17-06-06 01:45:11, Jan Beulich wrote:
> >> >>> On 02.06.17 at 09:26, <yi.y.sun@linux.intel.com> wrote:
> >> > On 17-05-31 03:37:48, Jan Beulich wrote:
> >> >> >>> On 03.05.17 at 10:44, <yi.y.sun@linux.intel.com> wrote:
> >> >> > +        /* Cut half of cos_max when CDP is enabled. */
> >> >> > +        feat->cos_max >>= 1;
> >> >> > +
> >> >> > +        /* We only write mask1 since mask0 is always all ones by default. */
> >> >> 
> >> >> Is this, btw, just reset state or even guaranteed after offlining
> >> >> and re-onlining a CPU?
> >> >> 
> >> > Below MSRs are all per socket. So, we just need reset them when socket is
> >> > online.
> >> 
> >> Which I hope you've understood then means the comment and
> >> presumably also the code here need further refinement.
> >> 
> > Spec states it below. So, the mask0 is guranteed.
> > "the default mask in IA32_L3_MASK_0 - which is all “1”s (on reset)"
> 
> Sigh. I did ask very clearly (and this is still visible above) about
> the case where the CPU did _not_ undergo a reset cycle.
> 
Sorry, I think I must mis-understand your question. SW never modifies value
of COS ID 0 mask register. So, the value in mask0 will not be changed after
socket first online (mask0 is set to default by HW this time). So, we think
it is not necessary to restore mask0 value to default here.
Yi Sun June 7, 2017, 7:28 a.m. UTC | #7
On 17-06-07 09:31:02, Yi Sun wrote:
> On 17-06-06 02:38:27, Jan Beulich wrote:
> > >>> On 06.06.17 at 10:13, <yi.y.sun@linux.intel.com> wrote:
> > > On 17-06-06 01:45:11, Jan Beulich wrote:
> > >> >>> On 02.06.17 at 09:26, <yi.y.sun@linux.intel.com> wrote:
> > >> > On 17-05-31 03:37:48, Jan Beulich wrote:
> > >> >> >>> On 03.05.17 at 10:44, <yi.y.sun@linux.intel.com> wrote:
> > >> >> > +        /* Cut half of cos_max when CDP is enabled. */
> > >> >> > +        feat->cos_max >>= 1;
> > >> >> > +
> > >> >> > +        /* We only write mask1 since mask0 is always all ones by default. */
> > >> >> 
> > >> >> Is this, btw, just reset state or even guaranteed after offlining
> > >> >> and re-onlining a CPU?
> > >> >> 
> > >> > Below MSRs are all per socket. So, we just need reset them when socket is
> > >> > online.
> > >> 
> > >> Which I hope you've understood then means the comment and
> > >> presumably also the code here need further refinement.
> > >> 
> > > Spec states it below. So, the mask0 is guranteed.
> > > "the default mask in IA32_L3_MASK_0 - which is all “1”s (on reset)"
> > 
> > Sigh. I did ask very clearly (and this is still visible above) about
> > the case where the CPU did _not_ undergo a reset cycle.
> > 
> Sorry, I think I must mis-understand your question. SW never modifies value
> of COS ID 0 mask register. So, the value in mask0 will not be changed after
> socket first online (mask0 is set to default by HW this time). So, we think
> it is not necessary to restore mask0 value to default here.
> 
But considering something else (e.g. FW) may change this MSR value during
socket offline-online cycle, we may need to restore mask0 here too. Is that
your intention? Thanks!

> _______________________________________________
> Xen-devel mailing list
> Xen-devel@lists.xen.org
> https://lists.xen.org/xen-devel
Jan Beulich June 7, 2017, 8:14 a.m. UTC | #8
>>> On 07.06.17 at 03:31, <yi.y.sun@linux.intel.com> wrote:
> On 17-06-06 02:38:27, Jan Beulich wrote:
>> >>> On 06.06.17 at 10:13, <yi.y.sun@linux.intel.com> wrote:
>> > On 17-06-06 01:45:11, Jan Beulich wrote:
>> >> >>> On 02.06.17 at 09:26, <yi.y.sun@linux.intel.com> wrote:
>> >> > On 17-05-31 03:37:48, Jan Beulich wrote:
>> >> >> >>> On 03.05.17 at 10:44, <yi.y.sun@linux.intel.com> wrote:
>> >> >> > +        /* Cut half of cos_max when CDP is enabled. */
>> >> >> > +        feat->cos_max >>= 1;
>> >> >> > +
>> >> >> > +        /* We only write mask1 since mask0 is always all ones by default. */
>> >> >> 
>> >> >> Is this, btw, just reset state or even guaranteed after offlining
>> >> >> and re-onlining a CPU?
>> >> >> 
>> >> > Below MSRs are all per socket. So, we just need reset them when socket is
>> >> > online.
>> >> 
>> >> Which I hope you've understood then means the comment and
>> >> presumably also the code here need further refinement.
>> >> 
>> > Spec states it below. So, the mask0 is guranteed.
>> > "the default mask in IA32_L3_MASK_0 - which is all “1”s (on reset)"
>> 
>> Sigh. I did ask very clearly (and this is still visible above) about
>> the case where the CPU did _not_ undergo a reset cycle.
>> 
> Sorry, I think I must mis-understand your question. SW never modifies value
> of COS ID 0 mask register. So, the value in mask0 will not be changed after
> socket first online (mask0 is set to default by HW this time). So, we think
> it is not necessary to restore mask0 value to default here.

Is the register read-only? If so, writing it would indeed be
unnecessary (and likely wrong, as it might raise #GP then
instead of being ignored). If not, firmware may have written it,
so you'll want to write it even during boot time CPU bringup.

Jan
Yi Sun June 7, 2017, 9 a.m. UTC | #9
On 17-06-07 02:14:26, Jan Beulich wrote:
> >>> On 07.06.17 at 03:31, <yi.y.sun@linux.intel.com> wrote:
> > On 17-06-06 02:38:27, Jan Beulich wrote:
> >> >>> On 06.06.17 at 10:13, <yi.y.sun@linux.intel.com> wrote:
> >> > On 17-06-06 01:45:11, Jan Beulich wrote:
> >> >> >>> On 02.06.17 at 09:26, <yi.y.sun@linux.intel.com> wrote:
> >> >> > On 17-05-31 03:37:48, Jan Beulich wrote:
> >> >> >> >>> On 03.05.17 at 10:44, <yi.y.sun@linux.intel.com> wrote:
> >> >> >> > +        /* Cut half of cos_max when CDP is enabled. */
> >> >> >> > +        feat->cos_max >>= 1;
> >> >> >> > +
> >> >> >> > +        /* We only write mask1 since mask0 is always all ones by default. */
> >> >> >> 
> >> >> >> Is this, btw, just reset state or even guaranteed after offlining
> >> >> >> and re-onlining a CPU?
> >> >> >> 
> >> >> > Below MSRs are all per socket. So, we just need reset them when socket is
> >> >> > online.
> >> >> 
> >> >> Which I hope you've understood then means the comment and
> >> >> presumably also the code here need further refinement.
> >> >> 
> >> > Spec states it below. So, the mask0 is guranteed.
> >> > "the default mask in IA32_L3_MASK_0 - which is all “1”s (on reset)"
> >> 
> >> Sigh. I did ask very clearly (and this is still visible above) about
> >> the case where the CPU did _not_ undergo a reset cycle.
> >> 
> > Sorry, I think I must mis-understand your question. SW never modifies value
> > of COS ID 0 mask register. So, the value in mask0 will not be changed after
> > socket first online (mask0 is set to default by HW this time). So, we think
> > it is not necessary to restore mask0 value to default here.
> 
> Is the register read-only? If so, writing it would indeed be
> unnecessary (and likely wrong, as it might raise #GP then
> instead of being ignored). If not, firmware may have written it,
> so you'll want to write it even during boot time CPU bringup.
> 
No, it is writable. I will restore mask0 to default value here.
Furthermore, for L3/L2 CAT mask0, we may need to restore mask0
too.

> Jan
diff mbox

Patch

diff --git a/xen/arch/x86/psr.c b/xen/arch/x86/psr.c
index 9b8428d..7000d95 100644
--- a/xen/arch/x86/psr.c
+++ b/xen/arch/x86/psr.c
@@ -62,6 +62,7 @@ 
 
 enum psr_feat_type {
     PSR_SOCKET_L3_CAT,
+    PSR_SOCKET_L3_CDP,
     PSR_SOCKET_FEAT_NUM,
     PSR_SOCKET_FEAT_UNKNOWN,
 };
@@ -150,11 +151,28 @@  static DEFINE_PER_CPU(struct psr_assoc, psr_assoc);
  * array creation. It is used to transiently store a spare node.
  */
 static struct feat_node *feat_l3_cat;
+static struct feat_node *feat_l3_cdp;
 
 /* Common functions */
 #define cat_default_val(len) (0xffffffff >> (32 - (len)))
 
 /*
+ * get_cdp_data - get DATA COS register value from input COS ID.
+ * @feat:        the feature node.
+ * @cos:         the COS ID.
+ */
+#define get_cdp_data(feat, cos)              \
+            ( (feat)->cos_reg_val[(cos) * 2] )
+
+/*
+ * get_cdp_code - get CODE COS register value from input COS ID.
+ * @feat:        the feature node.
+ * @cos:         the COS ID.
+ */
+#define get_cdp_code(feat, cos)              \
+            ( (feat)->cos_reg_val[(cos) * 2 + 1] )
+
+/*
  * Use this function to check if any allocation feature has been enabled
  * in cmdline.
  */
@@ -249,6 +267,25 @@  static void cat_init_feature(const struct cpuid_leaf *regs,
 
         break;
 
+    case PSR_SOCKET_L3_CDP:
+    {
+        unsigned long val;
+
+        /* Cut half of cos_max when CDP is enabled. */
+        feat->cos_max >>= 1;
+
+        /* We only write mask1 since mask0 is always all ones by default. */
+        wrmsrl(MSR_IA32_PSR_L3_MASK(1), cat_default_val(feat->cbm_len));
+        rdmsrl(MSR_IA32_PSR_L3_QOS_CFG, val);
+        wrmsrl(MSR_IA32_PSR_L3_QOS_CFG, val | (1 << PSR_L3_QOS_CDP_ENABLE_BIT));
+
+        /* cos=0 is reserved as default cbm(all bits within cbm_len are 1). */
+        get_cdp_code(feat, 0) = cat_default_val(feat->cbm_len);
+        get_cdp_data(feat, 0) = cat_default_val(feat->cbm_len);
+
+        break;
+    }
+
     default:
         return;
     }
@@ -259,8 +296,9 @@  static void cat_init_feature(const struct cpuid_leaf *regs,
     if ( !opt_cpu_info )
         return;
 
-    printk(XENLOG_INFO "%s CAT: enabled on socket %u, cos_max:%u, cbm_len:%u\n",
-           ((type == PSR_SOCKET_L3_CAT) ? "L3" : "L2"),
+    printk(XENLOG_INFO "%s: enabled on socket %u, cos_max:%u, cbm_len:%u\n",
+           ((type == PSR_SOCKET_L3_CDP) ? "CDP" :
+            ((type == PSR_SOCKET_L3_CAT) ? "L3 CAT": "L2 CAT")),
            cpu_to_socket(smp_processor_id()), feat->cos_max, feat->cbm_len);
 }
 
@@ -289,6 +327,11 @@  static struct feat_props l3_cat_props = {
     .write_msr = l3_cat_write_msr,
 };
 
+/* L3 CDP props */
+static struct feat_props l3_cdp_props = {
+    .cos_num = 2,
+};
+
 static void __init parse_psr_bool(char *s, char *value, char *feature,
                                   unsigned int mask)
 {
@@ -1206,6 +1249,10 @@  static int psr_cpu_prepare(void)
          (feat_l3_cat = xzalloc(struct feat_node)) == NULL )
         return -ENOMEM;
 
+    if ( feat_l3_cdp == NULL &&
+         (feat_l3_cdp = xzalloc(struct feat_node)) == NULL )
+        return -ENOMEM;
+
     return 0;
 }
 
@@ -1238,12 +1285,24 @@  static void psr_cpu_init(void)
     {
         cpuid_count_leaf(PSR_CPUID_LEVEL_CAT, 1, &regs);
 
-        feat = feat_l3_cat;
-        feat_l3_cat = NULL;
-        l3_cat_props.type[0] = PSR_CBM_TYPE_L3;
-        feat_props[PSR_SOCKET_L3_CAT] = &l3_cat_props;
-
-        cat_init_feature(&regs, feat, info, PSR_SOCKET_L3_CAT);
+        if ( (regs.c & PSR_CAT_CDP_CAPABILITY) && (opt_psr & PSR_CDP) &&
+             !info->features[PSR_SOCKET_L3_CDP] )
+        {
+            feat = feat_l3_cdp;
+            feat_l3_cdp = NULL;
+            l3_cdp_props.type[0] = PSR_CBM_TYPE_L3_DATA;
+            l3_cdp_props.type[1] = PSR_CBM_TYPE_L3_CODE;
+            feat_props[PSR_SOCKET_L3_CDP] = &l3_cdp_props;
+            cat_init_feature(&regs, feat, info, PSR_SOCKET_L3_CDP);
+        }
+        else
+        {
+            feat = feat_l3_cat;
+            feat_l3_cat = NULL;
+            l3_cat_props.type[0] = PSR_CBM_TYPE_L3;
+            feat_props[PSR_SOCKET_L3_CAT] = &l3_cat_props;
+            cat_init_feature(&regs, feat, info, PSR_SOCKET_L3_CAT);
+        }
 
         info->feat_init = true;
     }
@@ -1305,7 +1364,7 @@  static int __init psr_presmp_init(void)
     if ( (opt_psr & PSR_CMT) && opt_rmid_max )
         init_psr_cmt(opt_rmid_max);
 
-    if ( opt_psr & PSR_CAT )
+    if ( opt_psr & (PSR_CAT | PSR_CDP) )
         init_psr();
 
     if ( psr_cpu_prepare() )