diff options
author | Borislav Petkov <borislav.petkov@amd.com> | 2012-08-01 09:38:18 -0400 |
---|---|---|
committer | H. Peter Anvin <hpa@linux.intel.com> | 2012-08-22 19:16:21 -0400 |
commit | a3eb3b4da106a23b5d41bf915726172e31654a65 (patch) | |
tree | eb8192823f4b15184eb631902aa785bb8195fbe7 /arch/x86/kernel | |
parent | c96d2c0905cc48e34f2b37b775b59932c416b343 (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.c | 67 |
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 */ |
79 | void *patch; | 79 | void *patch; |
80 | 80 | ||
81 | struct ucode_patch { | ||
82 | struct list_head plist; | ||
83 | void *data; | ||
84 | u32 patch_id; | ||
85 | u16 equiv_cpu; | ||
86 | }; | ||
87 | |||
88 | static LIST_HEAD(pcache); | ||
89 | |||
81 | static u16 find_equiv_id(unsigned int cpu) | 90 | static 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 | */ | ||
124 | static 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 | |||
134 | static 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 | |||
154 | static 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 | |||
165 | static 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 | |||
111 | static int collect_cpu_info_amd(int cpu, struct cpu_signature *csig) | 176 | static 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); |