diff mbox

[v10,07/25] x86: refactor psr: L3 CAT: implement get hw info flow.

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

Commit Message

Yi Sun April 1, 2017, 1:53 p.m. UTC
This patch implements get HW info flow including L3 CAT callback
function.

It also changes sysctl interface to make it more general.

With this patch, 'psr-hwinfo' can work for L3 CAT.

Signed-off-by: Yi Sun <yi.y.sun@linux.intel.com>
---
v10:
    - remove 'PSR_SOCKET_UNKNOWN' and use 'ASSERT_UNREACHABLE()' to handle
      this case.
      (suggested by Jan Beulich)
    - check 'feat_type'.
      (suggested by Jan Beulich)
    - adjust macros names and values to make them more appropriate.
      (suggested by Jan Beulich)
    - use 'feat_init_done'.
      (suggested by Jan Beulich)
    - changes about 'cbm_len'.
      (suggested by Jan Beulich)
v9:
    - replace feature list handling to feature array handling.
      (suggested by Roger Pau)
    - define 'PSR_INFO_SIZE'.
      (suggested by Roger Pau)
    - fix coding style issue.
      (suggested by Roger Pau and Jan Beulich)
    - use 'ARRAY_SIZE'.
      (suggested by Roger Pau)
    - rename 'l3_cat_get_feat_info' to 'cat_get_feat_info' to make it a common
      function for both L3/L2 CAT.
      (suggested by Roger Pau)
    - move constant to the right of comparison.
      (suggested by Wei Liu)
    - remove wrong comment.
      (suggested by Jan Beulich)
    - rename macros used by psr_get_info to make them meaningful.
      (suggested by Jan Beulich)
    - remove assignment for 'PSR_SOCKET_UNKNOWN'.
      (suggested by Jan Beulich)
    - retain blank line after 'case XEN_SYSCTL_PSR_CAT_get_l3_info'.
      (suggested by Jan Beulich)
    - modify patch title to indicate 'L3 CAT'.
      (suggested by Jan Beulich)
    - move common data check into common function.
      (suggested by Jan Beulich)
v6:
    - fix coding style issue.
      (suggested by Konrad Rzeszutek Wilk)
    - define 'PSR_SOCKET_UNKNOWN' in 'psr_feat_type'.
      (suggested by Konrad Rzeszutek Wilk)
    - change '-ENOTSOCK' to 'ERANGE'.
      (suggested by Konrad Rzeszutek Wilk)
    - modify position of macros to remove odd spacing in psr.h.
      (suggested by Konrad Rzeszutek Wilk)
v5:
    - change 'dat[]' to 'data[]'.
      (suggested by Jan Beulich)
    - modify parameter type to avoid fixed width type when there is no such
      intention.
      (suggested by Jan Beulich)
    - use 'const' when it is possible.
      (suggested by Jan Beulich)
    - check feature type outside callback function.
      (suggested by Jan Beulich)
    - modify macros names to add prefix 'PSR_' and change 'CDP_FLAG' to
      'PSR_FLAG'.
      (suggested by Jan Beulich)
v4:
    - create this patch to make codes easier to understand.
      (suggested by Jan Beulich)
---
 xen/arch/x86/psr.c        | 75 +++++++++++++++++++++++++++++++++++++++++++++--
 xen/arch/x86/sysctl.c     | 19 +++++++++---
 xen/include/asm-x86/psr.h | 16 ++++++----
 3 files changed, 98 insertions(+), 12 deletions(-)

Comments

