diff options
| author | Linus Torvalds <torvalds@woody.osdl.org> | 2006-12-04 11:29:45 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@woody.osdl.org> | 2006-12-04 11:29:45 -0500 |
| commit | 07704eb29a765d2e862000d952fd96271c1464e2 (patch) | |
| tree | 43dcf020188d8eeaeb71fae8c09de1f7aec88c43 /arch/s390/mm | |
| parent | f75e3b1de6a72f6eb22f3ab120dd52b902357c03 (diff) | |
| parent | 74f8f557fd0c6f32e17e78c9ef508ca66ef37d3a (diff) | |
Merge branch 'for-linus' of git://git390.osdl.marist.edu/pub/scm/linux-2.6
* 'for-linus' of git://git390.osdl.marist.edu/pub/scm/linux-2.6: (34 commits)
[S390] Don't use small stacks when lockdep is used.
[S390] cio: Use device_reprobe() instead of bus_rescan_devices().
[S390] cio: Retry internal operations after vary off.
[S390] cio: Use path verification for last path gone after vary off.
[S390] non-unique constant/macro identifiers.
[S390] Memory detection fixes.
[S390] cio: Make ccw_dev_id_is_equal() more robust.
[S390] Convert extmem spin_lock into a mutex.
[S390] set KBUILD_IMAGE.
[S390] lockdep: show held locks when showing a stackdump
[S390] Add dynamic size check for usercopy functions.
[S390] Use diag260 for memory size detection.
[S390] pfault code cleanup.
[S390] Cleanup memory_chunk array usage.
[S390] Misaligned wait PSW at memory detection.
[S390] cpu shutdown rework
[S390] cpcmd <-> __cpcmd calling issues
[S390] Bad kexec control page allocation.
[S390] Reset infrastructure for re-IPL.
[S390] Some documentation typos.
...
Diffstat (limited to 'arch/s390/mm')
| -rw-r--r-- | arch/s390/mm/extmem.c | 38 | ||||
| -rw-r--r-- | arch/s390/mm/fault.c | 28 |
2 files changed, 43 insertions, 23 deletions
diff --git a/arch/s390/mm/extmem.c b/arch/s390/mm/extmem.c index 226275d5c4f6..9e9bc48463a5 100644 --- a/arch/s390/mm/extmem.c +++ b/arch/s390/mm/extmem.c | |||
| @@ -14,12 +14,13 @@ | |||
| 14 | #include <linux/slab.h> | 14 | #include <linux/slab.h> |
| 15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
| 16 | #include <linux/bootmem.h> | 16 | #include <linux/bootmem.h> |
| 17 | #include <linux/ctype.h> | ||
| 17 | #include <asm/page.h> | 18 | #include <asm/page.h> |
| 18 | #include <asm/ebcdic.h> | 19 | #include <asm/ebcdic.h> |
| 19 | #include <asm/errno.h> | 20 | #include <asm/errno.h> |
| 20 | #include <asm/extmem.h> | 21 | #include <asm/extmem.h> |
| 21 | #include <asm/cpcmd.h> | 22 | #include <asm/cpcmd.h> |
| 22 | #include <linux/ctype.h> | 23 | #include <asm/setup.h> |
| 23 | 24 | ||
| 24 | #define DCSS_DEBUG /* Debug messages on/off */ | 25 | #define DCSS_DEBUG /* Debug messages on/off */ |
| 25 | 26 | ||
| @@ -77,15 +78,11 @@ struct dcss_segment { | |||
| 77 | int segcnt; | 78 | int segcnt; |
| 78 | }; | 79 | }; |
| 79 | 80 | ||
| 80 | static DEFINE_SPINLOCK(dcss_lock); | 81 | static DEFINE_MUTEX(dcss_lock); |
| 81 | static struct list_head dcss_list = LIST_HEAD_INIT(dcss_list); | 82 | static struct list_head dcss_list = LIST_HEAD_INIT(dcss_list); |
| 82 | static char *segtype_string[] = { "SW", "EW", "SR", "ER", "SN", "EN", "SC", | 83 | static char *segtype_string[] = { "SW", "EW", "SR", "ER", "SN", "EN", "SC", |
| 83 | "EW/EN-MIXED" }; | 84 | "EW/EN-MIXED" }; |
| 84 | 85 | ||
| 85 | extern struct { | ||
| 86 | unsigned long addr, size, type; | ||
| 87 | } memory_chunk[MEMORY_CHUNKS]; | ||
| 88 | |||
| 89 | /* | 86 | /* |
| 90 | * Create the 8 bytes, ebcdic VM segment name from | 87 | * Create the 8 bytes, ebcdic VM segment name from |
| 91 | * an ascii name. | 88 | * an ascii name. |
| @@ -117,7 +114,7 @@ segment_by_name (char *name) | |||
| 117 | struct list_head *l; | 114 | struct list_head *l; |
| 118 | struct dcss_segment *tmp, *retval = NULL; | 115 | struct dcss_segment *tmp, *retval = NULL; |
| 119 | 116 | ||
| 120 | assert_spin_locked(&dcss_lock); | 117 | BUG_ON(!mutex_is_locked(&dcss_lock)); |
| 121 | dcss_mkname (name, dcss_name); | 118 | dcss_mkname (name, dcss_name); |
| 122 | list_for_each (l, &dcss_list) { | 119 | list_for_each (l, &dcss_list) { |
| 123 | tmp = list_entry (l, struct dcss_segment, list); | 120 | tmp = list_entry (l, struct dcss_segment, list); |
| @@ -249,8 +246,8 @@ segment_overlaps_storage(struct dcss_segment *seg) | |||
| 249 | { | 246 | { |
| 250 | int i; | 247 | int i; |
| 251 | 248 | ||
| 252 | for (i=0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++) { | 249 | for (i = 0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++) { |
| 253 | if (memory_chunk[i].type != 0) | 250 | if (memory_chunk[i].type != CHUNK_READ_WRITE) |
| 254 | continue; | 251 | continue; |
| 255 | if ((memory_chunk[i].addr >> 20) > (seg->end >> 20)) | 252 | if ((memory_chunk[i].addr >> 20) > (seg->end >> 20)) |
| 256 | continue; | 253 | continue; |
| @@ -272,7 +269,7 @@ segment_overlaps_others (struct dcss_segment *seg) | |||
| 272 | struct list_head *l; | 269 | struct list_head *l; |
| 273 | struct dcss_segment *tmp; | 270 | struct dcss_segment *tmp; |
| 274 | 271 | ||
| 275 | assert_spin_locked(&dcss_lock); | 272 | BUG_ON(!mutex_is_locked(&dcss_lock)); |
| 276 | list_for_each(l, &dcss_list) { | 273 | list_for_each(l, &dcss_list) { |
| 277 | tmp = list_entry(l, struct dcss_segment, list); | 274 | tmp = list_entry(l, struct dcss_segment, list); |
| 278 | if ((tmp->start_addr >> 20) > (seg->end >> 20)) | 275 | if ((tmp->start_addr >> 20) > (seg->end >> 20)) |
| @@ -429,7 +426,7 @@ segment_load (char *name, int do_nonshared, unsigned long *addr, | |||
| 429 | if (!MACHINE_IS_VM) | 426 | if (!MACHINE_IS_VM) |
| 430 | return -ENOSYS; | 427 | return -ENOSYS; |
| 431 | 428 | ||
| 432 | spin_lock (&dcss_lock); | 429 | mutex_lock(&dcss_lock); |
| 433 | seg = segment_by_name (name); | 430 | seg = segment_by_name (name); |
| 434 | if (seg == NULL) | 431 | if (seg == NULL) |
| 435 | rc = __segment_load (name, do_nonshared, addr, end); | 432 | rc = __segment_load (name, do_nonshared, addr, end); |
| @@ -444,7 +441,7 @@ segment_load (char *name, int do_nonshared, unsigned long *addr, | |||
| 444 | rc = -EPERM; | 441 | rc = -EPERM; |
| 445 | } | 442 | } |
| 446 | } | 443 | } |
| 447 | spin_unlock (&dcss_lock); | 444 | mutex_unlock(&dcss_lock); |
| 448 | return rc; | 445 | return rc; |
| 449 | } | 446 | } |
| 450 | 447 | ||
| @@ -467,7 +464,7 @@ segment_modify_shared (char *name, int do_nonshared) | |||
| 467 | unsigned long dummy; | 464 | unsigned long dummy; |
| 468 | int dcss_command, rc, diag_cc; | 465 | int dcss_command, rc, diag_cc; |
| 469 | 466 | ||
| 470 | spin_lock (&dcss_lock); | 467 | mutex_lock(&dcss_lock); |
| 471 | seg = segment_by_name (name); | 468 | seg = segment_by_name (name); |
| 472 | if (seg == NULL) { | 469 | if (seg == NULL) { |
| 473 | rc = -EINVAL; | 470 | rc = -EINVAL; |
| @@ -508,7 +505,7 @@ segment_modify_shared (char *name, int do_nonshared) | |||
| 508 | &dummy, &dummy); | 505 | &dummy, &dummy); |
| 509 | kfree(seg); | 506 | kfree(seg); |
| 510 | out_unlock: | 507 | out_unlock: |
| 511 | spin_unlock(&dcss_lock); | 508 | mutex_unlock(&dcss_lock); |
| 512 | return rc; | 509 | return rc; |
| 513 | } | 510 | } |
| 514 | 511 | ||
| @@ -526,7 +523,7 @@ segment_unload(char *name) | |||
| 526 | if (!MACHINE_IS_VM) | 523 | if (!MACHINE_IS_VM) |
| 527 | return; | 524 | return; |
| 528 | 525 | ||
| 529 | spin_lock(&dcss_lock); | 526 | mutex_lock(&dcss_lock); |
| 530 | seg = segment_by_name (name); | 527 | seg = segment_by_name (name); |
| 531 | if (seg == NULL) { | 528 | if (seg == NULL) { |
| 532 | PRINT_ERR ("could not find segment %s in segment_unload, " | 529 | PRINT_ERR ("could not find segment %s in segment_unload, " |
| @@ -540,7 +537,7 @@ segment_unload(char *name) | |||
| 540 | kfree(seg); | 537 | kfree(seg); |
| 541 | } | 538 | } |
| 542 | out_unlock: | 539 | out_unlock: |
| 543 | spin_unlock(&dcss_lock); | 540 | mutex_unlock(&dcss_lock); |
| 544 | } | 541 | } |
| 545 | 542 | ||
| 546 | /* | 543 | /* |
| @@ -559,12 +556,13 @@ segment_save(char *name) | |||
| 559 | if (!MACHINE_IS_VM) | 556 | if (!MACHINE_IS_VM) |
| 560 | return; | 557 | return; |
| 561 | 558 | ||
| 562 | spin_lock(&dcss_lock); | 559 | mutex_lock(&dcss_lock); |
| 563 | seg = segment_by_name (name); | 560 | seg = segment_by_name (name); |
| 564 | 561 | ||
| 565 | if (seg == NULL) { | 562 | if (seg == NULL) { |
| 566 | PRINT_ERR ("could not find segment %s in segment_save, please report to linux390@de.ibm.com\n",name); | 563 | PRINT_ERR("could not find segment %s in segment_save, please " |
| 567 | return; | 564 | "report to linux390@de.ibm.com\n", name); |
| 565 | goto out; | ||
| 568 | } | 566 | } |
| 569 | 567 | ||
| 570 | startpfn = seg->start_addr >> PAGE_SHIFT; | 568 | startpfn = seg->start_addr >> PAGE_SHIFT; |
| @@ -591,7 +589,7 @@ segment_save(char *name) | |||
| 591 | goto out; | 589 | goto out; |
| 592 | } | 590 | } |
| 593 | out: | 591 | out: |
| 594 | spin_unlock(&dcss_lock); | 592 | mutex_unlock(&dcss_lock); |
| 595 | } | 593 | } |
| 596 | 594 | ||
| 597 | EXPORT_SYMBOL(segment_load); | 595 | EXPORT_SYMBOL(segment_load); |
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index 1c323bbfda91..cd85e34d8703 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c | |||
| @@ -31,6 +31,7 @@ | |||
| 31 | #include <asm/uaccess.h> | 31 | #include <asm/uaccess.h> |
| 32 | #include <asm/pgtable.h> | 32 | #include <asm/pgtable.h> |
| 33 | #include <asm/kdebug.h> | 33 | #include <asm/kdebug.h> |
| 34 | #include <asm/s390_ext.h> | ||
| 34 | 35 | ||
| 35 | #ifndef CONFIG_64BIT | 36 | #ifndef CONFIG_64BIT |
| 36 | #define __FAIL_ADDR_MASK 0x7ffff000 | 37 | #define __FAIL_ADDR_MASK 0x7ffff000 |
| @@ -394,6 +395,7 @@ void do_dat_exception(struct pt_regs *regs, unsigned long error_code) | |||
| 394 | /* | 395 | /* |
| 395 | * 'pfault' pseudo page faults routines. | 396 | * 'pfault' pseudo page faults routines. |
| 396 | */ | 397 | */ |
| 398 | static ext_int_info_t ext_int_pfault; | ||
| 397 | static int pfault_disable = 0; | 399 | static int pfault_disable = 0; |
| 398 | 400 | ||
| 399 | static int __init nopfault(char *str) | 401 | static int __init nopfault(char *str) |
| @@ -422,7 +424,7 @@ int pfault_init(void) | |||
| 422 | __PF_RES_FIELD }; | 424 | __PF_RES_FIELD }; |
| 423 | int rc; | 425 | int rc; |
| 424 | 426 | ||
| 425 | if (pfault_disable) | 427 | if (!MACHINE_IS_VM || pfault_disable) |
| 426 | return -1; | 428 | return -1; |
| 427 | asm volatile( | 429 | asm volatile( |
| 428 | " diag %1,%0,0x258\n" | 430 | " diag %1,%0,0x258\n" |
| @@ -440,7 +442,7 @@ void pfault_fini(void) | |||
| 440 | pfault_refbk_t refbk = | 442 | pfault_refbk_t refbk = |
| 441 | { 0x258, 1, 5, 2, 0ULL, 0ULL, 0ULL, 0ULL }; | 443 | { 0x258, 1, 5, 2, 0ULL, 0ULL, 0ULL, 0ULL }; |
| 442 | 444 | ||
| 443 | if (pfault_disable) | 445 | if (!MACHINE_IS_VM || pfault_disable) |
| 444 | return; | 446 | return; |
| 445 | __ctl_clear_bit(0,9); | 447 | __ctl_clear_bit(0,9); |
| 446 | asm volatile( | 448 | asm volatile( |
| @@ -500,5 +502,25 @@ pfault_interrupt(__u16 error_code) | |||
| 500 | set_tsk_need_resched(tsk); | 502 | set_tsk_need_resched(tsk); |
| 501 | } | 503 | } |
| 502 | } | 504 | } |
| 503 | #endif | ||
| 504 | 505 | ||
| 506 | void __init pfault_irq_init(void) | ||
| 507 | { | ||
| 508 | if (!MACHINE_IS_VM) | ||
| 509 | return; | ||
| 510 | |||
| 511 | /* | ||
| 512 | * Try to get pfault pseudo page faults going. | ||
| 513 | */ | ||
| 514 | if (register_early_external_interrupt(0x2603, pfault_interrupt, | ||
| 515 | &ext_int_pfault) != 0) | ||
| 516 | panic("Couldn't request external interrupt 0x2603"); | ||
| 517 | |||
| 518 | if (pfault_init() == 0) | ||
| 519 | return; | ||
| 520 | |||
| 521 | /* Tough luck, no pfault. */ | ||
| 522 | pfault_disable = 1; | ||
| 523 | unregister_early_external_interrupt(0x2603, pfault_interrupt, | ||
| 524 | &ext_int_pfault); | ||
| 525 | } | ||
| 526 | #endif | ||
