diff --git a/xen/arch/x86/domctl.c b/xen/arch/x86/domctl.c
index 2a2fe04..c53d819 100644
--- a/xen/arch/x86/domctl.c
+++ b/xen/arch/x86/domctl.c
@@ -1386,41 +1386,41 @@ long arch_do_domctl(
         switch ( domctl->u.psr_cat_op.cmd )
         {
         case XEN_DOMCTL_PSR_CAT_OP_SET_L3_CBM:
-            ret = psr_set_l3_cbm(d, domctl->u.psr_cat_op.target,
-                                 domctl->u.psr_cat_op.data,
-                                 PSR_CBM_TYPE_L3);
+            ret = psr_set_val(d, domctl->u.psr_cat_op.target,
+                              domctl->u.psr_cat_op.data,
+                              PSR_MASK_TYPE_L3_CBM);
             break;
 
         case XEN_DOMCTL_PSR_CAT_OP_SET_L3_CODE:
-            ret = psr_set_l3_cbm(d, domctl->u.psr_cat_op.target,
-                                 domctl->u.psr_cat_op.data,
-                                 PSR_CBM_TYPE_L3_CODE);
+            ret = psr_set_val(d, domctl->u.psr_cat_op.target,
+                              domctl->u.psr_cat_op.data,
+                              PSR_MASK_TYPE_L3_CODE);
             break;
 
         case XEN_DOMCTL_PSR_CAT_OP_SET_L3_DATA:
-            ret = psr_set_l3_cbm(d, domctl->u.psr_cat_op.target,
-                                 domctl->u.psr_cat_op.data,
-                                 PSR_CBM_TYPE_L3_DATA);
+            ret = psr_set_val(d, domctl->u.psr_cat_op.target,
+                              domctl->u.psr_cat_op.data,
+                              PSR_MASK_TYPE_L3_DATA);
             break;
 
         case XEN_DOMCTL_PSR_CAT_OP_GET_L3_CBM:
-            ret = psr_get_l3_cbm(d, domctl->u.psr_cat_op.target,
-                                 &domctl->u.psr_cat_op.data,
-                                 PSR_CBM_TYPE_L3);
+            ret = psr_get_val(d, domctl->u.psr_cat_op.target,
+                              &domctl->u.psr_cat_op.data,
+                              PSR_MASK_TYPE_L3_CBM);
             copyback = 1;
             break;
 
         case XEN_DOMCTL_PSR_CAT_OP_GET_L3_CODE:
-            ret = psr_get_l3_cbm(d, domctl->u.psr_cat_op.target,
-                                 &domctl->u.psr_cat_op.data,
-                                 PSR_CBM_TYPE_L3_CODE);
+            ret = psr_get_val(d, domctl->u.psr_cat_op.target,
+                              &domctl->u.psr_cat_op.data,
+                              PSR_MASK_TYPE_L3_CODE);
             copyback = 1;
             break;
 
         case XEN_DOMCTL_PSR_CAT_OP_GET_L3_DATA:
-            ret = psr_get_l3_cbm(d, domctl->u.psr_cat_op.target,
-                                 &domctl->u.psr_cat_op.data,
-                                 PSR_CBM_TYPE_L3_DATA);
+            ret = psr_get_val(d, domctl->u.psr_cat_op.target,
+                              &domctl->u.psr_cat_op.data,
+                              PSR_MASK_TYPE_L3_DATA);
             copyback = 1;
             break;
 
diff --git a/xen/arch/x86/psr.c b/xen/arch/x86/psr.c
index 0b5073c..99e4c78 100644
--- a/xen/arch/x86/psr.c
+++ b/xen/arch/x86/psr.c
@@ -17,28 +17,159 @@
 #include <xen/cpu.h>
 #include <xen/err.h>
 #include <xen/sched.h>
+#include <xen/list.h>
 #include <asm/psr.h>
 
 #define PSR_CMT        (1<<0)
 #define PSR_CAT        (1<<1)
 #define PSR_CDP        (1<<2)
 
-struct psr_cat_cbm {
+/*
+ * To add a new PSR feature, please follow below steps:
+ * 1. Implement feature specific callback functions listed in
+ *    "struct feat_ops";
+ * 2. Implement a feature specific "struct feat_ops" object and register
+ *    feature specific callback functions into it;
+ * 3. Delcare feat_list object for the feature and malloc memory for it
+ *    in cpu_prepare_work(). Correspondingly, free them in
+ *    free_feature();
+ * 4. Add feature initialization codes in cpu_init_work().
+ */
+
+struct feat_list;
+struct psr_socket_info;
+
+/* Every feature enabled should implement such ops and callback functions. */
+struct feat_ops {
+    /*
+     * init_feature is used in cpu initialization process to do feature
+     * specific initialization works.
+     */
+    void (*init_feature)(unsigned int eax, unsigned int ebx,
+                         unsigned int ecx, unsigned int edx,
+                         struct feat_list *feat,
+                         struct psr_socket_info *info);
+    /*
+     * get_cos_num is used to get the COS registers number occupied by the
+     * feature for one setting, like CDP occupies 2 COSs but CAT occupies 1.
+     */
+    unsigned int (*get_cos_num)(const struct feat_list *feat);
+    /*
+     * get_old_val and set_new_val are a pair of functions called together.
+     * The caller will traverse all features in list to and call both functions
+     * for every feature do below two things:
+     * 1. get old_cos register value of all supported features and
+     * 2. set the new value for appointed feature.
+     *
+     * All the values are set into value array according the traversal order,
+     * meaning the same order of feature list members.
+     *
+     * The return value of the function means the number of the value array
+     * member to skip or error.
+     * 1 - one item in value array.
+     * 2 - two items in value array, like CDP occupies two items.
+     * negative - error.
+     */
+    int (*get_old_val)(uint64_t val[],
+                       const struct feat_list *feat,
+                       unsigned int old_cos,
+                       enum psr_val_type type);
+    int (*set_new_val)(uint64_t val[],
+                       const struct feat_list *feat,
+                       unsigned int old_cos,
+                       enum psr_val_type type,
+                       uint64_t m);
+    /*
+     * compare_val is used to in set value process to compare if the
+     * input value array can match all the features' COS registers values
+     * according to input cos id.
+     *
+     * The return value of the function means the number of the value array
+     * member to skip or error.
+     * 1 - one item in value array.
+     * 2 - two items in value array, like CDP occupies two items.
+     * negative - error.
+     */
+    int (*compare_val)(const uint64_t val[], const struct feat_list *feat,
+                        unsigned int cos, bool *found);
+    /*
+     * get_cos_max_from_type is used to get the cos_max value of the feature
+     * according to input psr_val_type.
+     */
+    unsigned int (*get_cos_max_from_type)(const struct feat_list *feat,
+                                          enum psr_val_type type);
+    /*
+     * exceeds_cos_max is used to check if the input cos id exceeds the
+     * feature's cos_max and if the input value is not the default one.
+     * Even if the associated cos exceeds the cos_max, HW can work as default
+     * value. That is the reason we need check if input value is default one.
+     * If both criteria are fulfilled, that means the input exceeds the
+     * range.
+     *
+     * The return value of the function means the number of the value array
+     * member to skip or error.
+     * 1 - one item in value array.
+     * 2 - two items in value array, like CDP occupies two items.
+     * 0 - error, exceed cos_max and value to set is not default.
+     */
+    unsigned int (*exceeds_cos_max)(const uint64_t val[],
+                                    const struct feat_list *feat,
+                                    unsigned int cos);
+    /* write_msr is used to write feature specific MSR registers. */
+    int (*write_msr)(unsigned int cos, const uint64_t val[],
+                     struct feat_list *feat);
+    /* get_val is used to get feature specific COS register value. */
+    int (*get_val)(const struct feat_list *feat, unsigned int cos,
+                   enum psr_val_type type, uint64_t *val);
+    /* get_feat_info is used to get feature specific HW info. */
+    int (*get_feat_info)(const struct feat_list *feat, enum psr_val_type type,
+                         uint32_t dat[], uint32_t array_len);
+    /* get_max_cos_max is used to get feature's cos_max. */
+    unsigned int (*get_max_cos_max)(const struct feat_list *feat);
+};
+
+/* CAT/CDP info data structure. */
+struct psr_cat_lvl_info {
+    unsigned int cbm_len;
+    unsigned int cos_max;
+};
+
+struct feat_info {
     union {
-        uint64_t cbm;
-        struct {
-            uint64_t code;
-            uint64_t data;
-        };
+        struct psr_cat_lvl_info l3_info;
     };
+};
+
+/*
+ * Per spec, the maximum COS register number is 128 for all current PSR
+ * features.
+ */
+#define MAX_COS_REG_NUM  128
+
+struct feat_list {
+    unsigned int feature;
+    struct feat_ops ops;
+    struct feat_info info;
+    uint64_t cos_reg_val[MAX_COS_REG_NUM];
+    struct list_head list;
+};
+
+struct psr_ref {
     unsigned int ref;
 };
 
-struct psr_cat_socket_info {
-    unsigned int cbm_len;
-    unsigned int cos_max;
-    struct psr_cat_cbm *cos_to_cbm;
-    spinlock_t cbm_lock;
+#define PSR_SOCKET_L3_CAT 0
+#define PSR_SOCKET_L3_CDP 1
+
+struct psr_socket_info {
+    /*
+     * bit 1~0: [01]->L3 CAT-only, [10]->L3 CDP
+     */
+    unsigned int features;
+    unsigned int nr_feat;
+    struct list_head feat_list;
+    struct psr_ref *cos_ref;
+    spinlock_t mask_lock;
 };
 
 struct psr_assoc {
@@ -48,9 +179,7 @@ struct psr_assoc {
 
 struct psr_cmt *__read_mostly psr_cmt;
 
-static unsigned long *__read_mostly cat_socket_enable;
-static struct psr_cat_socket_info *__read_mostly cat_socket_info;
-static unsigned long *__read_mostly cdp_socket_enable;
+static struct psr_socket_info *__read_mostly socket_info;
 
 static unsigned int opt_psr;
 static unsigned int __initdata opt_rmid_max = 255;
@@ -58,8 +187,410 @@ static unsigned int __read_mostly opt_cos_max = 255;
 static uint64_t rmid_mask;
 static DEFINE_PER_CPU(struct psr_assoc, psr_assoc);
 
-static struct psr_cat_cbm *temp_cos_to_cbm;
+static struct psr_ref *temp_cos_ref;
+/* Every feature has its own object. */
+static struct feat_list *feat_l3;
+
+/* Common functions for supporting feature callback functions. */
+static void free_feature(struct psr_socket_info *info)
+{
+    struct feat_list *feat_tmp;
+
+    if ( !info )
+        return;
+
+    list_for_each_entry(feat_tmp, &info->feat_list, list)
+    {
+        clear_bit(feat_tmp->feature, &info->features);
+        list_del(&feat_tmp->list);
+        xfree(feat_tmp);
+    }
+
+    /* Free feature which are not added into feat_list. */
+    if ( feat_l3 )
+    {
+        xfree(feat_l3);
+        feat_l3 = NULL;
+    }
+}
+
+static bool psr_check_cbm(unsigned int cbm_len, uint64_t cbm)
+{
+    unsigned int first_bit, zero_bit;
+
+    /* Set bits should only in the range of [0, cbm_len). */
+    if ( cbm & (~0ull << cbm_len) )
+        return false;
+
+    /* At least one bit need to be set. */
+    if ( cbm == 0 )
+        return false;
+
+    first_bit = find_first_bit(&cbm, cbm_len);
+    zero_bit = find_next_zero_bit(&cbm, cbm_len, first_bit);
+
+    /* Set bits should be contiguous. */
+    if ( zero_bit < cbm_len &&
+         find_next_bit(&cbm, cbm_len, zero_bit) < cbm_len )
+        return false;
+
+    return true;
+}
+
+/*
+ * Features specific implementations.
+ */
+
+/* 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 *feat,
+                                struct psr_socket_info *info)
+{
+    struct psr_cat_lvl_info l3_cat;
+    unsigned int socket;
+    uint64_t val;
+
+    /* No valid value so do not enable feature. */
+    if ( 0 == eax || 0 == edx )
+        return;
+
+    l3_cat.cbm_len = (eax & 0x1f) + 1;
+    l3_cat.cos_max = min(opt_cos_max, edx & 0xffff);
+
+    /* cos=0 is reserved as default cbm(all ones). */
+    feat->cos_reg_val[0] = (1ull << l3_cat.cbm_len) - 1;
+
+    feat->feature = PSR_SOCKET_L3_CAT;
+
+    if ( (ecx & PSR_CAT_CDP_CAPABILITY) && (opt_psr & PSR_CDP) &&
+         !test_bit(PSR_SOCKET_L3_CDP, &info->features) )
+    {
+        /* Data */
+        feat->cos_reg_val[0] = (1ull << l3_cat.cbm_len) - 1;
+        /* Code */
+        feat->cos_reg_val[1] = (1ull << l3_cat.cbm_len) - 1;
+
+        /* We only write mask1 since mask0 is always all ones by default. */
+        wrmsrl(MSR_IA32_PSR_L3_MASK(1),
+               (1ull << l3_cat.cbm_len) - 1);
+        rdmsrl(MSR_IA32_PSR_L3_QOS_CFG, val);
+        wrmsrl(MSR_IA32_PSR_L3_QOS_CFG, val | (1 << PSR_L3_QOS_CDP_ENABLE_BIT));
+
+        /* Cut half of cos_max when CDP is enabled. */
+        l3_cat.cos_max >>= 1;
+
+        feat->feature = PSR_SOCKET_L3_CDP;
+        __set_bit(PSR_SOCKET_L3_CDP, &info->features);
+    }
+    else
+        __set_bit(PSR_SOCKET_L3_CAT, &info->features);
+
+    feat->info.l3_info = l3_cat;
+
+    info->nr_feat++;
+
+    /* Add this feature into list. */
+    list_add_tail(&feat->list, &info->feat_list);
+
+    socket = cpu_to_socket(smp_processor_id());
+    printk(XENLOG_INFO "L3 CAT: enabled on socket %u, cos_max:%u, cbm_len:%u, CDP:%s\n",
+           socket, feat->info.l3_info.cos_max, feat->info.l3_info.cbm_len,
+           test_bit(PSR_SOCKET_L3_CDP, &info->features) ? "on" : "off");
+}
+
+static int l3_cat_compare_val(const uint64_t val[],
+                              const struct feat_list *feat,
+                              unsigned int cos, bool *found)
+{
+    uint64_t l3_def_cbm;
+
+    l3_def_cbm = (1ull << feat->info.l3_info.cbm_len) - 1;
+
+    /* CDP */
+    if ( feat->feature == PSR_SOCKET_L3_CDP )
+    {
+        if ( cos > feat->info.l3_info.cos_max )
+        {
+            if ( val[0] != l3_def_cbm ||
+                 val[1] != l3_def_cbm )
+            {
+                *found = false;
+                return -ENOENT;
+            }
+            *found = true;
+        }
+        else
+            *found = (val[0] == feat->cos_reg_val[cos * 2] &&
+                      val[1] == feat->cos_reg_val[cos * 2 + 1]);
+
+        /* CDP occupies two COS, one for data, one for code. */
+        return 2;
+    }
+
+    /* CAT */
+    if ( cos > feat->info.l3_info.cos_max )
+    {
+        if ( val[0] != l3_def_cbm )
+        {
+            *found = false;
+            return -ENOENT;
+        }
+        *found = true;
+    }
+    else
+        *found = (val[0] == feat->cos_reg_val[cos]);
+
+    /* L3 CAT occupies one COS. */
+    return 1;
+}
+
+static unsigned int l3_cat_get_cos_max_from_type(const struct feat_list *feat,
+                                                 enum psr_val_type type)
+{
+    if ( type != PSR_MASK_TYPE_L3_DATA &&
+         type != PSR_MASK_TYPE_L3_CODE &&
+         type != PSR_MASK_TYPE_L3_CBM )
+        return 0;
+
+    return feat->info.l3_info.cos_max;
+}
+
+static unsigned int l3_cat_exceeds_cos_max(const uint64_t val[],
+                                           const struct feat_list *feat,
+                                           unsigned int cos)
+{
+    uint64_t l3_def_cbm;
+
+    l3_def_cbm = (1ull << feat->info.l3_info.cbm_len) - 1;
+
+    /* CDP */
+    if ( feat->feature == PSR_SOCKET_L3_CDP )
+    {
+        if ( cos > feat->info.l3_info.cos_max &&
+             (val[0] != l3_def_cbm || val[1] != l3_def_cbm) )
+                /*
+                 * Exceed cos_max and value to set is not default,
+                 * return error.
+                 */
+                return 0;
+
+        /* CDP occupies two COS, one for data, one for code. */
+        return 2;
+    }
+
+    /* CAT */
+    if ( cos > feat->info.l3_info.cos_max &&
+         val[0] != l3_def_cbm )
+            /*
+             * Exceed cos_max and value to set is not default,
+             * return error.
+             */
+            return 0;
+
+    /* L3 CAT occupies one COS. */
+    return 1;
+}
+
+static int l3_cat_write_msr(unsigned int cos, const uint64_t val[],
+                            struct feat_list *feat)
+{
+    /* CDP */
+    if ( feat->feature == PSR_SOCKET_L3_CDP )
+    {
+        /*
+         * If input cos is more than the cos_max of the feature, we should
+         * not set the value.
+         */
+        if ( cos > feat->info.l3_info.cos_max )
+            /* CDP occupies two COS, one for data, one for code. */
+            return 2;
+
+        /* Data */
+        feat->cos_reg_val[cos * 2] = val[0];
+        /* Code */
+        feat->cos_reg_val[cos * 2 + 1] = val[1];
+
+        wrmsrl(MSR_IA32_PSR_L3_MASK_DATA(cos), val[0]);
+        wrmsrl(MSR_IA32_PSR_L3_MASK_CODE(cos), val[1]);
+        /* CDP occupies two COS, one for data, one for code. */
+        return 2;
+    }
+
+    /* CAT */
+    if ( cos > feat->info.l3_info.cos_max )
+        /* L3 CAT occupies one COS. */
+        return 1;
+
+    feat->cos_reg_val[cos] = val[0];
+    wrmsrl(MSR_IA32_PSR_L3_MASK(cos), val[0]);
+    /* L3 CAT occupies one COS. */
+    return 1;
+}
+
+static unsigned int l3_cat_get_cos_num(const struct feat_list *feat)
+{
+    if ( feat->feature == PSR_SOCKET_L3_CDP )
+        return 2;
+
+    return 1;
+}
+
+static int l3_cat_get_old_val(uint64_t val[],
+                              const struct feat_list *feat,
+                              unsigned int old_cos,
+                              enum psr_val_type type)
+{
+    if ( old_cos > feat->info.l3_info.cos_max )
+        /* Use default value. */
+        old_cos = 0;
+
+    /* CDP */
+    if ( feat->feature == PSR_SOCKET_L3_CDP )
+    {
+        /* Data */
+        val[0] = feat->cos_reg_val[old_cos * 2];
+        /* Code */
+        val[1] = feat->cos_reg_val[old_cos * 2 + 1];
+
+        /* CDP occupies two COS, one for data, one for code. */
+        return 2;
+    }
+
+    /* CAT */
+    val[0] =  feat->cos_reg_val[old_cos];
+
+    /* L3 CAT occupies one COS. */
+    return 1;
+}
+
+static int l3_cat_set_new_val(uint64_t val[],
+                              const struct feat_list *feat,
+                              unsigned int old_cos,
+                              enum psr_val_type type,
+                              uint64_t m)
+{
+    /* L3 CAT occupies one COS. */
+    unsigned int ret = 1;
+
+    switch (type) {
+    /* CDP occupies two COS, one for data, one for code. */
+    case PSR_MASK_TYPE_L3_DATA:
+    case PSR_MASK_TYPE_L3_CODE:
+        if ( feat->feature != PSR_SOCKET_L3_CDP )
+            return -ENXIO;
+
+        if ( !psr_check_cbm(feat->info.l3_info.cbm_len, m) )
+            return -EINVAL;
+
+        if ( type == PSR_MASK_TYPE_L3_DATA )
+            val[0] = m;
+        else
+            val[1] = m;
+
+        ret= 2;
+        break;
+
+    /* CAT */
+    case PSR_MASK_TYPE_L3_CBM:
+        if ( !psr_check_cbm(feat->info.l3_info.cbm_len, m) )
+            return -EINVAL;
+
+        val[0] = m;
+        break;
+
+    default:
+        if ( feat->feature == PSR_SOCKET_L3_CDP )
+            /* CDP occupies two COS, one for data, one for code. */
+            ret = 2;
+        break;
+    }
+
+    return ret;
+}
+
+static int l3_cat_get_val(const struct feat_list *feat, unsigned int cos,
+                          enum psr_val_type type, uint64_t *val)
+{
+    if ( cos > feat->info.l3_info.cos_max )
+        /* Use default value. */
+        cos = 0;
+
+    switch (type) {
+    /* CDP */
+    case PSR_MASK_TYPE_L3_DATA:
+    case PSR_MASK_TYPE_L3_CODE:
+        if ( feat->feature != PSR_SOCKET_L3_CDP )
+            return -ENXIO;
+
+        if ( type == PSR_MASK_TYPE_L3_DATA )
+            *val = feat->cos_reg_val[cos * 2];
+        else
+            *val = feat->cos_reg_val[cos * 2 + 1];
+        break;
+
+    /* CAT */
+    case PSR_MASK_TYPE_L3_CBM:
+        *val =  feat->cos_reg_val[cos];
+        break;
+
+    default:
+        return 0;
+    }
+
+    return 1;
+}
+
+static int l3_cat_get_feat_info(const struct feat_list *feat,
+                                enum psr_val_type type,
+                                uint32_t dat[], uint32_t array_len)
+{
+    if ( !dat || 3 > array_len )
+        return 0;
+
+    switch (type) {
+    case PSR_MASK_TYPE_L3_CBM:
+    case PSR_MASK_TYPE_L3_DATA:
+    case PSR_MASK_TYPE_L3_CODE:
+        if ( feat->feature == PSR_SOCKET_L3_CDP )
+            dat[2] |= XEN_SYSCTL_PSR_CAT_L3_CDP;
+        else
+            dat[2] = 0;
+        break;
 
+    default:
+        /* This feature is not requested feature. */
+        return 0;
+    }
+
+    dat[0] = feat->info.l3_info.cbm_len;
+    dat[1] = feat->info.l3_info.cos_max;
+
+    return 1;
+}
+
+static unsigned int l3_cat_get_max_cos_max(const struct feat_list *feat)
+{
+    return feat->info.l3_info.cos_max;
+}
+
+struct feat_ops l3_cat_ops = {
+    .init_feature = l3_cat_init_feature,
+    .get_cos_num = l3_cat_get_cos_num,
+    .get_old_val = l3_cat_get_old_val,
+    .set_new_val = l3_cat_set_new_val,
+    .compare_val = l3_cat_compare_val,
+    .get_cos_max_from_type = l3_cat_get_cos_max_from_type,
+    .exceeds_cos_max = l3_cat_exceeds_cos_max,
+    .write_msr = l3_cat_write_msr,
+    .get_val = l3_cat_get_val,
+    .get_feat_info = l3_cat_get_feat_info,
+    .get_max_cos_max = l3_cat_get_max_cos_max,
+};
+
+/*
+ * Common functions implementation
+ */
 static unsigned int get_socket_cpu(unsigned int socket)
 {
     if ( likely(socket < nr_sockets) )
@@ -209,17 +740,29 @@ void psr_free_rmid(struct domain *d)
     d->arch.psr_rmid = 0;
 }
 
+static inline unsigned int get_max_cos_max(const struct psr_socket_info *info)
+{
+    const struct feat_list *feat_tmp;
+    unsigned int cos_max = 0;
+
+    list_for_each_entry(feat_tmp, &info->feat_list, list)
+        cos_max = max(feat_tmp->ops.get_max_cos_max(feat_tmp), cos_max);
+
+    return cos_max;
+}
+
 static inline void psr_assoc_init(void)
 {
     struct psr_assoc *psra = &this_cpu(psr_assoc);
 
-    if ( cat_socket_info )
+    if ( socket_info )
     {
         unsigned int socket = cpu_to_socket(smp_processor_id());
+        const struct psr_socket_info *info = socket_info + socket;
+        unsigned int cos_max = get_max_cos_max(info);
 
-        if ( test_bit(socket, cat_socket_enable) )
-            psra->cos_mask = ((1ull << get_count_order(
-                             cat_socket_info[socket].cos_max)) - 1) << 32;
+        if ( info->features )
+            psra->cos_mask = ((1ull << get_count_order(cos_max)) - 1) << 32;
     }
 
     if ( psr_cmt_enabled() || psra->cos_mask )
@@ -256,270 +799,362 @@ void psr_ctxt_switch_to(struct domain *d)
         psra->val = reg;
     }
 }
-static struct psr_cat_socket_info *get_cat_socket_info(unsigned int socket)
+
+static struct psr_socket_info *get_socket_info(unsigned int socket)
 {
-    if ( !cat_socket_info )
+    struct psr_socket_info *info;
+
+    if ( !socket_info )
         return ERR_PTR(-ENODEV);
 
     if ( socket >= nr_sockets )
         return ERR_PTR(-ENOTSOCK);
 
-    if ( !test_bit(socket, cat_socket_enable) )
-        return ERR_PTR(-ENOENT);
+    info = socket_info + socket;
 
-    return cat_socket_info + socket;
-}
+    if ( !info->features )
+        return ERR_PTR(-ENOENT);
 
-static inline bool_t cdp_is_enabled(unsigned int socket)
-{
-    return cdp_socket_enable && test_bit(socket, cdp_socket_enable);
+    return info;
 }
 
-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 psr_val_type type,
+                 uint32_t dat[], uint32_t array_len)
 {
-    struct psr_cat_socket_info *info = get_cat_socket_info(socket);
+    struct psr_socket_info *info = get_socket_info(socket);
+    const struct feat_list *feat_tmp;
 
     if ( IS_ERR(info) )
         return PTR_ERR(info);
 
-    *cbm_len = info->cbm_len;
-    *cos_max = info->cos_max;
+    list_for_each_entry(feat_tmp, &info->feat_list, list)
+        if ( feat_tmp->ops.get_feat_info(feat_tmp, type, dat, array_len) )
+            return 0;
 
-    *flags = 0;
-    if ( cdp_is_enabled(socket) )
-        *flags |= XEN_SYSCTL_PSR_CAT_L3_CDP;
+    return -ENODEV;
+}
 
-    return 0;
+static unsigned int get_cos_num(const struct psr_socket_info *info)
+{
+    const struct feat_list *feat_tmp;
+    unsigned int num = 0;
+
+    list_for_each_entry(feat_tmp, &info->feat_list, list)
+        num += feat_tmp->ops.get_cos_num(feat_tmp);
+
+    return num;
 }
 
-int psr_get_l3_cbm(struct domain *d, unsigned int socket,
-                   uint64_t *cbm, enum cbm_type type)
+static int get_old_set_new(uint64_t *val,
+                           uint32_t array_len,
+                           const struct psr_socket_info *info,
+                           unsigned int old_cos,
+                           enum psr_val_type type,
+                           uint64_t m)
 {
-    struct psr_cat_socket_info *info = get_cat_socket_info(socket);
-    bool_t cdp_enabled = cdp_is_enabled(socket);
+    const struct feat_list *feat_tmp;
+    int ret;
+    uint64_t *val_tmp = val;
 
-    if ( IS_ERR(info) )
-        return PTR_ERR(info);
+    if ( !val )
+        return -EINVAL;
 
-    switch ( type )
+    list_for_each_entry(feat_tmp, &info->feat_list, list)
     {
-    case PSR_CBM_TYPE_L3:
-        if ( cdp_enabled )
-            return -EXDEV;
-        *cbm = info->cos_to_cbm[d->arch.psr_cos_ids[socket]].cbm;
-        break;
+        /* value getting order is same as feature list */
+        ret = feat_tmp->ops.get_old_val(val_tmp, feat_tmp, old_cos, type);
 
-    case PSR_CBM_TYPE_L3_CODE:
-        if ( !cdp_enabled )
-            *cbm = info->cos_to_cbm[d->arch.psr_cos_ids[socket]].cbm;
-        else
-            *cbm = info->cos_to_cbm[d->arch.psr_cos_ids[socket]].code;
-        break;
-
-    case PSR_CBM_TYPE_L3_DATA:
-        if ( !cdp_enabled )
-            *cbm = info->cos_to_cbm[d->arch.psr_cos_ids[socket]].cbm;
-        else
-            *cbm = info->cos_to_cbm[d->arch.psr_cos_ids[socket]].data;
-        break;
+        val_tmp += ret;
+        if ( val_tmp - val > array_len)
+            return -EINVAL;
+    }
 
-    default:
-        ASSERT_UNREACHABLE();
+    val_tmp = val;
+    list_for_each_entry(feat_tmp, &info->feat_list, list)
+    {
+        /* value setting order is same as feature list */
+        ret = feat_tmp->ops.set_new_val(val_tmp, feat_tmp, old_cos, type, m);
+        if ( ret < 0 )
+            return ret;
+
+        val_tmp += ret;
+        if ( val_tmp - val > array_len)
+            return -EINVAL;
     }
 
     return 0;
 }
 
-static bool_t psr_check_cbm(unsigned int cbm_len, uint64_t cbm)
+int psr_get_val(struct domain *d, unsigned int socket,
+                uint64_t *val, enum psr_val_type type)
 {
-    unsigned int first_bit, zero_bit;
+    const struct psr_socket_info *info = get_socket_info(socket);
+    unsigned int cos = d->arch.psr_cos_ids[socket];
+    const struct feat_list *feat_tmp;
+    int ret;
 
-    /* Set bits should only in the range of [0, cbm_len). */
-    if ( cbm & (~0ull << cbm_len) )
-        return 0;
-
-    /* At least one bit need to be set. */
-    if ( cbm == 0 )
-        return 0;
+    if ( IS_ERR(info) )
+        return PTR_ERR(info);
 
-    first_bit = find_first_bit(&cbm, cbm_len);
-    zero_bit = find_next_zero_bit(&cbm, cbm_len, first_bit);
+    list_for_each_entry(feat_tmp, &info->feat_list, list)
+    {
+        ret = feat_tmp->ops.get_val(feat_tmp, cos, type, val);
+        if ( ret < 0 )
+            return ret;
 
-    /* Set bits should be contiguous. */
-    if ( zero_bit < cbm_len &&
-         find_next_bit(&cbm, cbm_len, zero_bit) < cbm_len )
-        return 0;
+        if ( ret > 0 )
+            /* Found */
+            break;
+    }
 
-    return 1;
+    return 0;
 }
 
-struct cos_cbm_info
+struct cos_mask_info
 {
     unsigned int cos;
-    bool_t cdp;
-    uint64_t cbm_code;
-    uint64_t cbm_data;
+    struct list_head *feat_list;
+    const uint64_t *val;
 };
 
-static void do_write_l3_cbm(void *data)
+static void do_write_psr_msr(void *data)
 {
-    struct cos_cbm_info *info = data;
+    struct cos_mask_info *info = (struct cos_mask_info *)data;
+    unsigned int cos           = info->cos;
+    struct list_head *feat_list= info->feat_list;
+    const uint64_t *val        = info->val;
+    struct feat_list *feat_tmp;
+    int ret;
+
+    if ( !feat_list )
+        return;
 
-    if ( info->cdp )
+    list_for_each_entry(feat_tmp, feat_list, list)
     {
-        wrmsrl(MSR_IA32_PSR_L3_MASK_CODE(info->cos), info->cbm_code);
-        wrmsrl(MSR_IA32_PSR_L3_MASK_DATA(info->cos), info->cbm_data);
+        ret = feat_tmp->ops.write_msr(cos, val, feat_tmp);
+        if ( ret <= 0)
+            return;
+
+        val += ret;
     }
-    else
-        wrmsrl(MSR_IA32_PSR_L3_MASK(info->cos), info->cbm_code);
 }
 
-static int write_l3_cbm(unsigned int socket, unsigned int cos,
-                        uint64_t cbm_code, uint64_t cbm_data, bool_t cdp)
+static int write_psr_msr(unsigned int socket, unsigned int cos,
+                         const uint64_t *val)
 {
-    struct cos_cbm_info info =
+    struct psr_socket_info *info = get_socket_info(socket);
+
+    struct cos_mask_info data =
     {
         .cos = cos,
-        .cbm_code = cbm_code,
-        .cbm_data = cbm_data,
-        .cdp = cdp,
+        .feat_list = &info->feat_list,
+        .val = val,
     };
 
     if ( socket == cpu_to_socket(smp_processor_id()) )
-        do_write_l3_cbm(&info);
+        do_write_psr_msr(&data);
     else
     {
         unsigned int cpu = get_socket_cpu(socket);
 
         if ( cpu >= nr_cpu_ids )
             return -ENOTSOCK;
-        on_selected_cpus(cpumask_of(cpu), do_write_l3_cbm, &info, 1);
+        on_selected_cpus(cpumask_of(cpu), do_write_psr_msr, &data, 1);
     }
 
     return 0;
 }
 
-static int find_cos(struct psr_cat_cbm *map, unsigned int cos_max,
-                    uint64_t cbm_code, uint64_t cbm_data, bool_t cdp_enabled)
+static int find_cos(const uint64_t *val, uint32_t array_len,
+                    enum psr_val_type type,
+                    const struct psr_socket_info *info)
 {
     unsigned int cos;
+    const struct psr_ref *map = info->cos_ref;
+    const struct feat_list *feat_tmp;
+    const uint64_t *val_tmp = val;
+    int ret;
+    bool found = false;
+    unsigned int cos_max = 0;
+
+    /* cos_max is the max COS of the feature to be set. */
+    list_for_each_entry(feat_tmp, &info->feat_list, list)
+    {
+        cos_max = feat_tmp->ops.get_cos_max_from_type(feat_tmp, type);
+        if ( cos_max > 0 )
+            break;
+    }
 
     for ( cos = 0; cos <= cos_max; cos++ )
     {
-        if ( (map[cos].ref || cos == 0) &&
-             ((!cdp_enabled && map[cos].cbm == cbm_code) ||
-              (cdp_enabled && map[cos].code == cbm_code &&
-                              map[cos].data == cbm_data)) )
+        if ( 0 != cos && 0 == map[cos].ref )
+            continue;
+
+        /* Not found, need find again from beginning. */
+        val_tmp = val;
+        list_for_each_entry(feat_tmp, &info->feat_list, list)
+        {
+            /*
+             * Compare value according to feature list order.
+             * We must follow this order because value array is assembled
+             * as this order in get_old_set_new().
+             */
+            ret = feat_tmp->ops.compare_val(val_tmp, feat_tmp, cos, &found);
+            if ( ret < 0 )
+                return ret;
+
+            /* If fail to match, go to next cos to compare. */
+            if ( !found )
+                break;
+
+            val_tmp += ret;
+            if ( val_tmp - val > array_len )
+                return -EINVAL;
+        }
+
+        /* Every feature can match, this cos is what we find. */
+        if ( found )
             return cos;
     }
 
     return -ENOENT;
 }
 
-static int pick_avail_cos(struct psr_cat_cbm *map, unsigned int cos_max,
-                          unsigned int old_cos)
+static bool exceeds_cos_max(const uint64_t *val,
+                            uint32_t array_len,
+                            const struct psr_socket_info *info,
+                            unsigned int cos)
+{
+    unsigned int ret;
+    const uint64_t *val_tmp = val;
+    const struct feat_list *feat_tmp;
+
+    list_for_each_entry(feat_tmp, &info->feat_list, list)
+    {
+        ret = feat_tmp->ops.exceeds_cos_max(val_tmp, feat_tmp, cos);
+        if ( 0 == ret )
+            return false;
+
+        val_tmp += ret;
+        if ( val_tmp - val > array_len )
+            return false;
+    }
+
+    return true;
+}
+
+static int alloc_new_cos(const struct psr_socket_info *info,
+                         const uint64_t *val, uint32_t array_len,
+                         unsigned int old_cos,
+                         enum psr_val_type type)
 {
     unsigned int cos;
+    unsigned int cos_max = 0;
+    const struct feat_list *feat_tmp;
+    const struct psr_ref *map = info->cos_ref;
+
+    /*
+     * cos_max is the max COS of the feature to be set.
+     */
+    list_for_each_entry(feat_tmp, &info->feat_list, list)
+    {
+        cos_max = feat_tmp->ops.get_cos_max_from_type(feat_tmp, type);
+        if ( cos_max > 0 )
+            break;
+    }
+
+    if ( !cos_max )
+        return -ENOENT;
 
     /* If old cos is referred only by the domain, then use it. */
     if ( map[old_cos].ref == 1 && old_cos != 0 )
-        return old_cos;
+        if ( exceeds_cos_max(val, array_len, info, old_cos) )
+            return old_cos;
 
     /* Find an unused one other than cos0. */
     for ( cos = 1; cos <= cos_max; cos++ )
+        /*
+         * ref is 0 means this COS is not occupied by other domain and
+         * can be used for current setting.
+         */
         if ( map[cos].ref == 0 )
+        {
+            if ( !exceeds_cos_max(val, array_len, info, cos) )
+                return -ENOENT;
+
             return cos;
+        }
 
     return -ENOENT;
 }
 
-int psr_set_l3_cbm(struct domain *d, unsigned int socket,
-                   uint64_t cbm, enum cbm_type type)
+int psr_set_val(struct domain *d, unsigned int socket,
+                uint64_t val, enum psr_val_type type)
 {
-    unsigned int old_cos, cos_max;
+    unsigned int old_cos;
     int cos, ret;
-    uint64_t cbm_data, cbm_code;
-    bool_t cdp_enabled = cdp_is_enabled(socket);
-    struct psr_cat_cbm *map;
-    struct psr_cat_socket_info *info = get_cat_socket_info(socket);
+    struct psr_ref *map;
+    uint64_t *val_array;
+    struct psr_socket_info *info = get_socket_info(socket);
+    uint32_t array_len;
 
     if ( IS_ERR(info) )
         return PTR_ERR(info);
 
-    if ( !psr_check_cbm(info->cbm_len, cbm) )
-        return -EINVAL;
-
-    if ( !cdp_enabled && (type == PSR_CBM_TYPE_L3_CODE ||
-                          type == PSR_CBM_TYPE_L3_DATA) )
-        return -ENXIO;
-
-    cos_max = info->cos_max;
+    map = info->cos_ref;
     old_cos = d->arch.psr_cos_ids[socket];
-    map = info->cos_to_cbm;
 
-    switch ( type )
-    {
-    case PSR_CBM_TYPE_L3:
-        cbm_code = cbm;
-        cbm_data = cbm;
-        break;
-
-    case PSR_CBM_TYPE_L3_CODE:
-        cbm_code = cbm;
-        cbm_data = map[old_cos].data;
-        break;
-
-    case PSR_CBM_TYPE_L3_DATA:
-        cbm_code = map[old_cos].code;
-        cbm_data = cbm;
-        break;
+    array_len = get_cos_num((const struct psr_socket_info *)info);
+    val_array = xzalloc_array(uint64_t, array_len);
+    if ( !val_array )
+        return -ENOMEM;
 
-    default:
-        ASSERT_UNREACHABLE();
-        return -EINVAL;
-    }
+    if ( (ret = get_old_set_new(val_array, array_len,
+                                (const struct psr_socket_info *)info,
+                                old_cos, type, val)) != 0 )
+        return ret;
 
-    spin_lock(&info->cbm_lock);
-    cos = find_cos(map, cos_max, cbm_code, cbm_data, cdp_enabled);
+    spin_lock(&info->mask_lock);
+    cos = find_cos((const uint64_t *)val_array, array_len, type,
+                   (const struct psr_socket_info *)info);
     if ( cos >= 0 )
     {
         if ( cos == old_cos )
         {
-            spin_unlock(&info->cbm_lock);
+            spin_unlock(&info->mask_lock);
+            xfree(val_array);
             return 0;
         }
     }
     else
     {
-        cos = pick_avail_cos(map, cos_max, old_cos);
+        cos = alloc_new_cos((const struct psr_socket_info *)info,
+                            (const uint64_t *)val_array, array_len,
+                            old_cos, type);
         if ( cos < 0 )
         {
-            spin_unlock(&info->cbm_lock);
+            spin_unlock(&info->mask_lock);
+            xfree(val_array);
             return cos;
         }
 
-        /* We try to avoid writing MSR. */
-        if ( (cdp_enabled &&
-             (map[cos].code != cbm_code || map[cos].data != cbm_data)) ||
-             (!cdp_enabled && map[cos].cbm != cbm_code) )
+        /* Write all features MSRs corresponding to the COS */
+        ret = write_psr_msr(socket, cos, (const uint64_t *)val_array);
+        if ( ret )
         {
-            ret = write_l3_cbm(socket, cos, cbm_code, cbm_data, cdp_enabled);
-            if ( ret )
-            {
-                spin_unlock(&info->cbm_lock);
-                return ret;
-            }
-            map[cos].code = cbm_code;
-            map[cos].data = cbm_data;
+            spin_unlock(&info->mask_lock);
+            xfree(val_array);
+            return ret;
         }
     }
 
     map[cos].ref++;
     map[old_cos].ref--;
-    spin_unlock(&info->cbm_lock);
+
+    spin_unlock(&info->mask_lock);
 
     d->arch.psr_cos_ids[socket] = cos;
+    xfree(val_array);
 
     return 0;
 }
@@ -529,20 +1164,23 @@ static void psr_free_cos(struct domain *d)
 {
     unsigned int socket;
     unsigned int cos;
-    struct psr_cat_socket_info *info;
+    struct psr_socket_info *info;
 
     if( !d->arch.psr_cos_ids )
         return;
 
-    for_each_set_bit(socket, cat_socket_enable, nr_sockets)
+    for( socket = 0; socket < nr_sockets; socket++)
     {
         if ( (cos = d->arch.psr_cos_ids[socket]) == 0 )
             continue;
 
-        info = cat_socket_info + socket;
-        spin_lock(&info->cbm_lock);
-        info->cos_to_cbm[cos].ref--;
-        spin_unlock(&info->cbm_lock);
+        info = get_socket_info(socket);
+        if ( IS_ERR(info) )
+            continue;
+
+        spin_lock(&info->mask_lock);
+        info->cos_ref[cos].ref--;
+        spin_unlock(&info->mask_lock);
     }
 
     xfree(d->arch.psr_cos_ids);
@@ -551,7 +1189,7 @@ static void psr_free_cos(struct domain *d)
 
 int psr_domain_init(struct domain *d)
 {
-    if ( cat_socket_info )
+    if ( socket_info )
     {
         d->arch.psr_cos_ids = xzalloc_array(unsigned int, nr_sockets);
         if ( !d->arch.psr_cos_ids )
@@ -567,137 +1205,126 @@ void psr_domain_free(struct domain *d)
     psr_free_cos(d);
 }
 
-static int cat_cpu_prepare(unsigned int cpu)
+static int cpu_prepare_work(unsigned int cpu)
 {
-    if ( !cat_socket_info )
+    if ( !socket_info )
         return 0;
 
-    if ( temp_cos_to_cbm == NULL &&
-         (temp_cos_to_cbm = xzalloc_array(struct psr_cat_cbm,
+    if ( temp_cos_ref == NULL &&
+         (temp_cos_ref = xzalloc_array(struct psr_ref,
                                           opt_cos_max + 1UL)) == NULL )
         return -ENOMEM;
 
+    /* Malloc memory for the global feature head here. */
+    if ( feat_l3 == NULL &&
+         (feat_l3 = xzalloc(struct feat_list)) == NULL )
+        return -ENOMEM;
+
     return 0;
 }
 
-static void cat_cpu_init(void)
+static void cpu_init_work(void)
 {
     unsigned int eax, ebx, ecx, edx;
-    struct psr_cat_socket_info *info;
+    struct psr_socket_info *info;
     unsigned int socket;
     unsigned int cpu = smp_processor_id();
-    uint64_t val;
     const struct cpuinfo_x86 *c = cpu_data + cpu;
+    struct feat_list *feat_tmp;
 
     if ( !cpu_has(c, X86_FEATURE_PQE) || c->cpuid_level < PSR_CPUID_LEVEL_CAT )
         return;
 
     socket = cpu_to_socket(cpu);
-    if ( test_bit(socket, cat_socket_enable) )
+    info = socket_info + socket;
+    if ( info->features )
         return;
 
+    info->cos_ref = temp_cos_ref;
+    temp_cos_ref = NULL;
+    spin_lock_init(&info->mask_lock);
+
     cpuid_count(PSR_CPUID_LEVEL_CAT, 0, &eax, &ebx, &ecx, &edx);
     if ( ebx & PSR_RESOURCE_TYPE_L3 )
     {
-        cpuid_count(PSR_CPUID_LEVEL_CAT, 1, &eax, &ebx, &ecx, &edx);
-        info = cat_socket_info + socket;
-        info->cbm_len = (eax & 0x1f) + 1;
-        info->cos_max = min(opt_cos_max, edx & 0xffff);
-
-        info->cos_to_cbm = temp_cos_to_cbm;
-        temp_cos_to_cbm = NULL;
-        /* cos=0 is reserved as default cbm(all ones). */
-        info->cos_to_cbm[0].cbm = (1ull << info->cbm_len) - 1;
+        feat_tmp = feat_l3;
+        feat_l3 = NULL;
 
-        spin_lock_init(&info->cbm_lock);
-
-        set_bit(socket, cat_socket_enable);
-
-        if ( (ecx & PSR_CAT_CDP_CAPABILITY) && (opt_psr & PSR_CDP) &&
-             cdp_socket_enable && !test_bit(socket, cdp_socket_enable) )
-        {
-            info->cos_to_cbm[0].code = (1ull << info->cbm_len) - 1;
-            info->cos_to_cbm[0].data = (1ull << info->cbm_len) - 1;
-
-            /* We only write mask1 since mask0 is always all ones by default. */
-            wrmsrl(MSR_IA32_PSR_L3_MASK(1), (1ull << info->cbm_len) - 1);
-
-            rdmsrl(MSR_IA32_PSR_L3_QOS_CFG, val);
-            wrmsrl(MSR_IA32_PSR_L3_QOS_CFG, val | (1 << PSR_L3_QOS_CDP_ENABLE_BIT));
-
-            /* Cut half of cos_max when CDP is enabled. */
-            info->cos_max >>= 1;
-
-            set_bit(socket, cdp_socket_enable);
-        }
-        printk(XENLOG_INFO "CAT: enabled on socket %u, cos_max:%u, cbm_len:%u, CDP:%s\n",
-               socket, info->cos_max, info->cbm_len,
-               cdp_is_enabled(socket) ? "on" : "off");
+        /* Initialize this feature according to CPUID. */
+        cpuid_count(PSR_CPUID_LEVEL_CAT, 1, &eax, &ebx, &ecx, &edx);
+        feat_tmp->ops = l3_cat_ops;
+        feat_tmp->ops.init_feature(eax, ebx, ecx, edx, feat_tmp, info);
     }
 }
 
-static void cat_cpu_fini(unsigned int cpu)
+static void cpu_fini_work(unsigned int cpu)
 {
     unsigned int socket = cpu_to_socket(cpu);
 
     if ( !socket_cpumask[socket] || cpumask_empty(socket_cpumask[socket]) )
     {
-        struct psr_cat_socket_info *info = cat_socket_info + socket;
+        struct psr_socket_info *info = get_socket_info(socket);
+
+        free_feature(info);
 
-        if ( info->cos_to_cbm )
+        if ( info->cos_ref )
         {
-            xfree(info->cos_to_cbm);
-            info->cos_to_cbm = NULL;
+            xfree(info->cos_ref);
+            info->cos_ref = NULL;
         }
-
-        if ( cdp_is_enabled(socket) )
-            clear_bit(socket, cdp_socket_enable);
-
-        clear_bit(socket, cat_socket_enable);
     }
 }
 
-static void __init psr_cat_free(void)
+static void __init psr_free(void)
 {
-    xfree(cat_socket_enable);
-    cat_socket_enable = NULL;
-    xfree(cat_socket_info);
-    cat_socket_info = NULL;
+    unsigned int i;
+
+    for ( i = 0; i < nr_sockets; i++ )
+        free_feature(&socket_info[i]);
+
+    xfree(socket_info);
+    socket_info = NULL;
 }
 
-static void __init init_psr_cat(void)
+static void __init init_psr(void)
 {
+    unsigned int i;
+
     if ( opt_cos_max < 1 )
     {
         printk(XENLOG_INFO "CAT: disabled, cos_max is too small\n");
         return;
     }
 
-    cat_socket_enable = xzalloc_array(unsigned long, BITS_TO_LONGS(nr_sockets));
-    cat_socket_info = xzalloc_array(struct psr_cat_socket_info, nr_sockets);
-    cdp_socket_enable = xzalloc_array(unsigned long, BITS_TO_LONGS(nr_sockets));
+    socket_info = xzalloc_array(struct psr_socket_info, nr_sockets);
+
+    if ( !socket_info )
+    {
+        printk(XENLOG_INFO "Fail to alloc socket_info!\n");
+        return;
+    }
 
-    if ( !cat_socket_enable || !cat_socket_info )
-        psr_cat_free();
+    for ( i = 0; i < nr_sockets; i++ )
+        INIT_LIST_HEAD(&socket_info[i].feat_list);
 }
 
 static int psr_cpu_prepare(unsigned int cpu)
 {
-    return cat_cpu_prepare(cpu);
+    return cpu_prepare_work(cpu);
 }
 
 static void psr_cpu_init(void)
 {
-    if ( cat_socket_info )
-        cat_cpu_init();
+    if ( socket_info )
+        cpu_init_work();
 
     psr_assoc_init();
 }
 
 static void psr_cpu_fini(unsigned int cpu)
 {
-    if ( cat_socket_info )
-        cat_cpu_fini(cpu);
+    if ( socket_info )
+        cpu_fini_work(cpu);
 }
 
 static int cpu_callback(
@@ -739,13 +1366,13 @@ static int __init psr_presmp_init(void)
         init_psr_cmt(opt_rmid_max);
 
     if ( opt_psr & PSR_CAT )
-        init_psr_cat();
+        init_psr();
 
     if ( psr_cpu_prepare(0) )
-        psr_cat_free();
+        psr_free();
 
     psr_cpu_init();
-    if ( psr_cmt_enabled() || cat_socket_info )
+    if ( psr_cmt_enabled() || socket_info )
         register_cpu_notifier(&cpu_nfb);
 
     return 0;
diff --git a/xen/arch/x86/sysctl.c b/xen/arch/x86/sysctl.c
index 14e7dc7..8e17a9a 100644
--- a/xen/arch/x86/sysctl.c
+++ b/xen/arch/x86/sysctl.c
@@ -176,15 +176,19 @@ 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 dat[3];
+            ret = psr_get_info(sysctl->u.psr_cat_op.target,
+                               PSR_MASK_TYPE_L3_CBM,
+                               dat, 3);
+            sysctl->u.psr_cat_op.u.l3_info.cbm_len = dat[0];
+            sysctl->u.psr_cat_op.u.l3_info.cos_max = dat[1];
+            sysctl->u.psr_cat_op.u.l3_info.flags   = dat[2];
 
             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/psr.h b/xen/include/asm-x86/psr.h
index 57f47e9..ef46d12 100644
--- a/xen/include/asm-x86/psr.h
+++ b/xen/include/asm-x86/psr.h
@@ -46,10 +46,10 @@ struct psr_cmt {
     struct psr_cmt_l3 l3;
 };
 
-enum cbm_type {
-    PSR_CBM_TYPE_L3,
-    PSR_CBM_TYPE_L3_CODE,
-    PSR_CBM_TYPE_L3_DATA,
+enum psr_val_type {
+    PSR_MASK_TYPE_L3_CBM,
+    PSR_MASK_TYPE_L3_CODE,
+    PSR_MASK_TYPE_L3_DATA,
 };
 
 extern struct psr_cmt *psr_cmt;
@@ -63,12 +63,12 @@ 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_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,
-                   uint64_t cbm, enum cbm_type type);
+int psr_get_info(unsigned int socket, enum psr_val_type type,
+                 uint32_t dat[], uint32_t array_len);
+int psr_get_val(struct domain *d, unsigned int socket,
+                uint64_t *val, enum psr_val_type type);
+int psr_set_val(struct domain *d, unsigned int socket,
+                uint64_t val, enum psr_val_type type);
 
 int psr_domain_init(struct domain *d);
 void psr_domain_free(struct domain *d);
