diff options
Diffstat (limited to 'arch/i386/kernel/cpu/mtrr/main.c')
-rw-r--r-- | arch/i386/kernel/cpu/mtrr/main.c | 71 |
1 files changed, 50 insertions, 21 deletions
diff --git a/arch/i386/kernel/cpu/mtrr/main.c b/arch/i386/kernel/cpu/mtrr/main.c index fff90bda4733..16bb7ea87145 100644 --- a/arch/i386/kernel/cpu/mtrr/main.c +++ b/arch/i386/kernel/cpu/mtrr/main.c | |||
@@ -59,7 +59,11 @@ struct mtrr_ops * mtrr_if = NULL; | |||
59 | static void set_mtrr(unsigned int reg, unsigned long base, | 59 | static void set_mtrr(unsigned int reg, unsigned long base, |
60 | unsigned long size, mtrr_type type); | 60 | unsigned long size, mtrr_type type); |
61 | 61 | ||
62 | #ifndef CONFIG_X86_64 | ||
62 | extern int arr3_protected; | 63 | extern int arr3_protected; |
64 | #else | ||
65 | #define arr3_protected 0 | ||
66 | #endif | ||
63 | 67 | ||
64 | void set_mtrr_ops(struct mtrr_ops * ops) | 68 | void set_mtrr_ops(struct mtrr_ops * ops) |
65 | { | 69 | { |
@@ -168,6 +172,13 @@ static void ipi_handler(void *info) | |||
168 | 172 | ||
169 | #endif | 173 | #endif |
170 | 174 | ||
175 | static inline int types_compatible(mtrr_type type1, mtrr_type type2) { | ||
176 | return type1 == MTRR_TYPE_UNCACHABLE || | ||
177 | type2 == MTRR_TYPE_UNCACHABLE || | ||
178 | (type1 == MTRR_TYPE_WRTHROUGH && type2 == MTRR_TYPE_WRBACK) || | ||
179 | (type1 == MTRR_TYPE_WRBACK && type2 == MTRR_TYPE_WRTHROUGH); | ||
180 | } | ||
181 | |||
171 | /** | 182 | /** |
172 | * set_mtrr - update mtrrs on all processors | 183 | * set_mtrr - update mtrrs on all processors |
173 | * @reg: mtrr in question | 184 | * @reg: mtrr in question |
@@ -263,8 +274,8 @@ static void set_mtrr(unsigned int reg, unsigned long base, | |||
263 | 274 | ||
264 | /** | 275 | /** |
265 | * mtrr_add_page - Add a memory type region | 276 | * mtrr_add_page - Add a memory type region |
266 | * @base: Physical base address of region in pages (4 KB) | 277 | * @base: Physical base address of region in pages (in units of 4 kB!) |
267 | * @size: Physical size of region in pages (4 KB) | 278 | * @size: Physical size of region in pages (4 kB) |
268 | * @type: Type of MTRR desired | 279 | * @type: Type of MTRR desired |
269 | * @increment: If this is true do usage counting on the region | 280 | * @increment: If this is true do usage counting on the region |
270 | * | 281 | * |
@@ -300,11 +311,9 @@ static void set_mtrr(unsigned int reg, unsigned long base, | |||
300 | int mtrr_add_page(unsigned long base, unsigned long size, | 311 | int mtrr_add_page(unsigned long base, unsigned long size, |
301 | unsigned int type, char increment) | 312 | unsigned int type, char increment) |
302 | { | 313 | { |
303 | int i; | 314 | int i, replace, error; |
304 | mtrr_type ltype; | 315 | mtrr_type ltype; |
305 | unsigned long lbase; | 316 | unsigned long lbase, lsize; |
306 | unsigned int lsize; | ||
307 | int error; | ||
308 | 317 | ||
309 | if (!mtrr_if) | 318 | if (!mtrr_if) |
310 | return -ENXIO; | 319 | return -ENXIO; |
@@ -324,12 +333,18 @@ int mtrr_add_page(unsigned long base, unsigned long size, | |||
324 | return -ENOSYS; | 333 | return -ENOSYS; |
325 | } | 334 | } |
326 | 335 | ||
336 | if (!size) { | ||
337 | printk(KERN_WARNING "mtrr: zero sized request\n"); | ||
338 | return -EINVAL; | ||
339 | } | ||
340 | |||
327 | if (base & size_or_mask || size & size_or_mask) { | 341 | if (base & size_or_mask || size & size_or_mask) { |
328 | printk(KERN_WARNING "mtrr: base or size exceeds the MTRR width\n"); | 342 | printk(KERN_WARNING "mtrr: base or size exceeds the MTRR width\n"); |
329 | return -EINVAL; | 343 | return -EINVAL; |
330 | } | 344 | } |
331 | 345 | ||
332 | error = -EINVAL; | 346 | error = -EINVAL; |
347 | replace = -1; | ||
333 | 348 | ||
334 | /* No CPU hotplug when we change MTRR entries */ | 349 | /* No CPU hotplug when we change MTRR entries */ |
335 | lock_cpu_hotplug(); | 350 | lock_cpu_hotplug(); |
@@ -337,21 +352,28 @@ int mtrr_add_page(unsigned long base, unsigned long size, | |||
337 | mutex_lock(&mtrr_mutex); | 352 | mutex_lock(&mtrr_mutex); |
338 | for (i = 0; i < num_var_ranges; ++i) { | 353 | for (i = 0; i < num_var_ranges; ++i) { |
339 | mtrr_if->get(i, &lbase, &lsize, <ype); | 354 | mtrr_if->get(i, &lbase, &lsize, <ype); |
340 | if (base >= lbase + lsize) | 355 | if (!lsize || base > lbase + lsize - 1 || base + size - 1 < lbase) |
341 | continue; | ||
342 | if ((base < lbase) && (base + size <= lbase)) | ||
343 | continue; | 356 | continue; |
344 | /* At this point we know there is some kind of overlap/enclosure */ | 357 | /* At this point we know there is some kind of overlap/enclosure */ |
345 | if ((base < lbase) || (base + size > lbase + lsize)) { | 358 | if (base < lbase || base + size - 1 > lbase + lsize - 1) { |
359 | if (base <= lbase && base + size - 1 >= lbase + lsize - 1) { | ||
360 | /* New region encloses an existing region */ | ||
361 | if (type == ltype) { | ||
362 | replace = replace == -1 ? i : -2; | ||
363 | continue; | ||
364 | } | ||
365 | else if (types_compatible(type, ltype)) | ||
366 | continue; | ||
367 | } | ||
346 | printk(KERN_WARNING | 368 | printk(KERN_WARNING |
347 | "mtrr: 0x%lx000,0x%lx000 overlaps existing" | 369 | "mtrr: 0x%lx000,0x%lx000 overlaps existing" |
348 | " 0x%lx000,0x%x000\n", base, size, lbase, | 370 | " 0x%lx000,0x%lx000\n", base, size, lbase, |
349 | lsize); | 371 | lsize); |
350 | goto out; | 372 | goto out; |
351 | } | 373 | } |
352 | /* New region is enclosed by an existing region */ | 374 | /* New region is enclosed by an existing region */ |
353 | if (ltype != type) { | 375 | if (ltype != type) { |
354 | if (type == MTRR_TYPE_UNCACHABLE) | 376 | if (types_compatible(type, ltype)) |
355 | continue; | 377 | continue; |
356 | printk (KERN_WARNING "mtrr: type mismatch for %lx000,%lx000 old: %s new: %s\n", | 378 | printk (KERN_WARNING "mtrr: type mismatch for %lx000,%lx000 old: %s new: %s\n", |
357 | base, size, mtrr_attrib_to_str(ltype), | 379 | base, size, mtrr_attrib_to_str(ltype), |
@@ -364,10 +386,18 @@ int mtrr_add_page(unsigned long base, unsigned long size, | |||
364 | goto out; | 386 | goto out; |
365 | } | 387 | } |
366 | /* Search for an empty MTRR */ | 388 | /* Search for an empty MTRR */ |
367 | i = mtrr_if->get_free_region(base, size); | 389 | i = mtrr_if->get_free_region(base, size, replace); |
368 | if (i >= 0) { | 390 | if (i >= 0) { |
369 | set_mtrr(i, base, size, type); | 391 | set_mtrr(i, base, size, type); |
370 | usage_table[i] = 1; | 392 | if (likely(replace < 0)) |
393 | usage_table[i] = 1; | ||
394 | else { | ||
395 | usage_table[i] = usage_table[replace] + !!increment; | ||
396 | if (unlikely(replace != i)) { | ||
397 | set_mtrr(replace, 0, 0, 0); | ||
398 | usage_table[replace] = 0; | ||
399 | } | ||
400 | } | ||
371 | } else | 401 | } else |
372 | printk(KERN_INFO "mtrr: no more MTRRs available\n"); | 402 | printk(KERN_INFO "mtrr: no more MTRRs available\n"); |
373 | error = i; | 403 | error = i; |
@@ -455,8 +485,7 @@ int mtrr_del_page(int reg, unsigned long base, unsigned long size) | |||
455 | { | 485 | { |
456 | int i, max; | 486 | int i, max; |
457 | mtrr_type ltype; | 487 | mtrr_type ltype; |
458 | unsigned long lbase; | 488 | unsigned long lbase, lsize; |
459 | unsigned int lsize; | ||
460 | int error = -EINVAL; | 489 | int error = -EINVAL; |
461 | 490 | ||
462 | if (!mtrr_if) | 491 | if (!mtrr_if) |
@@ -544,9 +573,11 @@ extern void centaur_init_mtrr(void); | |||
544 | 573 | ||
545 | static void __init init_ifs(void) | 574 | static void __init init_ifs(void) |
546 | { | 575 | { |
576 | #ifndef CONFIG_X86_64 | ||
547 | amd_init_mtrr(); | 577 | amd_init_mtrr(); |
548 | cyrix_init_mtrr(); | 578 | cyrix_init_mtrr(); |
549 | centaur_init_mtrr(); | 579 | centaur_init_mtrr(); |
580 | #endif | ||
550 | } | 581 | } |
551 | 582 | ||
552 | /* The suspend/resume methods are only for CPU without MTRR. CPU using generic | 583 | /* The suspend/resume methods are only for CPU without MTRR. CPU using generic |
@@ -555,7 +586,7 @@ static void __init init_ifs(void) | |||
555 | struct mtrr_value { | 586 | struct mtrr_value { |
556 | mtrr_type ltype; | 587 | mtrr_type ltype; |
557 | unsigned long lbase; | 588 | unsigned long lbase; |
558 | unsigned int lsize; | 589 | unsigned long lsize; |
559 | }; | 590 | }; |
560 | 591 | ||
561 | static struct mtrr_value * mtrr_state; | 592 | static struct mtrr_value * mtrr_state; |
@@ -565,10 +596,8 @@ static int mtrr_save(struct sys_device * sysdev, pm_message_t state) | |||
565 | int i; | 596 | int i; |
566 | int size = num_var_ranges * sizeof(struct mtrr_value); | 597 | int size = num_var_ranges * sizeof(struct mtrr_value); |
567 | 598 | ||
568 | mtrr_state = kmalloc(size,GFP_ATOMIC); | 599 | mtrr_state = kzalloc(size,GFP_ATOMIC); |
569 | if (mtrr_state) | 600 | if (!mtrr_state) |
570 | memset(mtrr_state,0,size); | ||
571 | else | ||
572 | return -ENOMEM; | 601 | return -ENOMEM; |
573 | 602 | ||
574 | for (i = 0; i < num_var_ranges; i++) { | 603 | for (i = 0; i < num_var_ranges; i++) { |