diff --git a/xen/arch/x86/psr.c b/xen/arch/x86/psr.c
index 38a64f0..750278c 100644
--- a/xen/arch/x86/psr.c
+++ b/xen/arch/x86/psr.c
@@ -32,6 +32,21 @@ enum psr_feat_type {
     PSR_SOCKET_L3_CDP,
 };
 
+struct feat_node;
+struct psr_cat_socket_info;
+
+/* Every feature enabled MUST 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_node *feat,
+                         struct psr_cat_socket_info *info);
+};
+
 /* CAT/CDP HW info data structure. */
 struct psr_cat_hw_info {
     unsigned int cbm_len;
@@ -41,6 +56,8 @@ struct psr_cat_hw_info {
 struct feat_node {
     /* Which feature it is. */
     enum psr_feat_type feature;
+    /* Feature operation callback functions. */
+    struct feat_ops ops;
     /* Feature HW info. */
     struct psr_cat_hw_info info;
     /*
@@ -133,6 +150,69 @@ static void free_feature(struct psr_cat_socket_info *info)
     }
 }
 
+/* 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_node *feat,
+                                struct psr_cat_socket_info *info)
+{
+    struct psr_cat_hw_info l3_cat;
+    unsigned int socket;
+    uint64_t val;
+
+    /* No valid value so do not enable feature. */
+    if ( !eax || !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;
+
+    if ( (ecx & PSR_CAT_CDP_CAPABILITY) && (opt_psr & PSR_CDP) &&
+         !test_bit(PSR_SOCKET_L3_CDP, &info->feat_mask) )
+    {
+        /* CODE */
+        get_cdp_code(feat, 0) =
+                     (1ull << l3_cat.cbm_len) - 1;
+        /* DATA */
+        get_cdp_data(feat, 0) =
+                     (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->feat_mask);
+    } else {
+        feat->feature = PSR_SOCKET_L3_CAT;
+        __set_bit(PSR_SOCKET_L3_CAT, &info->feat_mask);
+    }
+
+    feat->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.cos_max, feat->info.cbm_len,
+           test_bit(PSR_SOCKET_L3_CDP, &info->feat_mask) ? "on" : "off");
+}
+
+struct feat_ops l3_cat_ops = {
+    .init_feature = l3_cat_init_feature,
+};
+
 static unsigned int get_socket_cpu(unsigned int socket)
 {
     if ( likely(socket < nr_sockets) )
@@ -683,7 +763,6 @@ static void cat_cpu_init(void)
     struct psr_cat_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_node *feat_tmp;
 
@@ -695,6 +774,8 @@ static void cat_cpu_init(void)
     if ( info->feat_mask )
         return;
 
+    spin_lock_init(&info->ref_lock);
+
     cpuid_count(PSR_CPUID_LEVEL_CAT, 0, &eax, &ebx, &ecx, &edx);
     if ( ebx & PSR_RESOURCE_TYPE_L3 )
     {
@@ -702,44 +783,8 @@ static void cat_cpu_init(void)
         feat_l3 = NULL;
 
         cpuid_count(PSR_CPUID_LEVEL_CAT, 1, &eax, &ebx, &ecx, &edx);
-        feat_tmp->info.cbm_len = (eax & 0x1f) + 1;
-        feat_tmp->info.cos_max = min(opt_cos_max, edx & 0xffff);
-
-        /* cos=0 is reserved as default cbm(all ones). */
-        feat_tmp->cos_reg_val[0] = (1ull << feat_tmp->info.cbm_len) - 1;
-
-        spin_lock_init(&info->ref_lock);
-
-        if ( (ecx & PSR_CAT_CDP_CAPABILITY) && (opt_psr & PSR_CDP) &&
-             !test_bit(PSR_SOCKET_L3_CDP, &info->feat_mask) )
-        {
-            /* CODE */
-            get_cdp_code(feat_tmp, 0) = (1ull << feat_tmp->info.cbm_len) - 1;
-            /* DATA */
-            get_cdp_data(feat_tmp, 0) = (1ull << feat_tmp->info.cbm_len) - 1;
-
-            /* We only write mask1 since mask0 is always all ones by default. */
-            wrmsrl(MSR_IA32_PSR_L3_MASK(1), (1ull << feat_tmp->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. */
-            feat_tmp->info.cos_max >>= 1;
-
-            __set_bit(PSR_SOCKET_L3_CDP, &info->feat_mask);
-        } else {
-            feat_tmp->feature = PSR_SOCKET_L3_CAT;
-            __set_bit(PSR_SOCKET_L3_CAT, &info->feat_mask);
-        }
-
-        info->nr_feat++;
-        /* Add this feature into list. */
-        list_add_tail(&feat_tmp->list, &info->feat_list);
-
-        printk(XENLOG_INFO "CAT: enabled on socket %u, cos_max:%u, cbm_len:%u, CDP:%s\n",
-               socket, feat_tmp->info.cos_max, feat_tmp->info.cbm_len,
-               cdp_is_enabled(socket) ? "on" : "off");
+        feat_tmp->ops = l3_cat_ops;
+        feat_tmp->ops.init_feature(eax, ebx, ecx, edx, feat_tmp, info);
     }
 }
 
