diff options
Diffstat (limited to 'arch/x86/mm/pat.c')
| -rw-r--r-- | arch/x86/mm/pat.c | 50 |
1 files changed, 36 insertions, 14 deletions
diff --git a/arch/x86/mm/pat.c b/arch/x86/mm/pat.c index 2fe30916d4b6..2a50e0fa64a5 100644 --- a/arch/x86/mm/pat.c +++ b/arch/x86/mm/pat.c | |||
| @@ -207,6 +207,9 @@ static int chk_conflict(struct memtype *new, struct memtype *entry, | |||
| 207 | return -EBUSY; | 207 | return -EBUSY; |
| 208 | } | 208 | } |
| 209 | 209 | ||
| 210 | static struct memtype *cached_entry; | ||
| 211 | static u64 cached_start; | ||
| 212 | |||
| 210 | /* | 213 | /* |
| 211 | * req_type typically has one of the: | 214 | * req_type typically has one of the: |
| 212 | * - _PAGE_CACHE_WB | 215 | * - _PAGE_CACHE_WB |
| @@ -280,11 +283,17 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type, | |||
| 280 | 283 | ||
| 281 | spin_lock(&memtype_lock); | 284 | spin_lock(&memtype_lock); |
| 282 | 285 | ||
| 286 | if (cached_entry && start >= cached_start) | ||
| 287 | entry = cached_entry; | ||
| 288 | else | ||
| 289 | entry = list_entry(&memtype_list, struct memtype, nd); | ||
| 290 | |||
| 283 | /* Search for existing mapping that overlaps the current range */ | 291 | /* Search for existing mapping that overlaps the current range */ |
| 284 | where = NULL; | 292 | where = NULL; |
| 285 | list_for_each_entry(entry, &memtype_list, nd) { | 293 | list_for_each_entry_continue(entry, &memtype_list, nd) { |
| 286 | if (end <= entry->start) { | 294 | if (end <= entry->start) { |
| 287 | where = entry->nd.prev; | 295 | where = entry->nd.prev; |
| 296 | cached_entry = list_entry(where, struct memtype, nd); | ||
| 288 | break; | 297 | break; |
| 289 | } else if (start <= entry->start) { /* end > entry->start */ | 298 | } else if (start <= entry->start) { /* end > entry->start */ |
| 290 | err = chk_conflict(new, entry, new_type); | 299 | err = chk_conflict(new, entry, new_type); |
| @@ -292,6 +301,8 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type, | |||
| 292 | dprintk("Overlap at 0x%Lx-0x%Lx\n", | 301 | dprintk("Overlap at 0x%Lx-0x%Lx\n", |
| 293 | entry->start, entry->end); | 302 | entry->start, entry->end); |
| 294 | where = entry->nd.prev; | 303 | where = entry->nd.prev; |
| 304 | cached_entry = list_entry(where, | ||
| 305 | struct memtype, nd); | ||
| 295 | } | 306 | } |
| 296 | break; | 307 | break; |
| 297 | } else if (start < entry->end) { /* start > entry->start */ | 308 | } else if (start < entry->end) { /* start > entry->start */ |
| @@ -299,7 +310,20 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type, | |||
| 299 | if (!err) { | 310 | if (!err) { |
| 300 | dprintk("Overlap at 0x%Lx-0x%Lx\n", | 311 | dprintk("Overlap at 0x%Lx-0x%Lx\n", |
| 301 | entry->start, entry->end); | 312 | entry->start, entry->end); |
| 302 | where = &entry->nd; | 313 | cached_entry = list_entry(entry->nd.prev, |
| 314 | struct memtype, nd); | ||
| 315 | |||
| 316 | /* | ||
| 317 | * Move to right position in the linked | ||
| 318 | * list to add this new entry | ||
| 319 | */ | ||
| 320 | list_for_each_entry_continue(entry, | ||
| 321 | &memtype_list, nd) { | ||
| 322 | if (start <= entry->start) { | ||
| 323 | where = entry->nd.prev; | ||
| 324 | break; | ||
| 325 | } | ||
| 326 | } | ||
| 303 | } | 327 | } |
| 304 | break; | 328 | break; |
| 305 | } | 329 | } |
| @@ -314,6 +338,8 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type, | |||
| 314 | return err; | 338 | return err; |
| 315 | } | 339 | } |
| 316 | 340 | ||
| 341 | cached_start = start; | ||
| 342 | |||
| 317 | if (where) | 343 | if (where) |
| 318 | list_add(&new->nd, where); | 344 | list_add(&new->nd, where); |
| 319 | else | 345 | else |
| @@ -343,6 +369,9 @@ int free_memtype(u64 start, u64 end) | |||
| 343 | spin_lock(&memtype_lock); | 369 | spin_lock(&memtype_lock); |
| 344 | list_for_each_entry(entry, &memtype_list, nd) { | 370 | list_for_each_entry(entry, &memtype_list, nd) { |
| 345 | if (entry->start == start && entry->end == end) { | 371 | if (entry->start == start && entry->end == end) { |
| 372 | if (cached_entry == entry || cached_start == start) | ||
| 373 | cached_entry = NULL; | ||
| 374 | |||
| 346 | list_del(&entry->nd); | 375 | list_del(&entry->nd); |
| 347 | kfree(entry); | 376 | kfree(entry); |
| 348 | err = 0; | 377 | err = 0; |
| @@ -361,14 +390,6 @@ int free_memtype(u64 start, u64 end) | |||
| 361 | } | 390 | } |
| 362 | 391 | ||
| 363 | 392 | ||
| 364 | /* | ||
| 365 | * /dev/mem mmap interface. The memtype used for mapping varies: | ||
| 366 | * - Use UC for mappings with O_SYNC flag | ||
| 367 | * - Without O_SYNC flag, if there is any conflict in reserve_memtype, | ||
| 368 | * inherit the memtype from existing mapping. | ||
| 369 | * - Else use UC_MINUS memtype (for backward compatibility with existing | ||
| 370 | * X drivers. | ||
| 371 | */ | ||
| 372 | pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn, | 393 | pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn, |
| 373 | unsigned long size, pgprot_t vma_prot) | 394 | unsigned long size, pgprot_t vma_prot) |
| 374 | { | 395 | { |
| @@ -406,14 +427,14 @@ int phys_mem_access_prot_allowed(struct file *file, unsigned long pfn, | |||
| 406 | unsigned long size, pgprot_t *vma_prot) | 427 | unsigned long size, pgprot_t *vma_prot) |
| 407 | { | 428 | { |
| 408 | u64 offset = ((u64) pfn) << PAGE_SHIFT; | 429 | u64 offset = ((u64) pfn) << PAGE_SHIFT; |
| 409 | unsigned long flags = _PAGE_CACHE_UC_MINUS; | 430 | unsigned long flags = -1; |
| 410 | int retval; | 431 | int retval; |
| 411 | 432 | ||
| 412 | if (!range_is_allowed(pfn, size)) | 433 | if (!range_is_allowed(pfn, size)) |
| 413 | return 0; | 434 | return 0; |
| 414 | 435 | ||
| 415 | if (file->f_flags & O_SYNC) { | 436 | if (file->f_flags & O_SYNC) { |
| 416 | flags = _PAGE_CACHE_UC; | 437 | flags = _PAGE_CACHE_UC_MINUS; |
| 417 | } | 438 | } |
| 418 | 439 | ||
| 419 | #ifdef CONFIG_X86_32 | 440 | #ifdef CONFIG_X86_32 |
| @@ -436,13 +457,14 @@ int phys_mem_access_prot_allowed(struct file *file, unsigned long pfn, | |||
| 436 | #endif | 457 | #endif |
| 437 | 458 | ||
| 438 | /* | 459 | /* |
| 439 | * With O_SYNC, we can only take UC mapping. Fail if we cannot. | 460 | * With O_SYNC, we can only take UC_MINUS mapping. Fail if we cannot. |
| 461 | * | ||
| 440 | * Without O_SYNC, we want to get | 462 | * Without O_SYNC, we want to get |
| 441 | * - WB for WB-able memory and no other conflicting mappings | 463 | * - WB for WB-able memory and no other conflicting mappings |
| 442 | * - UC_MINUS for non-WB-able memory with no other conflicting mappings | 464 | * - UC_MINUS for non-WB-able memory with no other conflicting mappings |
| 443 | * - Inherit from confliting mappings otherwise | 465 | * - Inherit from confliting mappings otherwise |
| 444 | */ | 466 | */ |
| 445 | if (flags != _PAGE_CACHE_UC_MINUS) { | 467 | if (flags != -1) { |
| 446 | retval = reserve_memtype(offset, offset + size, flags, NULL); | 468 | retval = reserve_memtype(offset, offset + size, flags, NULL); |
| 447 | } else { | 469 | } else { |
| 448 | retval = reserve_memtype(offset, offset + size, -1, &flags); | 470 | retval = reserve_memtype(offset, offset + size, -1, &flags); |
