diff mbox

[2/3] x86: add support for L2 CAT in hypervisor.

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

Commit Message

Yi Sun Aug. 25, 2016, 5:22 a.m. UTC
Add L2 CAT (Cache Allocation Technology) feature support in
hypervisor:
- Implement 'struct feat_ops' callback functions for L2 CAT
  and initialize L2 CAT feature and add it into feature list.
- Add new sysctl to get L2 CAT information.
- Add new domctl to set/get L2 CAT CBM.

Signed-off-by: He Chen <he.chen@linux.intel.com>
Signed-off-by: Yi Sun <yi.y.sun@linux.intel.com>
---
 xen/arch/x86/domctl.c           |  13 +++
 xen/arch/x86/psr.c              | 226 +++++++++++++++++++++++++++++++++++++++-
 xen/arch/x86/sysctl.c           |  16 ++-
 xen/include/asm-x86/msr-index.h |   1 +
 xen/include/asm-x86/psr.h       |   2 +
 xen/include/public/domctl.h     |   2 +
 xen/include/public/sysctl.h     |   3 +-
 7 files changed, 258 insertions(+), 5 deletions(-)

Comments

Jan Beulich Sept. 6, 2016, 7:43 a.m. UTC | #1
>>> On 25.08.16 at 07:22, <yi.y.sun@linux.intel.com> wrote:

Please extend the comments given for patch 1 to this one. Just one
extra thing:

> @@ -743,7 +744,7 @@ struct xen_sysctl_psr_cat_op {
>              uint32_t cos_max;   /* OUT: Maximum COS */
>  #define XEN_SYSCTL_PSR_CAT_L3_CDP       (1u << 0)
>              uint32_t flags;     /* OUT: CAT flags */
> -        } l3_info;
> +        } info;

Such an adjustment breaks the tools build, i.e. can't come without
also minimally adjusting libxc.

Jan
Yi Sun Sept. 7, 2016, 7:13 a.m. UTC | #2
On 16-09-06 01:43:22, Jan Beulich wrote:
> >>> On 25.08.16 at 07:22, <yi.y.sun@linux.intel.com> wrote:
> 
> Please extend the comments given for patch 1 to this one. Just one
> extra thing:
> 
> > @@ -743,7 +744,7 @@ struct xen_sysctl_psr_cat_op {
> >              uint32_t cos_max;   /* OUT: Maximum COS */
> >  #define XEN_SYSCTL_PSR_CAT_L3_CDP       (1u << 0)
> >              uint32_t flags;     /* OUT: CAT flags */
> > -        } l3_info;
> > +        } info;
> 
> Such an adjustment breaks the tools build, i.e. can't come without
> also minimally adjusting libxc.
> 
> Jan
I thought 4.8 will also make tools version upgrade but not considered
to be compatible with old tools. Sorry for that.

Considering the compatibility and to support future feature, I want to
add a general structure in union, like below. How do you think? Thanks!

    union {
        struct {
            uint32_t cbm_len;   /* OUT: CBM length */
            uint32_t cos_max;   /* OUT: Maximum COS */
#define XEN_SYSCTL_PSR_CAT_L3_CDP       (1u << 0)
            uint32_t flags;     /* OUT: CAT flags */
        } l3_info;

        struct {
            uint32_t cbm_len;
            uint32_t cos_max;
            uint32_t data;     /* Specific data of feature */
        } psr_info;
    } u;