Jan Beulich April 5, 2017, 3:37 p.m. UTC | #1
>>> On 01.04.17 at 15:53, <yi.y.sun@linux.intel.com> wrote:
> --- a/xen/arch/x86/psr.c
> +++ b/xen/arch/x86/psr.c
> @@ -93,6 +93,10 @@ struct feat_node {
>          unsigned int cos_num;
>          unsigned int cos_max;
>          unsigned int cbm_len;
> +
> +        /* get_feat_info is used to get feature HW info. */
> +        bool (*get_feat_info)(const struct feat_node *feat,
> +                              uint32_t data[], unsigned int array_len);

The comment isn't very helpful in its current shape. You really want
to make clear that this is being used to return HW info via sysctl.
Without this (and without seeing the rest of this patch), despite
having seen previous versions my first thought was that this
retrieves data from MSRs at initialization time.

> @@ -183,6 +187,22 @@ static bool feat_init_done(const struct psr_socket_info *info)
>      return false;
>  }
>  
> +static enum psr_feat_type psr_cbm_type_to_feat_type(enum cbm_type type)
> +{
> +    enum psr_feat_type feat_type;
> +
> +    switch ( type )
> +    {
> +    case PSR_CBM_TYPE_L3:
> +        feat_type = PSR_SOCKET_L3_CAT;
> +        break;
> +    default:
> +        ASSERT_UNREACHABLE();
> +    }
> +
> +    return feat_type;

I'm pretty certain this will (validly) produce an uninitialized variable
warning at least in a non-debug build. Not how I did say "add
ASSERT_UNREACHABLE()" in the v9 review.

> +int psr_get_info(unsigned int socket, enum cbm_type type,
> +                 uint32_t data[], unsigned int array_len)
> +{
> +    const struct psr_socket_info *info = get_socket_info(socket);
> +    const struct feat_node *feat;
> +    enum psr_feat_type feat_type;
> +
> +    if ( IS_ERR(info) )
> +        return PTR_ERR(info);
> +
> +    if ( !data )
> +        return -EINVAL;

I think I've asked this before - what does this check guard against?
A bad caller? This could be an ASSERT() then. Returning an error to
the sysctl caller because of some implementation bug seems pretty
odd to me.

> +    feat_type = psr_cbm_type_to_feat_type(type);
> +    if ( feat_type > ARRAY_SIZE(info->features) )
> +        return -ENOENT;
> +
> +    feat = info->features[feat_type];

Please can you be more careful when adding checks like the above
one? You still allow overrunning the array, when feat_type
== ARRAY_SIZE(info->features).

Jan
Yi Sun April 6, 2017, 6:05 a.m. UTC | #2
On 17-04-05 09:37:44, Jan Beulich wrote:
> >>> On 01.04.17 at 15:53, <yi.y.sun@linux.intel.com> wrote:
> > --- a/xen/arch/x86/psr.c
> > +++ b/xen/arch/x86/psr.c
> > @@ -93,6 +93,10 @@ struct feat_node {
> >          unsigned int cos_num;
> >          unsigned int cos_max;
> >          unsigned int cbm_len;
> > +
> > +        /* get_feat_info is used to get feature HW info. */
> > +        bool (*get_feat_info)(const struct feat_node *feat,
> > +                              uint32_t data[], unsigned int array_len);
> 
> The comment isn't very helpful in its current shape. You really want
> to make clear that this is being used to return HW info via sysctl.
> Without this (and without seeing the rest of this patch), despite
> having seen previous versions my first thought was that this
> retrieves data from MSRs at initialization time.
> 
Will modify the comment to make it clearer.

> > @@ -183,6 +187,22 @@ static bool feat_init_done(const struct psr_socket_info *info)
> >      return false;
> >  }
> >  
> > +static enum psr_feat_type psr_cbm_type_to_feat_type(enum cbm_type type)
> > +{
> > +    enum psr_feat_type feat_type;
> > +
> > +    switch ( type )
> > +    {
> > +    case PSR_CBM_TYPE_L3:
> > +        feat_type = PSR_SOCKET_L3_CAT;
> > +        break;
> > +    default:
> > +        ASSERT_UNREACHABLE();
> > +    }
> > +
> > +    return feat_type;
> 
> I'm pretty certain this will (validly) produce an uninitialized variable
> warning at least in a non-debug build. Not how I did say "add
> ASSERT_UNREACHABLE()" in the v9 review.
> 
Do you mean to init feat_type to 'PSR_SOCKET_MAX_FEAT' and then check it
at the end of function using ASSERT?

> > +int psr_get_info(unsigned int socket, enum cbm_type type,
> > +                 uint32_t data[], unsigned int array_len)
> > +{
> > +    const struct psr_socket_info *info = get_socket_info(socket);
> > +    const struct feat_node *feat;
> > +    enum psr_feat_type feat_type;
> > +
> > +    if ( IS_ERR(info) )
> > +        return PTR_ERR(info);
> > +
> > +    if ( !data )
> > +        return -EINVAL;
> 
> I think I've asked this before - what does this check guard against?
> A bad caller? This could be an ASSERT() then. Returning an error to
> the sysctl caller because of some implementation bug seems pretty
> odd to me.
> 
Sorry, will use ASSERT for such cases.

> > +    feat_type = psr_cbm_type_to_feat_type(type);
> > +    if ( feat_type > ARRAY_SIZE(info->features) )
> > +        return -ENOENT;
> > +
> > +    feat = info->features[feat_type];
> 
> Please can you be more careful when adding checks like the above
> one? You still allow overrunning the array, when feat_type
> == ARRAY_SIZE(info->features).
> 
Oh, sorry.

> Jan
Jan Beulich April 6, 2017, 8:36 a.m. UTC | #3
>>> On 06.04.17 at 08:05, <yi.y.sun@linux.intel.com> wrote:
> On 17-04-05 09:37:44, Jan Beulich wrote:
>> >>> On 01.04.17 at 15:53, <yi.y.sun@linux.intel.com> wrote:
>> > @@ -183,6 +187,22 @@ static bool feat_init_done(const struct psr_socket_info *info)
>> >      return false;
>> >  }
>> >  
>> > +static enum psr_feat_type psr_cbm_type_to_feat_type(enum cbm_type type)
>> > +{
>> > +    enum psr_feat_type feat_type;
>> > +
>> > +    switch ( type )
>> > +    {
>> > +    case PSR_CBM_TYPE_L3:
>> > +        feat_type = PSR_SOCKET_L3_CAT;
>> > +        break;
>> > +    default:
>> > +        ASSERT_UNREACHABLE();
>> > +    }
>> > +
>> > +    return feat_type;
>> 
>> I'm pretty certain this will (validly) produce an uninitialized variable
>> warning at least in a non-debug build. Not how I did say "add
>> ASSERT_UNREACHABLE()" in the v9 review.
>> 
> Do you mean to init feat_type to 'PSR_SOCKET_MAX_FEAT' and then check it
> at the end of function using ASSERT?

That's a (less desirable) option, but what I really mean is take v9
code and _add_ ASSERT_UNREACHABLE() first thing in the default
case.

Jan
Yi Sun April 6, 2017, 11:16 a.m. UTC | #4
On 17-04-06 02:36:19, Jan Beulich wrote:
> >>> On 06.04.17 at 08:05, <yi.y.sun@linux.intel.com> wrote:
> > On 17-04-05 09:37:44, Jan Beulich wrote:
> >> >>> On 01.04.17 at 15:53, <yi.y.sun@linux.intel.com> wrote:
> >> > @@ -183,6 +187,22 @@ static bool feat_init_done(const struct psr_socket_info *info)
> >> >      return false;
> >> >  }
> >> >  
> >> > +static enum psr_feat_type psr_cbm_type_to_feat_type(enum cbm_type type)
> >> > +{
> >> > +    enum psr_feat_type feat_type;
> >> > +
> >> > +    switch ( type )
> >> > +    {
> >> > +    case PSR_CBM_TYPE_L3:
> >> > +        feat_type = PSR_SOCKET_L3_CAT;
> >> > +        break;
> >> > +    default:
> >> > +        ASSERT_UNREACHABLE();
> >> > +    }
> >> > +
> >> > +    return feat_type;
> >> 
> >> I'm pretty certain this will (validly) produce an uninitialized variable
> >> warning at least in a non-debug build. Not how I did say "add
> >> ASSERT_UNREACHABLE()" in the v9 review.
> >> 
> > Do you mean to init feat_type to 'PSR_SOCKET_MAX_FEAT' and then check it
> > at the end of function using ASSERT?
> 
> That's a (less desirable) option, but what I really mean is take v9
> code and _add_ ASSERT_UNREACHABLE() first thing in the default
> case.
> 

DYM we should initialize 'feat_type' to a valid value, e.g. PSR_SOCKET_L3_CAT
and keep ASSERT_UNREACHABLE() in default case?
Jan Beulich April 6, 2017, 2:04 p.m. UTC | #5
>>> On 06.04.17 at 13:16, <yi.y.sun@linux.intel.com> wrote:
> On 17-04-06 02:36:19, Jan Beulich wrote:
>> >>> On 06.04.17 at 08:05, <yi.y.sun@linux.intel.com> wrote:
>> > On 17-04-05 09:37:44, Jan Beulich wrote:
>> >> >>> On 01.04.17 at 15:53, <yi.y.sun@linux.intel.com> wrote:
>> >> > @@ -183,6 +187,22 @@ static bool feat_init_done(const struct 
> psr_socket_info *info)
>> >> >      return false;
>> >> >  }
>> >> >  
>> >> > +static enum psr_feat_type psr_cbm_type_to_feat_type(enum cbm_type type)
>> >> > +{
>> >> > +    enum psr_feat_type feat_type;
>> >> > +
>> >> > +    switch ( type )
>> >> > +    {
>> >> > +    case PSR_CBM_TYPE_L3:
>> >> > +        feat_type = PSR_SOCKET_L3_CAT;
>> >> > +        break;
>> >> > +    default:
>> >> > +        ASSERT_UNREACHABLE();
>> >> > +    }
>> >> > +
>> >> > +    return feat_type;
>> >> 
>> >> I'm pretty certain this will (validly) produce an uninitialized variable
>> >> warning at least in a non-debug build. Not how I did say "add
>> >> ASSERT_UNREACHABLE()" in the v9 review.
>> >> 
>> > Do you mean to init feat_type to 'PSR_SOCKET_MAX_FEAT' and then check it
>> > at the end of function using ASSERT?
>> 
>> That's a (less desirable) option, but what I really mean is take v9
>> code and _add_ ASSERT_UNREACHABLE() first thing in the default
>> case.
> 
> DYM we should initialize 'feat_type' to a valid value, e.g. PSR_SOCKET_L3_CAT
> and keep ASSERT_UNREACHABLE() in default case?

Yi, please. Did you read my previous reply, where I think I did say
very precisely what I mean? Why would you pick some random
valid type here?

Jan
Yi Sun April 7, 2017, 5:39 a.m. UTC | #6
On 17-04-06 08:04:16, Jan Beulich wrote:
> >>> On 06.04.17 at 13:16, <yi.y.sun@linux.intel.com> wrote:
> > On 17-04-06 02:36:19, Jan Beulich wrote:
> >> >>> On 06.04.17 at 08:05, <yi.y.sun@linux.intel.com> wrote:
> >> > On 17-04-05 09:37:44, Jan Beulich wrote:
> >> >> >>> On 01.04.17 at 15:53, <yi.y.sun@linux.intel.com> wrote:
> >> >> > @@ -183,6 +187,22 @@ static bool feat_init_done(const struct 
> > psr_socket_info *info)
> >> >> >      return false;
> >> >> >  }
> >> >> >  
> >> >> > +static enum psr_feat_type psr_cbm_type_to_feat_type(enum cbm_type type)
> >> >> > +{
> >> >> > +    enum psr_feat_type feat_type;
> >> >> > +
> >> >> > +    switch ( type )
> >> >> > +    {
> >> >> > +    case PSR_CBM_TYPE_L3:
> >> >> > +        feat_type = PSR_SOCKET_L3_CAT;
> >> >> > +        break;
> >> >> > +    default:
> >> >> > +        ASSERT_UNREACHABLE();
> >> >> > +    }
> >> >> > +
> >> >> > +    return feat_type;
> >> >> 
> >> >> I'm pretty certain this will (validly) produce an uninitialized variable
> >> >> warning at least in a non-debug build. Not how I did say "add
> >> >> ASSERT_UNREACHABLE()" in the v9 review.
> >> >> 
> >> > Do you mean to init feat_type to 'PSR_SOCKET_MAX_FEAT' and then check it
> >> > at the end of function using ASSERT?
> >> 
> >> That's a (less desirable) option, but what I really mean is take v9
> >> code and _add_ ASSERT_UNREACHABLE() first thing in the default
> >> case.
> > 
> > DYM we should initialize 'feat_type' to a valid value, e.g. PSR_SOCKET_L3_CAT
> > and keep ASSERT_UNREACHABLE() in default case?
> 
> Yi, please. Did you read my previous reply, where I think I did say
> very precisely what I mean? Why would you pick some random
> valid type here?
> 
Sorry, I mis-understood your intention before. In v9 codes, I defined
'PSR_SOCKET_UNKNOWN' which is returned in default case. I thought you
wanted me to remove it.

I will add ASSERT_UNREACHABLE() and keep 'feat_type = PSR_SOCKET_UNKNOWN;'
in default case.

BRs,
Sun Yi
diff mbox

Patch

diff --git a/xen/arch/x86/psr.c b/xen/arch/x86/psr.c
index 3421219..36ade48 100644
--- a/xen/arch/x86/psr.c
+++ b/xen/arch/x86/psr.c
@@ -93,6 +93,10 @@  struct feat_node {
         unsigned int cos_num;
         unsigned int cos_max;
         unsigned int cbm_len;
+
+        /* get_feat_info is used to get feature HW info. */
+        bool (*get_feat_info)(const struct feat_node *feat,
+                              uint32_t data[], unsigned int array_len);
     } *props;
 
     uint32_t cos_reg_val[MAX_COS_REG_CNT];
@@ -183,6 +187,22 @@  static bool feat_init_done(const struct psr_socket_info *info)
     return false;
 }
 
+static enum psr_feat_type psr_cbm_type_to_feat_type(enum cbm_type type)
+{
+    enum psr_feat_type feat_type;
+
+    switch ( type )
+    {
+    case PSR_CBM_TYPE_L3:
+        feat_type = PSR_SOCKET_L3_CAT;
+        break;
+    default:
+        ASSERT_UNREACHABLE();
+    }
+
+    return feat_type;
+}
+
 /* CAT common functions implementation. */
 static void cat_init_feature(const struct cpuid_leaf *regs,
                              struct feat_node *feat,
@@ -232,9 +252,23 @@  static void cat_init_feature(const struct cpuid_leaf *regs,
            socket, feat->props->cos_max, feat->props->cbm_len);
 }
 
+static bool cat_get_feat_info(const struct feat_node *feat,
+                              uint32_t data[], unsigned int array_len)
+{
+    if ( array_len != PSR_INFO_ARRAY_SIZE )
+        return false;
+
+    data[PSR_INFO_IDX_COS_MAX] = feat->props->cos_max;
+    data[PSR_INFO_IDX_CAT_CBM_LEN] = feat->props->cbm_len;
+    data[PSR_INFO_IDX_CAT_FLAG] = 0;
+
+    return true;
+}
+
 /* L3 CAT ops */
 static struct feat_props l3_cat_props = {
     .cos_num = 1,
+    .get_feat_info = cat_get_feat_info,
 };
 
 static void __init parse_psr_bool(char *s, char *value, char *feature,
@@ -446,10 +480,45 @@  void psr_ctxt_switch_to(struct domain *d)
     }
 }
 
-int psr_get_cat_l3_info(unsigned int socket, uint32_t *cbm_len,
-                        uint32_t *cos_max, uint32_t *flags)
+static struct psr_socket_info *get_socket_info(unsigned int socket)
 {
-    return 0;
+    if ( !socket_info )
+        return ERR_PTR(-ENODEV);
+
+    if ( socket >= nr_sockets )
+        return ERR_PTR(-ERANGE);
+
+    if ( !feat_init_done(socket_info + socket) )
+        return ERR_PTR(-ENOENT);
+
+    return socket_info + socket;
+}
+
+int psr_get_info(unsigned int socket, enum cbm_type type,
+                 uint32_t data[], unsigned int array_len)
+{
+    const struct psr_socket_info *info = get_socket_info(socket);
+    const struct feat_node *feat;
+    enum psr_feat_type feat_type;
+
+    if ( IS_ERR(info) )
+        return PTR_ERR(info);
+
+    if ( !data )
+        return -EINVAL;
+
+    feat_type = psr_cbm_type_to_feat_type(type);
+    if ( feat_type > ARRAY_SIZE(info->features) )
+        return -ENOENT;
+
+    feat = info->features[feat_type];
+    if ( !feat )
+        return -ENOENT;
+
+    if ( feat->props->get_feat_info(feat, data, array_len) )
+        return 0;
+
+    return -EINVAL;
 }
 
 int psr_get_l3_cbm(struct domain *d, unsigned int socket,
diff --git a/xen/arch/x86/sysctl.c b/xen/arch/x86/sysctl.c
index 2f7056e..c23270d 100644
--- a/xen/arch/x86/sysctl.c
+++ b/xen/arch/x86/sysctl.c
@@ -175,14 +175,25 @@  long arch_do_sysctl(
         switch ( sysctl->u.psr_cat_op.cmd )
         {
         case XEN_SYSCTL_PSR_CAT_get_l3_info:
-            ret = psr_get_cat_l3_info(sysctl->u.psr_cat_op.target,
-                                      &sysctl->u.psr_cat_op.u.l3_info.cbm_len,
-                                      &sysctl->u.psr_cat_op.u.l3_info.cos_max,
-                                      &sysctl->u.psr_cat_op.u.l3_info.flags);
+        {
+            uint32_t data[PSR_INFO_ARRAY_SIZE];
+
+            ret = psr_get_info(sysctl->u.psr_cat_op.target,
+                               PSR_CBM_TYPE_L3, data, ARRAY_SIZE(data));
+            if ( ret )
+                break;
+
+            sysctl->u.psr_cat_op.u.l3_info.cos_max =
+                                      data[PSR_INFO_IDX_COS_MAX];
+            sysctl->u.psr_cat_op.u.l3_info.cbm_len =
+                                      data[PSR_INFO_IDX_CAT_CBM_LEN];
+            sysctl->u.psr_cat_op.u.l3_info.flags =
+                                      data[PSR_INFO_IDX_CAT_FLAG];
 
             if ( !ret && __copy_field_to_guest(u_sysctl, sysctl, u.psr_cat_op) )
                 ret = -EFAULT;
             break;
+        }
 
         default:
             ret = -EOPNOTSUPP;
diff --git a/xen/include/asm-x86/psr.h b/xen/include/asm-x86/psr.h
index 57f47e9..af3a465 100644
--- a/xen/include/asm-x86/psr.h
+++ b/xen/include/asm-x86/psr.h
@@ -19,20 +19,26 @@ 
 #include <xen/types.h>
 
 /* CAT cpuid level */
-#define PSR_CPUID_LEVEL_CAT   0x10
+#define PSR_CPUID_LEVEL_CAT             0x10
 
 /* Resource Type Enumeration */
 #define PSR_RESOURCE_TYPE_L3            0x2
 
 /* L3 Monitoring Features */
-#define PSR_CMT_L3_OCCUPANCY           0x1
+#define PSR_CMT_L3_OCCUPANCY            0x1
 
 /* CDP Capability */
-#define PSR_CAT_CDP_CAPABILITY       (1u << 2)
+#define PSR_CAT_CDP_CAPABILITY          (1u << 2)
 
 /* L3 CDP Enable bit*/
 #define PSR_L3_QOS_CDP_ENABLE_BIT       0x0
 
+/* Used by psr_get_info() */
+#define PSR_INFO_IDX_COS_MAX            0
+#define PSR_INFO_IDX_CAT_CBM_LEN        1
+#define PSR_INFO_IDX_CAT_FLAG           2
+#define PSR_INFO_ARRAY_SIZE             3
+
 struct psr_cmt_l3 {
     unsigned int features;
     unsigned int upscaling_factor;
@@ -63,8 +69,8 @@  int psr_alloc_rmid(struct domain *d);
 void psr_free_rmid(struct domain *d);
 void psr_ctxt_switch_to(struct domain *d);
 
-int psr_get_cat_l3_info(unsigned int socket, uint32_t *cbm_len,
-                        uint32_t *cos_max, uint32_t *flags);
+int psr_get_info(unsigned int socket, enum cbm_type type,
+                 uint32_t data[], unsigned int array_len);
 int psr_get_l3_cbm(struct domain *d, unsigned int socket,
                    uint64_t *cbm, enum cbm_type type);
 int psr_set_l3_cbm(struct domain *d, unsigned int socket,