diff --git a/xen/arch/x86/domctl.c b/xen/arch/x86/domctl.c
index bed70aa..a51ed2c 100644
--- a/xen/arch/x86/domctl.c
+++ b/xen/arch/x86/domctl.c
@@ -1358,41 +1358,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..a77b55a 100644
--- a/xen/arch/x86/psr.c
+++ b/xen/arch/x86/psr.c
@@ -23,22 +23,116 @@
 #define PSR_CAT        (1<<1)
 #define PSR_CDP        (1<<2)
 
-struct psr_cat_cbm {
-    union {
-        uint64_t cbm;
-        struct {
-            uint64_t code;
-            uint64_t data;
-        };
-    };
+/*
+ * 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 internal_cpu_prepare(). Correspondingly, free them in
+ *    free_feature();
+ * 4. Add feature initialization codes in internal_cpu_init().
+ */
+
+struct feat_list;
+struct psr_socket_alloc_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 *pFeat,
+                         struct psr_socket_alloc_info *info);
+    /*
+     * get_old_set_new is used in set value process to get all features'
+     * COS registers values according to original cos id of the domain.
+     * Then, assemble them into an mask array as feature list order.
+     * Then, set the new feature value into feature corresponding position
+     * in the array. This function is used to pair with compare_mask.
+     */
+    int (*get_old_set_new)(uint64_t *mask,
+                           struct feat_list *pFeat,
+                           unsigned int old_cos,
+                           enum mask_type type,
+                           uint64_t m);
+    /*
+     * compare_mask is used to in set value process to compare if the
+     * input mask array can match all the features' COS registers values
+     * according to input cos id.
+     */
+    int (*compare_mask)(uint64_t *mask, struct feat_list *pFeat,
+                        unsigned int cos, bool_t *found);
+    /*
+     * get_cos_max_as_type is used to get the cos_max value of the feature
+     * according to input mask_type.
+     */
+    unsigned int (*get_cos_max_as_type)(struct feat_list *pFeat,
+                                        enum mask_type type);
+    /*
+     * exceed_range is used to check if the input cos id exceeds the
+     * feature's cos_max and if the input mask 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 is mask value is default one.
+     * If both criteria are fulfilled, that means the input exceeds the
+     * range.
+     */
+    unsigned int (*exceed_range)(uint64_t *mask, struct feat_list *pFeat,
+                                 unsigned int cos);
+    /*
+     * write_msr is used to write feature specific MSR registers.
+     */
+    int (*write_msr)(unsigned int cos, uint64_t *mask,
+                     struct feat_list *pFeat);
+    /*
+     * get_val is used to get feature specific COS register value.
+     */
+    int (*get_val)(struct feat_list *pFeat, unsigned int cos,
+                   enum mask_type type, uint64_t *val);
+    /*
+     * get_feat_info is used to get feature specific HW info.
+     */
+    int (*get_feat_info)(struct feat_list *pFeat, enum mask_type type,
+                         uint32_t *dat0, uint32_t *dat1,
+                         uint32_t *dat2);
+    /*
+     * get_max_cos_max is used to get feature's cos_max.
+     */
+    unsigned int (*get_max_cos_max)(struct feat_list *pFeat);
+};
+
+#define MAX_FEAT_INFO_SIZE 8
+#define MAX_COS_REG_NUM  128
+
+struct feat_list {
+    unsigned int feature;
+    struct feat_ops ops;
+    unsigned int feat_info[MAX_FEAT_INFO_SIZE];
+    uint64_t cos_reg_val[MAX_COS_REG_NUM];
+    struct feat_list *pNext;
+};
+
+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_alloc_info {
+    /*
+     * bit 1~0: [01]->L3 CAT-only, [10]->L3 CDP
+     */
+    unsigned int features;
+    unsigned int nr_feat;
+    struct feat_list *pFeat;
+    struct psr_ref *cos_ref;
+    spinlock_t mask_lock;
 };
 
 struct psr_assoc {
@@ -48,9 +142,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_alloc_info *__read_mostly socket_alloc_info;
 
 static unsigned int opt_psr;
 static unsigned int __initdata opt_rmid_max = 255;
@@ -58,8 +150,427 @@ 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. */
+struct feat_list *pL3CAT;
+
+/* Common functions for supporting feature callback functions. */
+static void add_feature(struct feat_list *pHead, struct feat_list *pTmp)
+{
+    if ( NULL == pHead || NULL == pTmp )
+        return;
+
+    while ( pHead->pNext )
+        pHead = pHead->pNext;
+
+    pHead->pNext = pTmp;
+}
+
+static void free_feature(struct psr_socket_alloc_info *info)
+{
+    struct feat_list *pTmp;
+    struct feat_list *pPrev;
+
+    if ( NULL == info )
+        return;
+
+    if ( NULL == info->pFeat )
+        return;
+
+    pTmp = info->pFeat->pNext;
+    while ( pTmp )
+    {
+        pPrev = pTmp;
+        pTmp = pTmp->pNext;
+        clear_bit(pPrev->feature, &(info->features));
+        xfree(pPrev);
+        pPrev = NULL;
+    }
+}
+
+static bool_t 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 0;
+
+    /* At least one bit need to be set. */
+    if ( cbm == 0 )
+        return 0;
+
+    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 0;
+
+    return 1;
+}
+
+/*
+ * Features specific implementations.
+ */
+
+/* CAT/CDP data structure and callback functions implementation. */
+struct psr_cat_lvl_info {
+    unsigned int cbm_len;
+    unsigned int cos_max;
+};
+
+static void l3_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 l3_cat;
+    unsigned int socket;
+    uint64_t val;
+
+    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;
+
+    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). */
+    pFeat->cos_reg_val[0] = (1ull << l3_cat.cbm_len) - 1;
+
+    pFeat->feature = PSR_SOCKET_L3_CAT;
+    set_bit(PSR_SOCKET_L3_CAT, &(info->features));
+
+    if ( (ecx & PSR_CAT_CDP_CAPABILITY) && (opt_psr & PSR_CDP) &&
+         !test_bit(PSR_SOCKET_L3_CDP, &(info->features)) )
+    {
+        /* Data */
+        pFeat->cos_reg_val[0] = (1ull << l3_cat.cbm_len) - 1;
+        /* Code */
+        pFeat->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;
+
+        pFeat->feature = PSR_SOCKET_L3_CDP;
+        set_bit(PSR_SOCKET_L3_CDP, &(info->features));
+        clear_bit(PSR_SOCKET_L3_CAT, &(info->features));
+    }
+
+    memcpy(pFeat->feat_info, &l3_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 "L3 CAT: enabled on socket %u, cos_max:%u, cbm_len:%u, CDP:%s\n",
+           socket, pFeat->feat_info[1], pFeat->feat_info[0],
+           test_bit(PSR_SOCKET_L3_CDP, &(info->features)) ? "on" : "off");
+}
+
+static int l3_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 l3_def_cbm;
+
+    memcpy(&cat_info, pFeat->feat_info, sizeof(struct psr_cat_lvl_info));
+    l3_def_cbm = (1ull << cat_info.cbm_len) - 1;
+
+    /* CDP */
+    if ( pFeat->feature == PSR_SOCKET_L3_CDP )
+    {
+        if ( cos > cat_info.cos_max )
+        {
+            if ( mask[0] != l3_def_cbm ||
+                 mask[1] != l3_def_cbm )
+            {
+                *found = 0;
+                printk(XENLOG_ERR "CDP exceed cos max.\n");
+                return -ENOENT;
+            }
+            *found = 1;
+            return 2;
+        }
+
+        if ( mask[0] == pFeat->cos_reg_val[cos * 2] &&
+             mask[1] == pFeat->cos_reg_val[cos * 2 + 1])
+            *found = 1;
+        else
+            *found = 0;
+
+        return 2;
+    }
+
+    /* CAT */
+    if ( cos > cat_info.cos_max )
+    {
+        if ( mask[0] != l3_def_cbm )
+        {
+            *found = 0;
+            printk(XENLOG_ERR "CAT exceed cos max.\n");
+            return -ENOENT;
+        }
+        *found = 1;
+        return 1;
+    }
+
+    if ( mask[0] == pFeat->cos_reg_val[cos] )
+        *found = 1;
+    else
+        *found = 0;
+
+    return 1;
+}
+
+static unsigned int l3_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_L3_DATA &&
+         type != PSR_MASK_TYPE_L3_CODE &&
+         type != PSR_MASK_TYPE_L3_CBM )
+        return 0;
+
+    memcpy(&cat_info, pFeat->feat_info, sizeof(struct psr_cat_lvl_info));
+    return cat_info.cos_max;
+}
+
+static unsigned int l3_cat_exceed_range(uint64_t *mask, struct feat_list *pFeat,
+                                        unsigned int cos)
+{
+    struct psr_cat_lvl_info cat_info;
+    uint64_t l3_def_cbm;
+
+    memcpy(&cat_info, pFeat->feat_info, sizeof(struct psr_cat_lvl_info));
+    l3_def_cbm = (1ull << cat_info.cbm_len) - 1;
+
+    /* CDP */
+    if ( pFeat->feature == PSR_SOCKET_L3_CDP )
+    {
+        if ( cos > cat_info.cos_max )
+            if ( mask[0] != l3_def_cbm ||
+                 mask[1] != l3_def_cbm )
+                /*
+                 * Exceed cos_max and value to set is not default,
+                 * return error.
+                 */
+                return 0;
+
+        return 2;
+    }
+
+    /* CAT */
+    if ( cos > cat_info.cos_max )
+        if ( mask[0] != l3_def_cbm )
+            /*
+             * Exceed cos_max and value to set is not default,
+             * return error.
+             */
+            return 0;
+
+    return 1;
+}
+
+static int l3_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));
+
+    /* CDP */
+    if ( pFeat->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 > cat_info.cos_max )
+            return 2;
+
+        /* Data */
+        pFeat->cos_reg_val[cos * 2] = mask[0];
+        /* Code */
+        pFeat->cos_reg_val[cos * 2 + 1] = mask[1];
+
+        wrmsrl(MSR_IA32_PSR_L3_MASK_DATA(cos), mask[0]);
+        wrmsrl(MSR_IA32_PSR_L3_MASK_CODE(cos), mask[1]);
+        return 2;
+    }
+
+    /* CAT */
+    if ( cos > cat_info.cos_max )
+        return 1;
+
+    pFeat->cos_reg_val[cos] = mask[0];
+    wrmsrl(MSR_IA32_PSR_L3_MASK(cos), mask[0]);
+    return 1;
+}
+
+static int l3_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));
+
+    if ( type == PSR_MASK_TYPE_L3_DATA ||
+         type == PSR_MASK_TYPE_L3_CODE ||
+         type == PSR_MASK_TYPE_L3_CBM )
+    {
+        if ( !psr_check_cbm(cat_info.cbm_len, m) )
+            return -EINVAL;
+    }
+
+    if ( ( type == PSR_MASK_TYPE_L3_DATA ||
+         type == PSR_MASK_TYPE_L3_CODE ) &&
+         pFeat->feature != PSR_SOCKET_L3_CDP )
+        return -ENXIO;
+
+    /* CDP */
+    if ( pFeat->feature == PSR_SOCKET_L3_CDP )
+    {
+        if ( old_cos > cat_info.cos_max )
+        {
+            /* Data */
+            mask[0] = pFeat->cos_reg_val[0];
+            /* Code */
+            mask[1] = pFeat->cos_reg_val[1];
+        }
+        else
+        {
+            /* Data */
+            mask[0] = pFeat->cos_reg_val[old_cos * 2];
+            /* Code */
+            mask[1] = pFeat->cos_reg_val[old_cos * 2 + 1];
+        }
+
+        /* Set new mask */
+        if ( type == PSR_MASK_TYPE_L3_DATA )
+            mask[0] = m;
+        if ( type == PSR_MASK_TYPE_L3_CODE )
+            mask[1] = m;
+
+        return 2;
+    }
+
+    /* 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_L3_CBM )
+        mask[0] = m;
+
+    return 1;
+}
+
+static int l3_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_L3_DATA &&
+         type != PSR_MASK_TYPE_L3_CODE &&
+         type != PSR_MASK_TYPE_L3_CBM )
+         return 0;
+
+    if ( ( type == PSR_MASK_TYPE_L3_DATA ||
+         type == PSR_MASK_TYPE_L3_CODE ) &&
+         pFeat->feature != PSR_SOCKET_L3_CDP )
+        return -ENXIO;
+
+    memcpy(&cat_info, pFeat->feat_info, sizeof(struct psr_cat_lvl_info));
+
+    /* CDP */
+    if ( pFeat->feature == PSR_SOCKET_L3_CDP )
+    {
+        if ( cos > cat_info.cos_max )
+            *val = pFeat->cos_reg_val[0];
+        else if ( type == PSR_MASK_TYPE_L3_DATA )
+            *val = pFeat->cos_reg_val[cos * 2];
+        else if ( type == PSR_MASK_TYPE_L3_CODE )
+            *val = pFeat->cos_reg_val[cos * 2 + 1];
+
+        return 1;
+    }
+
+    /* CAT */
+    if ( cos > cat_info.cos_max )
+        *val =  pFeat->cos_reg_val[0];
+    else
+        *val =  pFeat->cos_reg_val[cos];
+
+    return 1;
+}
+
+static int l3_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_L3_DATA &&
+         type != PSR_MASK_TYPE_L3_CODE &&
+         type != PSR_MASK_TYPE_L3_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;
+
+    if ( pFeat->feature == PSR_SOCKET_L3_CDP )
+        *dat2 |= XEN_SYSCTL_PSR_CAT_L3_CDP;
+    else
+        *dat2 = 0;
+
+    return 1;
+}
+
+static unsigned int l3_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 l3_cat_ops = {
+    .init_feature = l3_cat_init_feature,
+    .get_old_set_new = l3_cat_get_old_set_new,
+    .compare_mask = l3_cat_compare_mask,
+    .get_cos_max_as_type = l3_cat_get_cos_max_as_type,
+    .exceed_range = l3_cat_exceed_range,
+    .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 +720,39 @@ void psr_free_rmid(struct domain *d)
     d->arch.psr_rmid = 0;
 }
 
