aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel
diff options
context:
space:
mode:
authorBorislav Petkov <borislav.petkov@amd.com>2012-08-01 09:38:18 -0400
committerH. Peter Anvin <hpa@linux.intel.com>2012-08-22 19:16:21 -0400
commita3eb3b4da106a23b5d41bf915726172e31654a65 (patch)
treeeb8192823f4b15184eb631902aa785bb8195fbe7 /arch/x86/kernel
parentc96d2c0905cc48e34f2b37b775b59932c416b343 (diff)
x86, microcode, AMD: Add a small, per-family patches cache
This is a trivial cache which collects all ucode patches for the current family of CPUs on the system. If a newer patch appears due to the container file being updated in userspace, we replace our cached version with the new one. Signed-off-by: Borislav Petkov <borislav.petkov@amd.com> Link: http://lkml.kernel.org/r/1344361461-10076-12-git-send-email-bp@amd64.org Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
Diffstat (limited to 'arch/x86/kernel')
-rw-r--r--arch/x86/kernel/microcode_amd.c67
1 files changed, 66 insertions, 1 deletions
diff --git a/arch/x86/kernel/microcode_amd.c b/arch/x86/kernel/microcode_amd.c
index 03ed5af7053d..cacdc9a5ee49 100644
--- a/arch/x86/kernel/microcode_amd.c
+++ b/arch/x86/kernel/microcode_amd.c
@@ -78,12 +78,22 @@ static struct equiv_cpu_entry *equiv_cpu_table;
78/* page-sized ucode patch buffer */ 78/* page-sized ucode patch buffer */
79void *patch; 79void *patch;
80 80
81struct ucode_patch {
82 struct list_head plist;
83 void *data;
84 u32 patch_id;
85 u16 equiv_cpu;
86};
87
88static LIST_HEAD(pcache);
89
81static u16 find_equiv_id(unsigned int cpu) 90static u16 find_equiv_id(unsigned int cpu)
82{ 91{
83 struct ucode_cpu_info *uci = ucode_cpu_info + cpu; 92 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
84 int i = 0; 93 int i = 0;
85 94
86 BUG_ON(equiv_cpu_table == NULL); 95 if (!equiv_cpu_table)
96 return 0;
87 97
88 while (equiv_cpu_table[i].installed_cpu != 0) { 98 while (equiv_cpu_table[i].installed_cpu != 0) {
89 if (uci->cpu_sig.sig == equiv_cpu_table[i].installed_cpu) 99 if (uci->cpu_sig.sig == equiv_cpu_table[i].installed_cpu)
@@ -108,6 +118,61 @@ static u32 find_cpu_family_by_equiv_cpu(u16 equiv_cpu)
108 return 0; 118 return 0;
109} 119}
110 120
121/*
122 * a small, trivial cache of per-family ucode patches
123 */
124static struct ucode_patch *cache_find_patch(u16 equiv_cpu)
125{
126 struct ucode_patch *p;
127
128 list_for_each_entry(p, &pcache, plist)
129 if (p->equiv_cpu == equiv_cpu)
130 return p;
131 return NULL;
132}
133
134static void update_cache(struct ucode_patch *new_patch)
135{
136 struct ucode_patch *p;
137
138 list_for_each_entry(p, &pcache, plist) {
139 if (p->equiv_cpu == new_patch->equiv_cpu) {
140 if (p->patch_id >= new_patch->patch_id)
141 /* we already have the latest patch */
142 return;
143
144 list_replace(&p->plist, &new_patch->plist);
145 kfree(p->data);
146 kfree(p);
147 return;
148 }
149 }
150 /* no patch found, add it */
151 list_add_tail(&new_patch->plist, &pcache);
152}
153
154static void free_cache(void)
155{
156 struct ucode_patch *p;
157
158 list_for_each_entry_reverse(p, &pcache, plist) {
159 __list_del(p->plist.prev, p->plist.next);
160 kfree(p->data);
161 kfree(p);
162 }
163}
164
165static struct ucode_patch *find_patch(unsigned int cpu)
166{
167 u16 equiv_id;
168
169 equiv_id = find_equiv_id(cpu);
170 if (!equiv_id)
171 return NULL;
172
173 return cache_find_patch(equiv_id);
174}
175
111static int collect_cpu_info_amd(int cpu, struct cpu_signature *csig) 176static int collect_cpu_info_amd(int cpu, struct cpu_signature *csig)
112{ 177{
113 struct cpuinfo_x86 *c = &cpu_data(cpu); 178 struct cpuinfo_x86 *c = &cpu_data(cpu);