Jan Beulich Sept. 7, 2016, 9:03 a.m. UTC | #3
>>> On 07.09.16 at 09:13, <yi.y.sun@linux.intel.com> wrote:
> On 16-09-06 01:43:22, Jan Beulich wrote:
>> >>> On 25.08.16 at 07:22, <yi.y.sun@linux.intel.com> wrote:
>> 
>> Please extend the comments given for patch 1 to this one. Just one
>> extra thing:
>> 
>> > @@ -743,7 +744,7 @@ struct xen_sysctl_psr_cat_op {
>> >              uint32_t cos_max;   /* OUT: Maximum COS */
>> >  #define XEN_SYSCTL_PSR_CAT_L3_CDP       (1u << 0)
>> >              uint32_t flags;     /* OUT: CAT flags */
>> > -        } l3_info;
>> > +        } info;
>> 
>> Such an adjustment breaks the tools build, i.e. can't come without
>> also minimally adjusting libxc.
>> 
>> Jan
> I thought 4.8 will also make tools version upgrade but not considered
> to be compatible with old tools. Sorry for that.
> 
> Considering the compatibility and to support future feature, I want to
> add a general structure in union, like below. How do you think? Thanks!

No, you don't need to be compatible with old tools. But you need to
avoid build breakage between patches 2 and 3. Please always
remember that (a) patch series may not get applied in one go and
(b) even if they do any intermediate build breakage will hinder
bisection attempts.

Jan
Yi Sun Sept. 8, 2016, 7:30 a.m. UTC | #4
On 16-09-07 03:03:12, Jan Beulich wrote:
> >>> On 07.09.16 at 09:13, <yi.y.sun@linux.intel.com> wrote:
> > On 16-09-06 01:43:22, Jan Beulich wrote:
> >> >>> On 25.08.16 at 07:22, <yi.y.sun@linux.intel.com> wrote:
> >> 
> >> Please extend the comments given for patch 1 to this one. Just one
> >> extra thing:
> >> 
> >> > @@ -743,7 +744,7 @@ struct xen_sysctl_psr_cat_op {
> >> >              uint32_t cos_max;   /* OUT: Maximum COS */
> >> >  #define XEN_SYSCTL_PSR_CAT_L3_CDP       (1u << 0)
> >> >              uint32_t flags;     /* OUT: CAT flags */
> >> > -        } l3_info;
> >> > +        } info;
> >> 
> >> Such an adjustment breaks the tools build, i.e. can't come without
> >> also minimally adjusting libxc.
> >> 
> >> Jan
> > I thought 4.8 will also make tools version upgrade but not considered
> > to be compatible with old tools. Sorry for that.
> > 
> > Considering the compatibility and to support future feature, I want to
> > add a general structure in union, like below. How do you think? Thanks!
> 
> No, you don't need to be compatible with old tools. But you need to
> avoid build breakage between patches 2 and 3. Please always
> remember that (a) patch series may not get applied in one go and
> (b) even if they do any intermediate build breakage will hinder
> bisection attempts.
> 
> Jan

Got it. Thanks a lot for your explanation!
diff mbox

Patch