+static inline unsigned int get_max_cos_max(struct psr_socket_alloc_info *info)
+{
+    struct feat_list *pTmp;
+    unsigned int cos_max = 0;
+
+    if ( NULL == info->pFeat || NULL == info->pFeat->pNext )
+        return 0;
+
+    pTmp = info->pFeat->pNext;
+    while ( pTmp )
+    {
+        cos_max = max(pTmp->ops.get_max_cos_max(pTmp), cos_max);
+        pTmp = pTmp->pNext;
+    }
+
+    return cos_max;
+}
+
 static inline void psr_assoc_init(void)
 {
     struct psr_assoc *psra = &this_cpu(psr_assoc);
+    struct psr_socket_alloc_info *info;
+    unsigned int cos_max;
+    unsigned int socket;
 
-    if ( cat_socket_info )
+    if ( socket_alloc_info )
     {
-        unsigned int socket = cpu_to_socket(smp_processor_id());
+        socket = cpu_to_socket(smp_processor_id());
+        info = socket_alloc_info + socket;
+        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 +789,359 @@ 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_alloc_info *get_socket_alloc_info(unsigned int socket)
 {
-    if ( !cat_socket_info )
+    struct psr_socket_alloc_info *info;
+
+    if ( !socket_alloc_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_alloc_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 mask_type type,
+                 uint32_t *dat0, uint32_t *dat1,
+                 uint32_t *dat2)
 {
-    struct psr_cat_socket_info *info = get_cat_socket_info(socket);
+    struct psr_socket_alloc_info *info = get_socket_alloc_info(socket);
+    struct feat_list *pTmp;
 
     if ( IS_ERR(info) )
         return PTR_ERR(info);
 
-    *cbm_len = info->cbm_len;
-    *cos_max = info->cos_max;
+    if ( NULL == info->pFeat || NULL == info->pFeat->pNext)
+       return -ENODEV;
 
-    *flags = 0;
-    if ( cdp_is_enabled(socket) )
-        *flags |= XEN_SYSCTL_PSR_CAT_L3_CDP;
+    pTmp = info->pFeat->pNext;
+    while ( pTmp )
+    {
+        if ( pTmp->ops.get_feat_info(pTmp, type, dat0, dat1, dat2) )
+            return 0;
 
-    return 0;
+        pTmp = pTmp->pNext;
+    }
+
+    return -ENODEV;
 }
 
-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 *mask,
+                           struct psr_socket_alloc_info *info,
+                           unsigned int old_cos,
+                           enum mask_type type,
+                           uint64_t m)
 {
-    struct psr_cat_socket_info *info = get_cat_socket_info(socket);
-    bool_t cdp_enabled = cdp_is_enabled(socket);
-
-    if ( IS_ERR(info) )
-        return PTR_ERR(info);
+    struct feat_list *pTmp;
+    int ret;
 
-    switch ( type )
-    {
-    case PSR_CBM_TYPE_L3:
-        if ( cdp_enabled )
-            return -EXDEV;
-        *cbm = info->cos_to_cbm[d->arch.psr_cos_ids[socket]].cbm;
-        break;
+    if ( !mask )
+        return -EINVAL;
 
-    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;
+    if ( !info || !info->pFeat )
+        return -ENODEV;
 
-    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;
+    pTmp = info->pFeat->pNext;
+    while ( pTmp )
+    {
+        /* mask getting and setting order is same as feature list */
+        ret = pTmp->ops.get_old_set_new(mask, pTmp, old_cos, type, m);
+        if ( ret < 0 )
+            return ret;
 
-    default:
-        ASSERT_UNREACHABLE();
+        mask += ret;
+        pTmp = pTmp->pNext;
     }
 
     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 mask_type type)
 {
-    unsigned int first_bit, zero_bit;
-
-    /* Set bits should only in the range of [0, cbm_len). */
-    if ( cbm & (~0ull << cbm_len) )
-        return 0;
+    struct psr_socket_alloc_info *info = get_socket_alloc_info(socket);
+    unsigned int cos = d->arch.psr_cos_ids[socket];
+    struct feat_list *pTmp;
+    int ret;
 
-    /* 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);
+    if ( NULL == info->pFeat || NULL == info->pFeat->pNext )
+        return -ENODEV;
 
-    /* Set bits should be contiguous. */
-    if ( zero_bit < cbm_len &&
-         find_next_bit(&cbm, cbm_len, zero_bit) < cbm_len )
-        return 0;
+    pTmp = info->pFeat->pNext;
+    while ( pTmp )
+    {
+        ret = pTmp->ops.get_val(pTmp, cos, type, val);
+        if ( ret < 0 )
+            return -EINVAL;
+        else if ( ret > 0 )
+            /* Found */
+            break;
+
+        pTmp = pTmp->pNext;
+    }
 
-    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 feat_list *pFeat;
+    uint64_t *mask;
 };
 
-static void do_write_l3_cbm(void *data)
+static void do_write_psr_ref(void *data)
 {
-    struct cos_cbm_info *info = data;
+    struct cos_mask_info *info = (struct cos_mask_info *)data;
+    unsigned int cos           = info->cos;
+    struct feat_list *pFeat    = info->pFeat;
+    uint64_t *mask             = info->mask;
+    struct feat_list *pTmp;
+    int ret;
+
+    if ( NULL == pFeat || NULL == pFeat->pNext)
+        return;
 
-    if ( info->cdp )
+    pTmp = pFeat->pNext;
+    while ( pTmp )
     {
-        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 = pTmp->ops.write_msr(cos, mask, pTmp);
+        if ( ret <= 0)
+            return;
+
+        mask += ret;
+        pTmp = pTmp->pNext;
     }
-    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_ref(unsigned int socket, unsigned int cos,
+                          uint64_t *mask)
 {
-    struct cos_cbm_info info =
+    struct psr_socket_alloc_info *info = get_socket_alloc_info(socket);
+
+    struct cos_mask_info data =
     {
         .cos = cos,
-        .cbm_code = cbm_code,
-        .cbm_data = cbm_data,
-        .cdp = cdp,
+        .pFeat = info->pFeat,
+        .mask = mask,
     };
 
     if ( socket == cpu_to_socket(smp_processor_id()) )
-        do_write_l3_cbm(&info);
+        do_write_psr_ref(&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_ref, &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(uint64_t *mask, enum mask_type type,
+                    struct psr_socket_alloc_info *info)
 {
     unsigned int cos;
+    struct psr_ref *map = info->cos_ref;
+    struct feat_list *pTmp;
+    uint64_t *pMask = mask;
+    int ret;
+    bool_t found = 0;
+    unsigned int cos_max = 0;
+
+    /* cos_max is the max COS of the feature to be set. */
+    pTmp = info->pFeat->pNext;
+    while ( pTmp )
+    {
+        cos_max = pTmp->ops.get_cos_max_as_type(pTmp, type);
+        if ( cos_max > 0 )
+            break;
+
+        pTmp = pTmp->pNext;
+    }
 
+    pTmp = info->pFeat->pNext;
     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;
+
+        while ( pTmp )
+        {
+            /*
+             * Compare mask according to feature list order.
+             * We must follow this order because mask is assembled
+             * as this order in get_old_set_new().
+             */
+            ret = pTmp->ops.compare_mask(pMask, pTmp, cos, &found);
+            if ( ret < 0 )
+                return ret;
+
+            /* If fail to match, go to next cos to compare. */
+            if ( !found )
+                break;
+
+            pMask += ret;
+            pTmp = pTmp->pNext;
+        }
+
+        /* Every feature can match, this cos is what we find. */
+        if ( found )
             return cos;
+
+        /* Not found, need find again from beginning. */
+        pTmp = info->pFeat->pNext;
+        pMask = mask;
     }
 
+    printk(XENLOG_INFO "%s: cannot find cos.\n", __func__);
     return -ENOENT;
 }
 
-static int pick_avail_cos(struct psr_cat_cbm *map, unsigned int cos_max,
-                          unsigned int old_cos)
+static int check_exceed_range(uint64_t *mask, struct feat_list *pTmp,
+                              unsigned int cos)
 {
+    unsigned int ret = 0;
+
+    while ( pTmp )
+    {
+        ret = pTmp->ops.exceed_range(mask, pTmp, cos);
+        if ( 0 == ret )
+            return -ENOENT;
+
+        mask += ret;
+        pTmp = pTmp->pNext;
+    }
+
+    return 0;
+}
+
+static int alloc_new_cos(struct psr_socket_alloc_info *info,
+                         uint64_t *mask, unsigned int old_cos,
+                         enum mask_type type)
+{
+    unsigned int cos_max = 0;
+    struct feat_list *pTmp;
     unsigned int cos;
+    struct psr_ref *map = info->cos_ref;
+
+    /*
+     * cos_max is the max COS of the feature to be set.
+     */
+    pTmp = info->pFeat->pNext;
+    while ( pTmp )
+    {
+        cos_max = pTmp->ops.get_cos_max_as_type(pTmp, type);
+        if ( cos_max > 0 )
+            break;
+
+        pTmp = pTmp->pNext;
+    }
+
+    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 )
+    {
+        pTmp = info->pFeat->pNext;
+        if ( check_exceed_range(mask, pTmp, old_cos) )
+            goto find_new;
+
         return old_cos;
+    }
 
+find_new:
     /* 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 )
+        {
+            pTmp = info->pFeat->pNext;
+            if ( check_exceed_range(mask, pTmp, cos) )
+                return -ENOENT;
+
             return cos;
+        }
 
+    printk(XENLOG_INFO "%s: all COSs have been occupied.\n", __func__);
     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 mask_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 *mask;
+    struct psr_socket_alloc_info *info = get_socket_alloc_info(socket);
 
     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;
 
-    default:
-        ASSERT_UNREACHABLE();
-        return -EINVAL;
-    }
+    /* Considering CDP liking features */
+    mask = xzalloc_array(uint64_t, info->nr_feat * 2);
+    if ( (ret = get_old_set_new(mask, 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(mask, type, info);
     if ( cos >= 0 )
     {
         if ( cos == old_cos )
         {
-            spin_unlock(&info->cbm_lock);
+            spin_unlock(&info->mask_lock);
+            xfree(mask);
             return 0;
         }
     }
     else
     {
-        cos = pick_avail_cos(map, cos_max, old_cos);
+        cos = alloc_new_cos(info, mask, old_cos, type);
         if ( cos < 0 )
         {
-            spin_unlock(&info->cbm_lock);
+            spin_unlock(&info->mask_lock);
+            xfree(mask);
             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 mask MSRs corresponding to the COS */
+        ret = write_psr_ref(socket, cos, mask);
+        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(mask);
+            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(mask);
+    mask = NULL;
 
     return 0;
 }
@@ -529,20 +1151,23 @@ static void psr_free_cos(struct domain *d)
 {
     unsigned int socket;
     unsigned int cos;
-    struct psr_cat_socket_info *info;
+    struct psr_socket_alloc_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_alloc_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 +1176,7 @@ static void psr_free_cos(struct domain *d)
 
 int psr_domain_init(struct domain *d)
 {
-    if ( cat_socket_info )
+    if ( socket_alloc_info )
     {
         d->arch.psr_cos_ids = xzalloc_array(unsigned int, nr_sockets);
         if ( !d->arch.psr_cos_ids )
@@ -567,137 +1192,147 @@ void psr_domain_free(struct domain *d)
     psr_free_cos(d);
 }
 
-static int cat_cpu_prepare(unsigned int cpu)
+static int internal_cpu_prepare(unsigned int cpu)
 {
-    if ( !cat_socket_info )
+    if ( !socket_alloc_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 ( pL3CAT == NULL &&
+         (pL3CAT = xzalloc(struct feat_list)) == NULL )
+        return -ENOMEM;
+
     return 0;
 }
 
-static void cat_cpu_init(void)
+static void internal_cpu_init(void)
 {
     unsigned int eax, ebx, ecx, edx;
-    struct psr_cat_socket_info *info;
+    struct psr_socket_alloc_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 *pTmp;
 
     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_alloc_info + socket;
+    if ( info->features )
         return;
 
     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;
+        pTmp = pL3CAT;
+        if ( !pTmp )
+            return;
+        pL3CAT = 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);
+        pTmp->ops = l3_cat_ops;
+        pTmp->ops.init_feature(eax, ebx, ecx, edx, pTmp, info);
     }
 }
 
-static void cat_cpu_fini(unsigned int cpu)
+static void internal_cpu_fini(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_alloc_info *info = get_socket_alloc_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;
+    int i;
+
+    for ( i = 0; i < nr_sockets; i++ )
+    {
+        free_feature(&socket_alloc_info[i]);
+        xfree(socket_alloc_info[i].pFeat);
+        socket_alloc_info[i].pFeat = NULL;
+    }
+
+    xfree(socket_alloc_info);
+    socket_alloc_info = NULL;
 }
 
-static void __init init_psr_cat(void)
+static void __init init_psr(void)
 {
+    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_alloc_info = xzalloc_array(struct psr_socket_alloc_info, nr_sockets);
+
+    if ( !socket_alloc_info )
+    {
+        printk(XENLOG_INFO "Fail to alloc socket_alloc_info!\n");
+        return;
+    }
 
-    if ( !cat_socket_enable || !cat_socket_info )
-        psr_cat_free();
+    for ( i = 0; i < nr_sockets; i++ )
+    {
+        socket_alloc_info[i].pFeat =  xzalloc(struct feat_list);
+        if ( NULL == socket_alloc_info[i].pFeat )
+        {
+            printk(XENLOG_INFO "Fail to alloc pFeat!\n");
+            return;
+        }
+        socket_alloc_info[i].pFeat->pNext = NULL;
+    }
 }
 
 static int psr_cpu_prepare(unsigned int cpu)
 {
-    return cat_cpu_prepare(cpu);
+    return internal_cpu_prepare(cpu);
 }
 
 static void psr_cpu_init(void)
 {
-    if ( cat_socket_info )
-        cat_cpu_init();
+    unsigned int socket;
+    struct psr_socket_alloc_info *info;
+
+    if ( socket_alloc_info )
+    {
+        socket = cpu_to_socket(smp_processor_id());
+        info = socket_alloc_info + socket;
+        info->cos_ref = temp_cos_ref;
+        temp_cos_ref = NULL;
+        spin_lock_init(&info->mask_lock);
+
+        internal_cpu_init();
+    }
 
     psr_assoc_init();
 }
 
 static void psr_cpu_fini(unsigned int cpu)
 {
-    if ( cat_socket_info )
-        cat_cpu_fini(cpu);
+    if ( socket_alloc_info )
+        internal_cpu_fini(cpu);
 }
 
 static int cpu_callback(
@@ -739,13 +1374,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_alloc_info )
         register_cpu_notifier(&cpu_nfb);
 
     return 0;
diff --git a/xen/arch/x86/sysctl.c b/xen/arch/x86/sysctl.c
index 14e7dc7..a143e7a 100644
--- a/xen/arch/x86/sysctl.c
+++ b/xen/arch/x86/sysctl.c
@@ -176,10 +176,11 @@ 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);
+            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);
 
             if ( !ret && __copy_field_to_guest(u_sysctl, sysctl, u.psr_cat_op) )
                 ret = -EFAULT;
diff --git a/xen/include/asm-x86/psr.h b/xen/include/asm-x86/psr.h
index 57f47e9..0993863 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 mask_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,13 @@ 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 mask_type type,
+                 uint32_t *dat0, uint32_t *dat1,
+                 uint32_t *dat2);
+int psr_get_val(struct domain *d, unsigned int socket,
+                uint64_t *val, enum mask_type type);
+int psr_set_val(struct domain *d, unsigned int socket,
+                uint64_t val, enum mask_type type);
 
 int psr_domain_init(struct domain *d);
 void psr_domain_free(struct domain *d);