diff --git a/xen/arch/x86/domctl.c b/xen/arch/x86/domctl.c
index a51ed2c..604d202 100644
--- a/xen/arch/x86/domctl.c
+++ b/xen/arch/x86/domctl.c
@@ -1396,6 +1396,19 @@  long arch_do_domctl(
             copyback = 1;
             break;
 
+        case XEN_DOMCTL_PSR_CAT_OP_SET_L2_CBM:
+            ret = psr_set_val(d, domctl->u.psr_cat_op.target,
+                              domctl->u.psr_cat_op.data,
+                              PSR_MASK_TYPE_L2_CBM);
+            break;
+
+        case XEN_DOMCTL_PSR_CAT_OP_GET_L2_CBM:
+            ret = psr_get_val(d, domctl->u.psr_cat_op.target,
+                              &domctl->u.psr_cat_op.data,
+                              PSR_MASK_TYPE_L2_CBM);
+            copyback = 1;
+            break;
+
         default:
             ret = -EOPNOTSUPP;
             break;
diff --git a/xen/arch/x86/psr.c b/xen/arch/x86/psr.c
index a77b55a..a23d3c9 100644
--- a/xen/arch/x86/psr.c
+++ b/xen/arch/x86/psr.c
@@ -123,6 +123,7 @@  struct psr_ref {
 
 #define PSR_SOCKET_L3_CAT 0
 #define PSR_SOCKET_L3_CDP 1
+#define PSR_SOCKET_L2_CAT 2
 
 struct psr_socket_alloc_info {
     /*
@@ -153,6 +154,7 @@  static DEFINE_PER_CPU(struct psr_assoc, psr_assoc);
 static struct psr_ref *temp_cos_ref;
 /* Every feature has its own object. */
 struct feat_list *pL3CAT;
+struct feat_list *pL2CAT;
 
 /* Common functions for supporting feature callback functions. */
 static void add_feature(struct feat_list *pHead, struct feat_list *pTmp)
@@ -215,12 +217,215 @@  static bool_t psr_check_cbm(unsigned int cbm_len, uint64_t cbm)
  * Features specific implementations.
  */
 
-/* CAT/CDP data structure and callback functions implementation. */
+/* CAT/CDP data structure definition. */
 struct psr_cat_lvl_info {
     unsigned int cbm_len;
     unsigned int cos_max;
 };
 
+/* L2 CAT callback functions implementation. */
+static void l2_cat_init_feature(unsigned int eax, unsigned int ebx,
+                                unsigned int ecx, unsigned int edx,
+                                struct feat_list *pFeat,
+                                struct psr_socket_alloc_info *info)
+{
+    struct psr_cat_lvl_info l2_cat;
+    unsigned int socket;
+
+    if ( MAX_FEAT_INFO_SIZE < sizeof(struct psr_cat_lvl_info) )
+        return;
+
+    /* No valid value so do not enable feature. */
+    if ( 0 == eax || 0 == edx )
+        return;
+
+    l2_cat.cbm_len = (eax & 0x1f) + 1;
+    l2_cat.cos_max = min(opt_cos_max, edx & 0xffff);
+
+    /* cos=0 is reserved as default cbm(all ones). */
+    pFeat->cos_reg_val[0] = (1ull << l2_cat.cbm_len) - 1;
+
+    pFeat->feature = PSR_SOCKET_L2_CAT;
+    set_bit(PSR_SOCKET_L2_CAT, &(info->features));
+
+    memcpy(pFeat->feat_info, &l2_cat, sizeof(struct psr_cat_lvl_info));
+
+    info->nr_feat++;
+
+    /* Add this feature into list. */
+    add_feature(info->pFeat, pFeat);
+
+    socket = cpu_to_socket(smp_processor_id());
+    printk(XENLOG_INFO "L2 CAT: enabled on socket %u, cos_max:%u, cbm_len:%u.\n",
+           socket, pFeat->feat_info[1], pFeat->feat_info[0]);
+}
+
+static int l2_cat_compare_mask(uint64_t *mask, struct feat_list *pFeat,
+                               unsigned int cos, bool_t *found)
+{
+    struct psr_cat_lvl_info cat_info;
+    uint64_t l2_def_cbm;
+
+    memcpy(&cat_info, pFeat->feat_info, sizeof(struct psr_cat_lvl_info));
+    l2_def_cbm = (1ull << cat_info.cbm_len) - 1;
+
+    /* L2 CAT */
+    if ( cos > cat_info.cos_max )
+    {
+        if ( mask[0] != l2_def_cbm )
+        {
+            printk(XENLOG_ERR "L2 CAT exceed cos max.\n");
+            *found = 0;
+            return -ENOENT;
+        }
+        *found = 1;
+        return 1;
+    }
+
+    if ( mask[0] == pFeat->cos_reg_val[cos] )
+        *found = 1;
+    else
+        *found = 0;
+
+    return 1;
+}
+
+static unsigned int l2_cat_get_cos_max_as_type(struct feat_list *pFeat,
+                                               enum mask_type type)
+{
+    struct psr_cat_lvl_info cat_info;
+
+    if ( type != PSR_MASK_TYPE_L2_CBM )
+        return 0;
+
+    memcpy(&cat_info, pFeat->feat_info, sizeof(struct psr_cat_lvl_info));
+    return cat_info.cos_max;
+}
+
+static unsigned int l2_cat_exceed_range(uint64_t *mask, struct feat_list *pFeat,
+                                        unsigned int cos)
+{
+    struct psr_cat_lvl_info cat_info;
+    uint64_t l2_def_cbm;
+
+    memcpy(&cat_info, pFeat->feat_info, sizeof(struct psr_cat_lvl_info));
+    l2_def_cbm = (1ull << cat_info.cbm_len) - 1;
+
+    /* L2 CAT */
+    if ( cos > cat_info.cos_max )
+        if ( mask[0] != l2_def_cbm )
+            /*
+             * Exceed cos_max and value to set is not default,
+             * return error.
+             */
+            return 0;
+
+    return 1;
+}
+
+static int l2_cat_write_msr(unsigned int cos, uint64_t *mask,
+                            struct feat_list *pFeat)
+{
+    struct psr_cat_lvl_info cat_info;
+
+    memcpy(&cat_info, pFeat->feat_info, sizeof(struct psr_cat_lvl_info));
+
+    /* L2 CAT */
+    if ( cos > cat_info.cos_max )
+        return 1;
+
+    pFeat->cos_reg_val[cos] = mask[0];
+    wrmsrl(MSR_IA32_PSR_L2_MASK(cos), mask[0]);
+    return 1;
+}
+
+static int l2_cat_get_old_set_new(uint64_t *mask,
+                                  struct feat_list *pFeat,
+                                  unsigned int old_cos,
+                                  enum mask_type type,
+                                  uint64_t m)
+{
+    struct psr_cat_lvl_info cat_info;
+
+    memcpy(&cat_info, pFeat->feat_info, sizeof(struct psr_cat_lvl_info));
+
+    /* No matter the type, we should return L2 CAT mask. */
+    if ( type == PSR_MASK_TYPE_L2_CBM )
+        if ( !psr_check_cbm(cat_info.cbm_len, m) )
+            return -EINVAL;
+
+    /* L2 CAT */
+    if ( old_cos > cat_info.cos_max )
+        mask[0] =  pFeat->cos_reg_val[0];
+    else
+        mask[0] =  pFeat->cos_reg_val[old_cos];
+
+    if ( type == PSR_MASK_TYPE_L2_CBM )
+        mask[0] = m;
+
+    /* Return number of masks to be handled. */
+    return 1;
+}
+
+static int l2_cat_get_val(struct feat_list *pFeat, unsigned int cos,
+                          enum mask_type type, uint64_t *val)
+{
+    struct psr_cat_lvl_info cat_info;
+
+    if ( type != PSR_MASK_TYPE_L2_CBM )
+         return 0;
+
+    memcpy(&cat_info, pFeat->feat_info, sizeof(struct psr_cat_lvl_info));
+
+    /* L2 CAT */
+    if ( cos > cat_info.cos_max )
+        *val =  pFeat->cos_reg_val[0];
+    else
+        *val =  pFeat->cos_reg_val[cos];
+
+    return 1;
+}
+
+static int l2_cat_get_feat_info(struct feat_list *pFeat, enum mask_type type,
+                                uint32_t *dat0, uint32_t *dat1,
+                                uint32_t *dat2)
+{
+    struct psr_cat_lvl_info cat_info;
+
+    if ( type != PSR_MASK_TYPE_L2_CBM )
+        return 0;
+
+    memcpy(&cat_info, pFeat->feat_info, sizeof(struct psr_cat_lvl_info));
+
+    *dat0 = cat_info.cbm_len;
+    *dat1 = cat_info.cos_max;
+    *dat2 = 0;
+
+    return 1;
+}
+
+static unsigned int l2_cat_get_max_cos_max(struct feat_list *pFeat)
+{
+    struct psr_cat_lvl_info cat_info;
+
+    memcpy(&cat_info, pFeat->feat_info, sizeof(struct psr_cat_lvl_info));
+
+    return cat_info.cos_max;
+}
+
+struct feat_ops l2_cat_ops = {
+    .init_feature = l2_cat_init_feature,
+    .get_old_set_new = l2_cat_get_old_set_new,
+    .compare_mask = l2_cat_compare_mask,
+    .get_cos_max_as_type = l2_cat_get_cos_max_as_type,
+    .exceed_range = l2_cat_exceed_range,
+    .write_msr = l2_cat_write_msr,
+    .get_val = l2_cat_get_val,
+    .get_feat_info = l2_cat_get_feat_info,
+    .get_max_cos_max = l2_cat_get_max_cos_max,
+};
+
+/* L3 CAT/CDP callback functions implementation. */
 static void l3_cat_init_feature(unsigned int eax, unsigned int ebx,
                                 unsigned int ecx, unsigned int edx,
                                 struct feat_list *pFeat,
@@ -1207,9 +1412,14 @@  static int internal_cpu_prepare(unsigned int cpu)
          (pL3CAT = xzalloc(struct feat_list)) == NULL )
         return -ENOMEM;
 
+    if ( pL2CAT == NULL &&
+         (pL2CAT = xzalloc(struct feat_list)) == NULL )
+        return -ENOMEM;
+
     return 0;
 }
 
+/* Every feature should be handled here. */
 static void internal_cpu_init(void)
 {
     unsigned int eax, ebx, ecx, edx;
@@ -1240,6 +1450,20 @@  static void internal_cpu_init(void)
         pTmp->ops = l3_cat_ops;
         pTmp->ops.init_feature(eax, ebx, ecx, edx, pTmp, info);
     }
+
+    cpuid_count(PSR_CPUID_LEVEL_CAT, 0, &eax, &ebx, &ecx, &edx);
+    if ( ebx & PSR_RESOURCE_TYPE_L2 )
+    {
+        pTmp = pL2CAT;
+        if ( !pTmp )
+            return;
+        pL2CAT = NULL;
+
+        /* Initialize L2 CAT according to CPUID. */
+        cpuid_count(PSR_CPUID_LEVEL_CAT, 2, &eax, &ebx, &ecx, &edx);
+        pTmp->ops = l2_cat_ops;
+        pTmp->ops.init_feature(eax, ebx, ecx, edx, pTmp, info);
+    }
 }
 
 static void internal_cpu_fini(unsigned int cpu)
diff --git a/xen/arch/x86/sysctl.c b/xen/arch/x86/sysctl.c
index a143e7a..3a1d80b 100644
--- a/xen/arch/x86/sysctl.c
+++ b/xen/arch/x86/sysctl.c
@@ -178,14 +178,24 @@  long arch_do_sysctl(
         case XEN_SYSCTL_PSR_CAT_get_l3_info:
             ret = psr_get_info(sysctl->u.psr_cat_op.target,
                                PSR_MASK_TYPE_L3_CBM,
-                               &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);
+                               &sysctl->u.psr_cat_op.u.info.cbm_len,
+                               &sysctl->u.psr_cat_op.u.info.cos_max,
+                               &sysctl->u.psr_cat_op.u.info.flags);
 
             if ( !ret && __copy_field_to_guest(u_sysctl, sysctl, u.psr_cat_op) )
                 ret = -EFAULT;
             break;
 
+        case XEN_SYSCTL_PSR_CAT_get_l2_info:
+            ret = psr_get_info(sysctl->u.psr_cat_op.target,
+                               PSR_MASK_TYPE_L2_CBM,
+                               &sysctl->u.psr_cat_op.u.info.cbm_len,
+                               &sysctl->u.psr_cat_op.u.info.cos_max,
+                               &sysctl->u.psr_cat_op.u.info.flags);
+            if ( !ret && __copy_field_to_guest(u_sysctl, sysctl, u.psr_cat_op) )
+                ret = -EFAULT;
+            break;
+
         default:
             ret = -EOPNOTSUPP;
             break;
diff --git a/xen/include/asm-x86/msr-index.h b/xen/include/asm-x86/msr-index.h
index 1095c81..e276f8a 100644
--- a/xen/include/asm-x86/msr-index.h
+++ b/xen/include/asm-x86/msr-index.h
@@ -339,6 +339,7 @@ 
 #define MSR_IA32_PSR_L3_MASK(n)	(0x00000c90 + (n))
 #define MSR_IA32_PSR_L3_MASK_CODE(n)	(0x00000c90 + (n) * 2 + 1)
 #define MSR_IA32_PSR_L3_MASK_DATA(n)	(0x00000c90 + (n) * 2)
+#define MSR_IA32_PSR_L2_MASK(n)		(0x00000d10 + (n))
 
 /* Intel Model 6 */
 #define MSR_P6_PERFCTR(n)		(0x000000c1 + (n))
diff --git a/xen/include/asm-x86/psr.h b/xen/include/asm-x86/psr.h
index 0993863..de9a5b5 100644
--- a/xen/include/asm-x86/psr.h
+++ b/xen/include/asm-x86/psr.h
@@ -23,6 +23,7 @@ 
 
 /* Resource Type Enumeration */
 #define PSR_RESOURCE_TYPE_L3            0x2
+#define PSR_RESOURCE_TYPE_L2            0x4
 
 /* L3 Monitoring Features */
 #define PSR_CMT_L3_OCCUPANCY           0x1
@@ -50,6 +51,7 @@  enum mask_type {
     PSR_MASK_TYPE_L3_CBM,
     PSR_MASK_TYPE_L3_CODE,
     PSR_MASK_TYPE_L3_DATA,
+    PSR_MASK_TYPE_L2_CBM,
 };
 
 extern struct psr_cmt *psr_cmt;
diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h
index ddd3de4..8a30299 100644
--- a/xen/include/public/domctl.h
+++ b/xen/include/public/domctl.h
@@ -1136,6 +1136,8 @@  struct xen_domctl_psr_cat_op {
 #define XEN_DOMCTL_PSR_CAT_OP_SET_L3_DATA    3
 #define XEN_DOMCTL_PSR_CAT_OP_GET_L3_CODE    4
 #define XEN_DOMCTL_PSR_CAT_OP_GET_L3_DATA    5
+#define XEN_DOMCTL_PSR_CAT_OP_SET_L2_CBM     6
+#define XEN_DOMCTL_PSR_CAT_OP_GET_L2_CBM     7
     uint32_t cmd;       /* IN: XEN_DOMCTL_PSR_CAT_OP_* */
     uint32_t target;    /* IN */
     uint64_t data;      /* IN/OUT */
diff --git a/xen/include/public/sysctl.h b/xen/include/public/sysctl.h
index 8197c14..e2542fa 100644
--- a/xen/include/public/sysctl.h
+++ b/xen/include/public/sysctl.h
@@ -734,6 +734,7 @@  typedef struct xen_sysctl_pcitopoinfo xen_sysctl_pcitopoinfo_t;
 DEFINE_XEN_GUEST_HANDLE(xen_sysctl_pcitopoinfo_t);
 
 #define XEN_SYSCTL_PSR_CAT_get_l3_info               0
+#define XEN_SYSCTL_PSR_CAT_get_l2_info               1
 struct xen_sysctl_psr_cat_op {
     uint32_t cmd;       /* IN: XEN_SYSCTL_PSR_CAT_* */
     uint32_t target;    /* IN */
@@ -743,7 +744,7 @@  struct xen_sysctl_psr_cat_op {
             uint32_t cos_max;   /* OUT: Maximum COS */
 #define XEN_SYSCTL_PSR_CAT_L3_CDP       (1u << 0)
             uint32_t flags;     /* OUT: CAT flags */
-        } l3_info;
+        } info;
     } u;
 };
 typedef struct xen_sysctl_psr_cat_op xen_sysctl_psr_cat_op_t;