diff options
58 files changed, 1369 insertions, 1004 deletions
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 0d8cd9bbe101..79d0ca086820 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig | |||
| @@ -444,13 +444,6 @@ config FORCE_MAX_ZONEORDER | |||
| 444 | int | 444 | int |
| 445 | default "9" | 445 | default "9" |
| 446 | 446 | ||
| 447 | config PROCESS_DEBUG | ||
| 448 | bool "Show crashed user process info" | ||
| 449 | help | ||
| 450 | Say Y to print all process fault locations to the console. This is | ||
| 451 | a debugging option; you probably do not want to set it unless you | ||
| 452 | are an S390 port maintainer. | ||
| 453 | |||
| 454 | config PFAULT | 447 | config PFAULT |
| 455 | bool "Pseudo page fault support" | 448 | bool "Pseudo page fault support" |
| 456 | help | 449 | help |
diff --git a/arch/s390/Makefile b/arch/s390/Makefile index 0da10746e0e5..30c5f01f93b0 100644 --- a/arch/s390/Makefile +++ b/arch/s390/Makefile | |||
| @@ -116,6 +116,12 @@ image bzImage: vmlinux | |||
| 116 | zfcpdump: | 116 | zfcpdump: |
| 117 | $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@ | 117 | $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@ |
| 118 | 118 | ||
| 119 | vdso_install: | ||
| 120 | ifeq ($(CONFIG_64BIT),y) | ||
| 121 | $(Q)$(MAKE) $(build)=arch/$(ARCH)/kernel/vdso64 $@ | ||
| 122 | endif | ||
| 123 | $(Q)$(MAKE) $(build)=arch/$(ARCH)/kernel/vdso32 $@ | ||
| 124 | |||
| 119 | archclean: | 125 | archclean: |
| 120 | $(Q)$(MAKE) $(clean)=$(boot) | 126 | $(Q)$(MAKE) $(clean)=$(boot) |
| 121 | 127 | ||
diff --git a/arch/s390/hypfs/hypfs.h b/arch/s390/hypfs/hypfs.h index aea572009d60..fa487d4cc08b 100644 --- a/arch/s390/hypfs/hypfs.h +++ b/arch/s390/hypfs/hypfs.h | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | 11 | ||
| 12 | #include <linux/fs.h> | 12 | #include <linux/fs.h> |
| 13 | #include <linux/types.h> | 13 | #include <linux/types.h> |
| 14 | #include <linux/debugfs.h> | ||
| 14 | 15 | ||
| 15 | #define REG_FILE_MODE 0440 | 16 | #define REG_FILE_MODE 0440 |
| 16 | #define UPDATE_FILE_MODE 0220 | 17 | #define UPDATE_FILE_MODE 0220 |
| @@ -34,6 +35,9 @@ extern int hypfs_diag_create_files(struct super_block *sb, struct dentry *root); | |||
| 34 | 35 | ||
| 35 | /* VM Hypervisor */ | 36 | /* VM Hypervisor */ |
| 36 | extern int hypfs_vm_init(void); | 37 | extern int hypfs_vm_init(void); |
| 38 | extern void hypfs_vm_exit(void); | ||
| 37 | extern int hypfs_vm_create_files(struct super_block *sb, struct dentry *root); | 39 | extern int hypfs_vm_create_files(struct super_block *sb, struct dentry *root); |
| 38 | 40 | ||
| 41 | /* Directory for debugfs files */ | ||
| 42 | extern struct dentry *hypfs_dbfs_dir; | ||
| 39 | #endif /* _HYPFS_H_ */ | 43 | #endif /* _HYPFS_H_ */ |
diff --git a/arch/s390/hypfs/hypfs_diag.c b/arch/s390/hypfs/hypfs_diag.c index 5b1acdba6495..1211bb1d2f24 100644 --- a/arch/s390/hypfs/hypfs_diag.c +++ b/arch/s390/hypfs/hypfs_diag.c | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
| 16 | #include <linux/string.h> | 16 | #include <linux/string.h> |
| 17 | #include <linux/vmalloc.h> | 17 | #include <linux/vmalloc.h> |
| 18 | #include <linux/mm.h> | ||
| 18 | #include <asm/ebcdic.h> | 19 | #include <asm/ebcdic.h> |
| 19 | #include "hypfs.h" | 20 | #include "hypfs.h" |
| 20 | 21 | ||
| @@ -22,6 +23,8 @@ | |||
| 22 | #define CPU_NAME_LEN 16 /* type name len of cpus in diag224 name table */ | 23 | #define CPU_NAME_LEN 16 /* type name len of cpus in diag224 name table */ |
| 23 | #define TMP_SIZE 64 /* size of temporary buffers */ | 24 | #define TMP_SIZE 64 /* size of temporary buffers */ |
| 24 | 25 | ||
| 26 | #define DBFS_D204_HDR_VERSION 0 | ||
| 27 | |||
| 25 | /* diag 204 subcodes */ | 28 | /* diag 204 subcodes */ |
| 26 | enum diag204_sc { | 29 | enum diag204_sc { |
| 27 | SUBC_STIB4 = 4, | 30 | SUBC_STIB4 = 4, |
| @@ -47,6 +50,8 @@ static void *diag204_buf; /* 4K aligned buffer for diag204 data */ | |||
| 47 | static void *diag204_buf_vmalloc; /* vmalloc pointer for diag204 data */ | 50 | static void *diag204_buf_vmalloc; /* vmalloc pointer for diag204 data */ |
| 48 | static int diag204_buf_pages; /* number of pages for diag204 data */ | 51 | static int diag204_buf_pages; /* number of pages for diag204 data */ |
| 49 | 52 | ||
| 53 | static struct dentry *dbfs_d204_file; | ||
| 54 | |||
| 50 | /* | 55 | /* |
| 51 | * DIAG 204 data structures and member access functions. | 56 | * DIAG 204 data structures and member access functions. |
| 52 | * | 57 | * |
| @@ -364,18 +369,21 @@ static void diag204_free_buffer(void) | |||
| 364 | } else { | 369 | } else { |
| 365 | free_pages((unsigned long) diag204_buf, 0); | 370 | free_pages((unsigned long) diag204_buf, 0); |
| 366 | } | 371 | } |
| 367 | diag204_buf_pages = 0; | ||
| 368 | diag204_buf = NULL; | 372 | diag204_buf = NULL; |
| 369 | } | 373 | } |
| 370 | 374 | ||
| 375 | static void *page_align_ptr(void *ptr) | ||
| 376 | { | ||
| 377 | return (void *) PAGE_ALIGN((unsigned long) ptr); | ||
| 378 | } | ||
| 379 | |||
| 371 | static void *diag204_alloc_vbuf(int pages) | 380 | static void *diag204_alloc_vbuf(int pages) |
| 372 | { | 381 | { |
| 373 | /* The buffer has to be page aligned! */ | 382 | /* The buffer has to be page aligned! */ |
| 374 | diag204_buf_vmalloc = vmalloc(PAGE_SIZE * (pages + 1)); | 383 | diag204_buf_vmalloc = vmalloc(PAGE_SIZE * (pages + 1)); |
| 375 | if (!diag204_buf_vmalloc) | 384 | if (!diag204_buf_vmalloc) |
| 376 | return ERR_PTR(-ENOMEM); | 385 | return ERR_PTR(-ENOMEM); |
| 377 | diag204_buf = (void*)((unsigned long)diag204_buf_vmalloc | 386 | diag204_buf = page_align_ptr(diag204_buf_vmalloc); |
| 378 | & ~0xfffUL) + 0x1000; | ||
| 379 | diag204_buf_pages = pages; | 387 | diag204_buf_pages = pages; |
| 380 | return diag204_buf; | 388 | return diag204_buf; |
| 381 | } | 389 | } |
| @@ -468,17 +476,26 @@ fail_alloc: | |||
| 468 | return rc; | 476 | return rc; |
| 469 | } | 477 | } |
| 470 | 478 | ||
| 479 | static int diag204_do_store(void *buf, int pages) | ||
| 480 | { | ||
| 481 | int rc; | ||
| 482 | |||
| 483 | rc = diag204((unsigned long) diag204_store_sc | | ||
| 484 | (unsigned long) diag204_info_type, pages, buf); | ||
| 485 | return rc < 0 ? -ENOSYS : 0; | ||
| 486 | } | ||
| 487 | |||
| 471 | static void *diag204_store(void) | 488 | static void *diag204_store(void) |
| 472 | { | 489 | { |
| 473 | void *buf; | 490 | void *buf; |
| 474 | int pages; | 491 | int pages, rc; |
| 475 | 492 | ||
| 476 | buf = diag204_get_buffer(diag204_info_type, &pages); | 493 | buf = diag204_get_buffer(diag204_info_type, &pages); |
| 477 | if (IS_ERR(buf)) | 494 | if (IS_ERR(buf)) |
| 478 | goto out; | 495 | goto out; |
| 479 | if (diag204((unsigned long)diag204_store_sc | | 496 | rc = diag204_do_store(buf, pages); |
| 480 | (unsigned long)diag204_info_type, pages, buf) < 0) | 497 | if (rc) |
| 481 | return ERR_PTR(-ENOSYS); | 498 | return ERR_PTR(rc); |
| 482 | out: | 499 | out: |
| 483 | return buf; | 500 | return buf; |
| 484 | } | 501 | } |
| @@ -526,6 +543,92 @@ static int diag224_idx2name(int index, char *name) | |||
| 526 | return 0; | 543 | return 0; |
| 527 | } | 544 | } |
| 528 | 545 | ||
| 546 | struct dbfs_d204_hdr { | ||
| 547 | u64 len; /* Length of d204 buffer without header */ | ||
| 548 | u16 version; /* Version of header */ | ||
| 549 | u8 sc; /* Used subcode */ | ||
| 550 | char reserved[53]; | ||
| 551 | } __attribute__ ((packed)); | ||
| 552 | |||
| 553 | struct dbfs_d204 { | ||
| 554 | struct dbfs_d204_hdr hdr; /* 64 byte header */ | ||
| 555 | char buf[]; /* d204 buffer */ | ||
| 556 | } __attribute__ ((packed)); | ||
| 557 | |||
| 558 | struct dbfs_d204_private { | ||
| 559 | struct dbfs_d204 *d204; /* Aligned d204 data with header */ | ||
| 560 | void *base; /* Base pointer (needed for vfree) */ | ||
| 561 | }; | ||
| 562 | |||
| 563 | static int dbfs_d204_open(struct inode *inode, struct file *file) | ||
| 564 | { | ||
| 565 | struct dbfs_d204_private *data; | ||
| 566 | struct dbfs_d204 *d204; | ||
| 567 | int rc, buf_size; | ||
| 568 | |||
| 569 | data = kzalloc(sizeof(*data), GFP_KERNEL); | ||
| 570 | if (!data) | ||
| 571 | return -ENOMEM; | ||
| 572 | buf_size = PAGE_SIZE * (diag204_buf_pages + 1) + sizeof(d204->hdr); | ||
| 573 | data->base = vmalloc(buf_size); | ||
| 574 | if (!data->base) { | ||
| 575 | rc = -ENOMEM; | ||
| 576 | goto fail_kfree_data; | ||
| 577 | } | ||
| 578 | memset(data->base, 0, buf_size); | ||
| 579 | d204 = page_align_ptr(data->base + sizeof(d204->hdr)) | ||
| 580 | - sizeof(d204->hdr); | ||
| 581 | rc = diag204_do_store(&d204->buf, diag204_buf_pages); | ||
| 582 | if (rc) | ||
| 583 | goto fail_vfree_base; | ||
| 584 | d204->hdr.version = DBFS_D204_HDR_VERSION; | ||
| 585 | d204->hdr.len = PAGE_SIZE * diag204_buf_pages; | ||
| 586 | d204->hdr.sc = diag204_store_sc; | ||
| 587 | data->d204 = d204; | ||
| 588 | file->private_data = data; | ||
| 589 | return nonseekable_open(inode, file); | ||
| 590 | |||
| 591 | fail_vfree_base: | ||
| 592 | vfree(data->base); | ||
| 593 | fail_kfree_data: | ||
| 594 | kfree(data); | ||
| 595 | return rc; | ||
| 596 | } | ||
| 597 | |||
| 598 | static int dbfs_d204_release(struct inode *inode, struct file *file) | ||
| 599 | { | ||
| 600 | struct dbfs_d204_private *data = file->private_data; | ||
| 601 | |||
| 602 | vfree(data->base); | ||
| 603 | kfree(data); | ||
| 604 | return 0; | ||
| 605 | } | ||
| 606 | |||
| 607 | static ssize_t dbfs_d204_read(struct file *file, char __user *buf, | ||
| 608 | size_t size, loff_t *ppos) | ||
| 609 | { | ||
| 610 | struct dbfs_d204_private *data = file->private_data; | ||
| 611 | |||
| 612 | return simple_read_from_buffer(buf, size, ppos, data->d204, | ||
| 613 | data->d204->hdr.len + | ||
| 614 | sizeof(data->d204->hdr)); | ||
| 615 | } | ||
| 616 | |||
| 617 | static const struct file_operations dbfs_d204_ops = { | ||
| 618 | .open = dbfs_d204_open, | ||
| 619 | .read = dbfs_d204_read, | ||
| 620 | .release = dbfs_d204_release, | ||
| 621 | }; | ||
| 622 | |||
| 623 | static int hypfs_dbfs_init(void) | ||
| 624 | { | ||
| 625 | dbfs_d204_file = debugfs_create_file("diag_204", 0400, hypfs_dbfs_dir, | ||
| 626 | NULL, &dbfs_d204_ops); | ||
| 627 | if (IS_ERR(dbfs_d204_file)) | ||
| 628 | return PTR_ERR(dbfs_d204_file); | ||
| 629 | return 0; | ||
| 630 | } | ||
| 631 | |||
| 529 | __init int hypfs_diag_init(void) | 632 | __init int hypfs_diag_init(void) |
| 530 | { | 633 | { |
| 531 | int rc; | 634 | int rc; |
| @@ -540,11 +643,17 @@ __init int hypfs_diag_init(void) | |||
| 540 | pr_err("The hardware system does not provide all " | 643 | pr_err("The hardware system does not provide all " |
| 541 | "functions required by hypfs\n"); | 644 | "functions required by hypfs\n"); |
| 542 | } | 645 | } |
| 646 | if (diag204_info_type == INFO_EXT) { | ||
| 647 | rc = hypfs_dbfs_init(); | ||
| 648 | if (rc) | ||
| 649 | diag204_free_buffer(); | ||
| 650 | } | ||
| 543 | return rc; | 651 | return rc; |
| 544 | } | 652 | } |
| 545 | 653 | ||
| 546 | void hypfs_diag_exit(void) | 654 | void hypfs_diag_exit(void) |
| 547 | { | 655 | { |
| 656 | debugfs_remove(dbfs_d204_file); | ||
| 548 | diag224_delete_name_table(); | 657 | diag224_delete_name_table(); |
| 549 | diag204_free_buffer(); | 658 | diag204_free_buffer(); |
| 550 | } | 659 | } |
diff --git a/arch/s390/hypfs/hypfs_vm.c b/arch/s390/hypfs/hypfs_vm.c index f0b0d31f0b48..ee5ab1a578e7 100644 --- a/arch/s390/hypfs/hypfs_vm.c +++ b/arch/s390/hypfs/hypfs_vm.c | |||
| @@ -10,14 +10,18 @@ | |||
| 10 | #include <linux/string.h> | 10 | #include <linux/string.h> |
| 11 | #include <linux/vmalloc.h> | 11 | #include <linux/vmalloc.h> |
| 12 | #include <asm/ebcdic.h> | 12 | #include <asm/ebcdic.h> |
| 13 | #include <asm/timex.h> | ||
| 13 | #include "hypfs.h" | 14 | #include "hypfs.h" |
| 14 | 15 | ||
| 15 | #define NAME_LEN 8 | 16 | #define NAME_LEN 8 |
| 17 | #define DBFS_D2FC_HDR_VERSION 0 | ||
| 16 | 18 | ||
| 17 | static char local_guest[] = " "; | 19 | static char local_guest[] = " "; |
| 18 | static char all_guests[] = "* "; | 20 | static char all_guests[] = "* "; |
| 19 | static char *guest_query; | 21 | static char *guest_query; |
| 20 | 22 | ||
| 23 | static struct dentry *dbfs_d2fc_file; | ||
| 24 | |||
| 21 | struct diag2fc_data { | 25 | struct diag2fc_data { |
| 22 | __u32 version; | 26 | __u32 version; |
| 23 | __u32 flags; | 27 | __u32 flags; |
| @@ -76,23 +80,26 @@ static int diag2fc(int size, char* query, void *addr) | |||
| 76 | return -residual_cnt; | 80 | return -residual_cnt; |
| 77 | } | 81 | } |
| 78 | 82 | ||
| 79 | static struct diag2fc_data *diag2fc_store(char *query, int *count) | 83 | /* |
| 84 | * Allocate buffer for "query" and store diag 2fc at "offset" | ||
| 85 | */ | ||
| 86 | static void *diag2fc_store(char *query, unsigned int *count, int offset) | ||
| 80 | { | 87 | { |
| 88 | void *data; | ||
| 81 | int size; | 89 | int size; |
| 82 | struct diag2fc_data *data; | ||
| 83 | 90 | ||
| 84 | do { | 91 | do { |
| 85 | size = diag2fc(0, query, NULL); | 92 | size = diag2fc(0, query, NULL); |
| 86 | if (size < 0) | 93 | if (size < 0) |
| 87 | return ERR_PTR(-EACCES); | 94 | return ERR_PTR(-EACCES); |
| 88 | data = vmalloc(size); | 95 | data = vmalloc(size + offset); |
| 89 | if (!data) | 96 | if (!data) |
| 90 | return ERR_PTR(-ENOMEM); | 97 | return ERR_PTR(-ENOMEM); |
| 91 | if (diag2fc(size, query, data) == 0) | 98 | if (diag2fc(size, query, data + offset) == 0) |
| 92 | break; | 99 | break; |
| 93 | vfree(data); | 100 | vfree(data); |
| 94 | } while (1); | 101 | } while (1); |
| 95 | *count = (size / sizeof(*data)); | 102 | *count = (size / sizeof(struct diag2fc_data)); |
| 96 | 103 | ||
| 97 | return data; | 104 | return data; |
| 98 | } | 105 | } |
| @@ -168,9 +175,10 @@ int hypfs_vm_create_files(struct super_block *sb, struct dentry *root) | |||
| 168 | { | 175 | { |
| 169 | struct dentry *dir, *file; | 176 | struct dentry *dir, *file; |
| 170 | struct diag2fc_data *data; | 177 | struct diag2fc_data *data; |
| 171 | int rc, i, count = 0; | 178 | unsigned int count = 0; |
| 179 | int rc, i; | ||
| 172 | 180 | ||
| 173 | data = diag2fc_store(guest_query, &count); | 181 | data = diag2fc_store(guest_query, &count, 0); |
| 174 | if (IS_ERR(data)) | 182 | if (IS_ERR(data)) |
| 175 | return PTR_ERR(data); | 183 | return PTR_ERR(data); |
| 176 | 184 | ||
| @@ -218,8 +226,61 @@ failed: | |||
| 218 | return rc; | 226 | return rc; |
| 219 | } | 227 | } |
| 220 | 228 | ||
| 229 | struct dbfs_d2fc_hdr { | ||
| 230 | u64 len; /* Length of d2fc buffer without header */ | ||
| 231 | u16 version; /* Version of header */ | ||
| 232 | char tod_ext[16]; /* TOD clock for d2fc */ | ||
| 233 | u64 count; /* Number of VM guests in d2fc buffer */ | ||
| 234 | char reserved[30]; | ||
| 235 | } __attribute__ ((packed)); | ||
| 236 | |||
| 237 | struct dbfs_d2fc { | ||
| 238 | struct dbfs_d2fc_hdr hdr; /* 64 byte header */ | ||
| 239 | char buf[]; /* d2fc buffer */ | ||
| 240 | } __attribute__ ((packed)); | ||
| 241 | |||
| 242 | static int dbfs_d2fc_open(struct inode *inode, struct file *file) | ||
| 243 | { | ||
| 244 | struct dbfs_d2fc *data; | ||
| 245 | unsigned int count; | ||
| 246 | |||
| 247 | data = diag2fc_store(guest_query, &count, sizeof(data->hdr)); | ||
| 248 | if (IS_ERR(data)) | ||
| 249 | return PTR_ERR(data); | ||
| 250 | get_clock_ext(data->hdr.tod_ext); | ||
| 251 | data->hdr.len = count * sizeof(struct diag2fc_data); | ||
| 252 | data->hdr.version = DBFS_D2FC_HDR_VERSION; | ||
| 253 | data->hdr.count = count; | ||
| 254 | memset(&data->hdr.reserved, 0, sizeof(data->hdr.reserved)); | ||
| 255 | file->private_data = data; | ||
| 256 | return nonseekable_open(inode, file); | ||
| 257 | } | ||
| 258 | |||
| 259 | static int dbfs_d2fc_release(struct inode *inode, struct file *file) | ||
| 260 | { | ||
| 261 | diag2fc_free(file->private_data); | ||
| 262 | return 0; | ||
| 263 | } | ||
| 264 | |||
| 265 | static ssize_t dbfs_d2fc_read(struct file *file, char __user *buf, | ||
| 266 | size_t size, loff_t *ppos) | ||
| 267 | { | ||
| 268 | struct dbfs_d2fc *data = file->private_data; | ||
| 269 | |||
| 270 | return simple_read_from_buffer(buf, size, ppos, data, data->hdr.len + | ||
| 271 | sizeof(struct dbfs_d2fc_hdr)); | ||
| 272 | } | ||
| 273 | |||
| 274 | static const struct file_operations dbfs_d2fc_ops = { | ||
| 275 | .open = dbfs_d2fc_open, | ||
| 276 | .read = dbfs_d2fc_read, | ||
| 277 | .release = dbfs_d2fc_release, | ||
| 278 | }; | ||
| 279 | |||
| 221 | int hypfs_vm_init(void) | 280 | int hypfs_vm_init(void) |
| 222 | { | 281 | { |
| 282 | if (!MACHINE_IS_VM) | ||
| 283 | return 0; | ||
| 223 | if (diag2fc(0, all_guests, NULL) > 0) | 284 | if (diag2fc(0, all_guests, NULL) > 0) |
| 224 | guest_query = all_guests; | 285 | guest_query = all_guests; |
| 225 | else if (diag2fc(0, local_guest, NULL) > 0) | 286 | else if (diag2fc(0, local_guest, NULL) > 0) |
| @@ -227,5 +288,17 @@ int hypfs_vm_init(void) | |||
| 227 | else | 288 | else |
| 228 | return -EACCES; | 289 | return -EACCES; |
| 229 | 290 | ||
| 291 | dbfs_d2fc_file = debugfs_create_file("diag_2fc", 0400, hypfs_dbfs_dir, | ||
| 292 | NULL, &dbfs_d2fc_ops); | ||
| 293 | if (IS_ERR(dbfs_d2fc_file)) | ||
| 294 | return PTR_ERR(dbfs_d2fc_file); | ||
| 295 | |||
| 230 | return 0; | 296 | return 0; |
| 231 | } | 297 | } |
| 298 | |||
| 299 | void hypfs_vm_exit(void) | ||
| 300 | { | ||
| 301 | if (!MACHINE_IS_VM) | ||
| 302 | return; | ||
| 303 | debugfs_remove(dbfs_d2fc_file); | ||
| 304 | } | ||
diff --git a/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c index c53f8ac825ca..6b120f073043 100644 --- a/arch/s390/hypfs/inode.c +++ b/arch/s390/hypfs/inode.c | |||
| @@ -46,6 +46,8 @@ static const struct super_operations hypfs_s_ops; | |||
| 46 | /* start of list of all dentries, which have to be deleted on update */ | 46 | /* start of list of all dentries, which have to be deleted on update */ |
| 47 | static struct dentry *hypfs_last_dentry; | 47 | static struct dentry *hypfs_last_dentry; |
| 48 | 48 | ||
| 49 | struct dentry *hypfs_dbfs_dir; | ||
| 50 | |||
| 49 | static void hypfs_update_update(struct super_block *sb) | 51 | static void hypfs_update_update(struct super_block *sb) |
| 50 | { | 52 | { |
| 51 | struct hypfs_sb_info *sb_info = sb->s_fs_info; | 53 | struct hypfs_sb_info *sb_info = sb->s_fs_info; |
| @@ -145,7 +147,7 @@ static int hypfs_open(struct inode *inode, struct file *filp) | |||
| 145 | } | 147 | } |
| 146 | mutex_unlock(&fs_info->lock); | 148 | mutex_unlock(&fs_info->lock); |
| 147 | } | 149 | } |
| 148 | return 0; | 150 | return nonseekable_open(inode, filp); |
| 149 | } | 151 | } |
| 150 | 152 | ||
| 151 | static ssize_t hypfs_aio_read(struct kiocb *iocb, const struct iovec *iov, | 153 | static ssize_t hypfs_aio_read(struct kiocb *iocb, const struct iovec *iov, |
| @@ -468,20 +470,22 @@ static int __init hypfs_init(void) | |||
| 468 | { | 470 | { |
| 469 | int rc; | 471 | int rc; |
| 470 | 472 | ||
| 471 | if (MACHINE_IS_VM) { | 473 | hypfs_dbfs_dir = debugfs_create_dir("s390_hypfs", NULL); |
| 472 | if (hypfs_vm_init()) | 474 | if (IS_ERR(hypfs_dbfs_dir)) |
| 473 | /* no diag 2fc, just exit */ | 475 | return PTR_ERR(hypfs_dbfs_dir); |
| 474 | return -ENODATA; | 476 | |
| 475 | } else { | 477 | if (hypfs_diag_init()) { |
| 476 | if (hypfs_diag_init()) { | 478 | rc = -ENODATA; |
| 477 | rc = -ENODATA; | 479 | goto fail_debugfs_remove; |
| 478 | goto fail_diag; | 480 | } |
| 479 | } | 481 | if (hypfs_vm_init()) { |
| 482 | rc = -ENODATA; | ||
| 483 | goto fail_hypfs_diag_exit; | ||
| 480 | } | 484 | } |
| 481 | s390_kobj = kobject_create_and_add("s390", hypervisor_kobj); | 485 | s390_kobj = kobject_create_and_add("s390", hypervisor_kobj); |
| 482 | if (!s390_kobj) { | 486 | if (!s390_kobj) { |
| 483 | rc = -ENOMEM; | 487 | rc = -ENOMEM; |
| 484 | goto fail_sysfs; | 488 | goto fail_hypfs_vm_exit; |
| 485 | } | 489 | } |
| 486 | rc = register_filesystem(&hypfs_type); | 490 | rc = register_filesystem(&hypfs_type); |
| 487 | if (rc) | 491 | if (rc) |
| @@ -490,18 +494,22 @@ static int __init hypfs_init(void) | |||
| 490 | 494 | ||
| 491 | fail_filesystem: | 495 | fail_filesystem: |
| 492 | kobject_put(s390_kobj); | 496 | kobject_put(s390_kobj); |
| 493 | fail_sysfs: | 497 | fail_hypfs_vm_exit: |
| 494 | if (!MACHINE_IS_VM) | 498 | hypfs_vm_exit(); |
| 495 | hypfs_diag_exit(); | 499 | fail_hypfs_diag_exit: |
| 496 | fail_diag: | 500 | hypfs_diag_exit(); |
| 501 | fail_debugfs_remove: | ||
| 502 | debugfs_remove(hypfs_dbfs_dir); | ||
| 503 | |||
| 497 | pr_err("Initialization of hypfs failed with rc=%i\n", rc); | 504 | pr_err("Initialization of hypfs failed with rc=%i\n", rc); |
| 498 | return rc; | 505 | return rc; |
| 499 | } | 506 | } |
| 500 | 507 | ||
| 501 | static void __exit hypfs_exit(void) | 508 | static void __exit hypfs_exit(void) |
| 502 | { | 509 | { |
| 503 | if (!MACHINE_IS_VM) | 510 | hypfs_diag_exit(); |
| 504 | hypfs_diag_exit(); | 511 | hypfs_vm_exit(); |
| 512 | debugfs_remove(hypfs_dbfs_dir); | ||
| 505 | unregister_filesystem(&hypfs_type); | 513 | unregister_filesystem(&hypfs_type); |
| 506 | kobject_put(s390_kobj); | 514 | kobject_put(s390_kobj); |
| 507 | } | 515 | } |
diff --git a/arch/s390/include/asm/cputime.h b/arch/s390/include/asm/cputime.h index 258ba88b7b50..8b1a52a137c5 100644 --- a/arch/s390/include/asm/cputime.h +++ b/arch/s390/include/asm/cputime.h | |||
| @@ -188,15 +188,16 @@ struct s390_idle_data { | |||
| 188 | 188 | ||
| 189 | DECLARE_PER_CPU(struct s390_idle_data, s390_idle); | 189 | DECLARE_PER_CPU(struct s390_idle_data, s390_idle); |
| 190 | 190 | ||
| 191 | void vtime_start_cpu(void); | 191 | void vtime_start_cpu(__u64 int_clock, __u64 enter_timer); |
| 192 | cputime64_t s390_get_idle_time(int cpu); | 192 | cputime64_t s390_get_idle_time(int cpu); |
| 193 | 193 | ||
| 194 | #define arch_idle_time(cpu) s390_get_idle_time(cpu) | 194 | #define arch_idle_time(cpu) s390_get_idle_time(cpu) |
| 195 | 195 | ||
| 196 | static inline void s390_idle_check(void) | 196 | static inline void s390_idle_check(struct pt_regs *regs, __u64 int_clock, |
| 197 | __u64 enter_timer) | ||
| 197 | { | 198 | { |
| 198 | if ((&__get_cpu_var(s390_idle))->idle_enter != 0ULL) | 199 | if (regs->psw.mask & PSW_MASK_WAIT) |
| 199 | vtime_start_cpu(); | 200 | vtime_start_cpu(int_clock, enter_timer); |
| 200 | } | 201 | } |
| 201 | 202 | ||
| 202 | static inline int s390_nohz_delay(int cpu) | 203 | static inline int s390_nohz_delay(int cpu) |
diff --git a/arch/s390/include/asm/lowcore.h b/arch/s390/include/asm/lowcore.h index 05527c040b7a..0f97ef2d92ac 100644 --- a/arch/s390/include/asm/lowcore.h +++ b/arch/s390/include/asm/lowcore.h | |||
| @@ -104,38 +104,39 @@ struct _lowcore { | |||
| 104 | /* CPU time accounting values */ | 104 | /* CPU time accounting values */ |
| 105 | __u64 sync_enter_timer; /* 0x0250 */ | 105 | __u64 sync_enter_timer; /* 0x0250 */ |
| 106 | __u64 async_enter_timer; /* 0x0258 */ | 106 | __u64 async_enter_timer; /* 0x0258 */ |
| 107 | __u64 exit_timer; /* 0x0260 */ | 107 | __u64 mcck_enter_timer; /* 0x0260 */ |
| 108 | __u64 user_timer; /* 0x0268 */ | 108 | __u64 exit_timer; /* 0x0268 */ |
| 109 | __u64 system_timer; /* 0x0270 */ | 109 | __u64 user_timer; /* 0x0270 */ |
| 110 | __u64 steal_timer; /* 0x0278 */ | 110 | __u64 system_timer; /* 0x0278 */ |
| 111 | __u64 last_update_timer; /* 0x0280 */ | 111 | __u64 steal_timer; /* 0x0280 */ |
| 112 | __u64 last_update_clock; /* 0x0288 */ | 112 | __u64 last_update_timer; /* 0x0288 */ |
| 113 | __u64 last_update_clock; /* 0x0290 */ | ||
| 113 | 114 | ||
| 114 | /* Current process. */ | 115 | /* Current process. */ |
| 115 | __u32 current_task; /* 0x0290 */ | 116 | __u32 current_task; /* 0x0298 */ |
| 116 | __u32 thread_info; /* 0x0294 */ | 117 | __u32 thread_info; /* 0x029c */ |
| 117 | __u32 kernel_stack; /* 0x0298 */ | 118 | __u32 kernel_stack; /* 0x02a0 */ |
| 118 | 119 | ||
| 119 | /* Interrupt and panic stack. */ | 120 | /* Interrupt and panic stack. */ |
| 120 | __u32 async_stack; /* 0x029c */ | 121 | __u32 async_stack; /* 0x02a4 */ |
| 121 | __u32 panic_stack; /* 0x02a0 */ | 122 | __u32 panic_stack; /* 0x02a8 */ |
| 122 | 123 | ||
| 123 | /* Address space pointer. */ | 124 | /* Address space pointer. */ |
| 124 | __u32 kernel_asce; /* 0x02a4 */ | 125 | __u32 kernel_asce; /* 0x02ac */ |
| 125 | __u32 user_asce; /* 0x02a8 */ | 126 | __u32 user_asce; /* 0x02b0 */ |
| 126 | __u32 user_exec_asce; /* 0x02ac */ | 127 | __u32 user_exec_asce; /* 0x02b4 */ |
| 127 | 128 | ||
| 128 | /* SMP info area */ | 129 | /* SMP info area */ |
| 129 | struct cpuid cpu_id; /* 0x02b0 */ | ||
| 130 | __u32 cpu_nr; /* 0x02b8 */ | 130 | __u32 cpu_nr; /* 0x02b8 */ |
| 131 | __u32 softirq_pending; /* 0x02bc */ | 131 | __u32 softirq_pending; /* 0x02bc */ |
| 132 | __u32 percpu_offset; /* 0x02c0 */ | 132 | __u32 percpu_offset; /* 0x02c0 */ |
| 133 | __u32 ext_call_fast; /* 0x02c4 */ | 133 | __u32 ext_call_fast; /* 0x02c4 */ |
| 134 | __u64 int_clock; /* 0x02c8 */ | 134 | __u64 int_clock; /* 0x02c8 */ |
| 135 | __u64 clock_comparator; /* 0x02d0 */ | 135 | __u64 mcck_clock; /* 0x02d0 */ |
| 136 | __u32 machine_flags; /* 0x02d8 */ | 136 | __u64 clock_comparator; /* 0x02d8 */ |
| 137 | __u32 ftrace_func; /* 0x02dc */ | 137 | __u32 machine_flags; /* 0x02e0 */ |
| 138 | __u8 pad_0x02e0[0x0300-0x02e0]; /* 0x02e0 */ | 138 | __u32 ftrace_func; /* 0x02e4 */ |
| 139 | __u8 pad_0x02e8[0x0300-0x02e8]; /* 0x02e8 */ | ||
| 139 | 140 | ||
| 140 | /* Interrupt response block */ | 141 | /* Interrupt response block */ |
| 141 | __u8 irb[64]; /* 0x0300 */ | 142 | __u8 irb[64]; /* 0x0300 */ |
| @@ -189,14 +190,14 @@ struct _lowcore { | |||
| 189 | __u32 data_exc_code; /* 0x0090 */ | 190 | __u32 data_exc_code; /* 0x0090 */ |
| 190 | __u16 mon_class_num; /* 0x0094 */ | 191 | __u16 mon_class_num; /* 0x0094 */ |
| 191 | __u16 per_perc_atmid; /* 0x0096 */ | 192 | __u16 per_perc_atmid; /* 0x0096 */ |
| 192 | addr_t per_address; /* 0x0098 */ | 193 | __u64 per_address; /* 0x0098 */ |
| 193 | __u8 exc_access_id; /* 0x00a0 */ | 194 | __u8 exc_access_id; /* 0x00a0 */ |
| 194 | __u8 per_access_id; /* 0x00a1 */ | 195 | __u8 per_access_id; /* 0x00a1 */ |
| 195 | __u8 op_access_id; /* 0x00a2 */ | 196 | __u8 op_access_id; /* 0x00a2 */ |
| 196 | __u8 ar_access_id; /* 0x00a3 */ | 197 | __u8 ar_access_id; /* 0x00a3 */ |
| 197 | __u8 pad_0x00a4[0x00a8-0x00a4]; /* 0x00a4 */ | 198 | __u8 pad_0x00a4[0x00a8-0x00a4]; /* 0x00a4 */ |
| 198 | addr_t trans_exc_code; /* 0x00a8 */ | 199 | __u64 trans_exc_code; /* 0x00a8 */ |
| 199 | addr_t monitor_code; /* 0x00b0 */ | 200 | __u64 monitor_code; /* 0x00b0 */ |
| 200 | __u16 subchannel_id; /* 0x00b8 */ | 201 | __u16 subchannel_id; /* 0x00b8 */ |
| 201 | __u16 subchannel_nr; /* 0x00ba */ | 202 | __u16 subchannel_nr; /* 0x00ba */ |
| 202 | __u32 io_int_parm; /* 0x00bc */ | 203 | __u32 io_int_parm; /* 0x00bc */ |
| @@ -207,7 +208,7 @@ struct _lowcore { | |||
| 207 | __u32 mcck_interruption_code[2]; /* 0x00e8 */ | 208 | __u32 mcck_interruption_code[2]; /* 0x00e8 */ |
| 208 | __u8 pad_0x00f0[0x00f4-0x00f0]; /* 0x00f0 */ | 209 | __u8 pad_0x00f0[0x00f4-0x00f0]; /* 0x00f0 */ |
| 209 | __u32 external_damage_code; /* 0x00f4 */ | 210 | __u32 external_damage_code; /* 0x00f4 */ |
| 210 | addr_t failing_storage_address; /* 0x00f8 */ | 211 | __u64 failing_storage_address; /* 0x00f8 */ |
| 211 | __u8 pad_0x0100[0x0110-0x0100]; /* 0x0100 */ | 212 | __u8 pad_0x0100[0x0110-0x0100]; /* 0x0100 */ |
| 212 | __u64 breaking_event_addr; /* 0x0110 */ | 213 | __u64 breaking_event_addr; /* 0x0110 */ |
| 213 | __u8 pad_0x0118[0x0120-0x0118]; /* 0x0118 */ | 214 | __u8 pad_0x0118[0x0120-0x0118]; /* 0x0118 */ |
| @@ -233,39 +234,41 @@ struct _lowcore { | |||
| 233 | /* CPU accounting and timing values. */ | 234 | /* CPU accounting and timing values. */ |
| 234 | __u64 sync_enter_timer; /* 0x02a0 */ | 235 | __u64 sync_enter_timer; /* 0x02a0 */ |
| 235 | __u64 async_enter_timer; /* 0x02a8 */ | 236 | __u64 async_enter_timer; /* 0x02a8 */ |
| 236 | __u64 exit_timer; /* 0x02b0 */ | 237 | __u64 mcck_enter_timer; /* 0x02b0 */ |
| 237 | __u64 user_timer; /* 0x02b8 */ | 238 | __u64 exit_timer; /* 0x02b8 */ |
| 238 | __u64 system_timer; /* 0x02c0 */ | 239 | __u64 user_timer; /* 0x02c0 */ |
| 239 | __u64 steal_timer; /* 0x02c8 */ | 240 | __u64 system_timer; /* 0x02c8 */ |
| 240 | __u64 last_update_timer; /* 0x02d0 */ | 241 | __u64 steal_timer; /* 0x02d0 */ |
| 241 | __u64 last_update_clock; /* 0x02d8 */ | 242 | __u64 last_update_timer; /* 0x02d8 */ |
| 243 | __u64 last_update_clock; /* 0x02e0 */ | ||
| 242 | 244 | ||
| 243 | /* Current process. */ | 245 | /* Current process. */ |
| 244 | __u64 current_task; /* 0x02e0 */ | 246 | __u64 current_task; /* 0x02e8 */ |
| 245 | __u64 thread_info; /* 0x02e8 */ | 247 | __u64 thread_info; /* 0x02f0 */ |
| 246 | __u64 kernel_stack; /* 0x02f0 */ | 248 | __u64 kernel_stack; /* 0x02f8 */ |
| 247 | 249 | ||
| 248 | /* Interrupt and panic stack. */ | 250 | /* Interrupt and panic stack. */ |
| 249 | __u64 async_stack; /* 0x02f8 */ | 251 | __u64 async_stack; /* 0x0300 */ |
| 250 | __u64 panic_stack; /* 0x0300 */ | 252 | __u64 panic_stack; /* 0x0308 */ |
| 251 | 253 | ||
| 252 | /* Address space pointer. */ | 254 | /* Address space pointer. */ |
| 253 | __u64 kernel_asce; /* 0x0308 */ | 255 | __u64 kernel_asce; /* 0x0310 */ |
| 254 | __u64 user_asce; /* 0x0310 */ | 256 | __u64 user_asce; /* 0x0318 */ |
| 255 | __u64 user_exec_asce; /* 0x0318 */ | 257 | __u64 user_exec_asce; /* 0x0320 */ |
| 256 | 258 | ||
| 257 | /* SMP info area */ | 259 | /* SMP info area */ |
| 258 | struct cpuid cpu_id; /* 0x0320 */ | ||
| 259 | __u32 cpu_nr; /* 0x0328 */ | 260 | __u32 cpu_nr; /* 0x0328 */ |
| 260 | __u32 softirq_pending; /* 0x032c */ | 261 | __u32 softirq_pending; /* 0x032c */ |
| 261 | __u64 percpu_offset; /* 0x0330 */ | 262 | __u64 percpu_offset; /* 0x0330 */ |
| 262 | __u64 ext_call_fast; /* 0x0338 */ | 263 | __u64 ext_call_fast; /* 0x0338 */ |
| 263 | __u64 int_clock; /* 0x0340 */ | 264 | __u64 int_clock; /* 0x0340 */ |
| 264 | __u64 clock_comparator; /* 0x0348 */ | 265 | __u64 mcck_clock; /* 0x0348 */ |
| 265 | __u64 vdso_per_cpu_data; /* 0x0350 */ | 266 | __u64 clock_comparator; /* 0x0350 */ |
| 266 | __u64 machine_flags; /* 0x0358 */ | 267 | __u64 vdso_per_cpu_data; /* 0x0358 */ |
| 267 | __u64 ftrace_func; /* 0x0360 */ | 268 | __u64 machine_flags; /* 0x0360 */ |
| 268 | __u8 pad_0x0368[0x0380-0x0368]; /* 0x0368 */ | 269 | __u64 ftrace_func; /* 0x0368 */ |
| 270 | __u64 sie_hook; /* 0x0370 */ | ||
| 271 | __u64 cmf_hpp; /* 0x0378 */ | ||
| 269 | 272 | ||
| 270 | /* Interrupt response block. */ | 273 | /* Interrupt response block. */ |
| 271 | __u8 irb[64]; /* 0x0380 */ | 274 | __u8 irb[64]; /* 0x0380 */ |
diff --git a/arch/s390/include/asm/ptrace.h b/arch/s390/include/asm/ptrace.h index fef9b33cdd59..e2c218dc68a6 100644 --- a/arch/s390/include/asm/ptrace.h +++ b/arch/s390/include/asm/ptrace.h | |||
| @@ -328,8 +328,8 @@ struct pt_regs | |||
| 328 | psw_t psw; | 328 | psw_t psw; |
| 329 | unsigned long gprs[NUM_GPRS]; | 329 | unsigned long gprs[NUM_GPRS]; |
| 330 | unsigned long orig_gpr2; | 330 | unsigned long orig_gpr2; |
| 331 | unsigned short svcnr; | ||
| 332 | unsigned short ilc; | 331 | unsigned short ilc; |
| 332 | unsigned short svcnr; | ||
| 333 | }; | 333 | }; |
| 334 | #endif | 334 | #endif |
| 335 | 335 | ||
| @@ -436,6 +436,7 @@ typedef struct | |||
| 436 | #define PTRACE_PEEKDATA_AREA 0x5003 | 436 | #define PTRACE_PEEKDATA_AREA 0x5003 |
| 437 | #define PTRACE_POKETEXT_AREA 0x5004 | 437 | #define PTRACE_POKETEXT_AREA 0x5004 |
| 438 | #define PTRACE_POKEDATA_AREA 0x5005 | 438 | #define PTRACE_POKEDATA_AREA 0x5005 |
| 439 | #define PTRACE_GET_LAST_BREAK 0x5006 | ||
| 439 | 440 | ||
| 440 | /* | 441 | /* |
| 441 | * PT_PROT definition is loosely based on hppa bsd definition in | 442 | * PT_PROT definition is loosely based on hppa bsd definition in |
diff --git a/arch/s390/include/asm/qdio.h b/arch/s390/include/asm/qdio.h index 9b04b1102bbc..0eaae6260274 100644 --- a/arch/s390/include/asm/qdio.h +++ b/arch/s390/include/asm/qdio.h | |||
| @@ -368,14 +368,12 @@ struct qdio_initialize { | |||
| 368 | #define QDIO_FLAG_SYNC_OUTPUT 0x02 | 368 | #define QDIO_FLAG_SYNC_OUTPUT 0x02 |
| 369 | #define QDIO_FLAG_PCI_OUT 0x10 | 369 | #define QDIO_FLAG_PCI_OUT 0x10 |
| 370 | 370 | ||
| 371 | extern int qdio_initialize(struct qdio_initialize *); | ||
| 372 | extern int qdio_allocate(struct qdio_initialize *); | 371 | extern int qdio_allocate(struct qdio_initialize *); |
| 373 | extern int qdio_establish(struct qdio_initialize *); | 372 | extern int qdio_establish(struct qdio_initialize *); |
| 374 | extern int qdio_activate(struct ccw_device *); | 373 | extern int qdio_activate(struct ccw_device *); |
| 375 | 374 | ||
| 376 | extern int do_QDIO(struct ccw_device *cdev, unsigned int callflags, | 375 | extern int do_QDIO(struct ccw_device *cdev, unsigned int callflags, |
| 377 | int q_nr, unsigned int bufnr, unsigned int count); | 376 | int q_nr, unsigned int bufnr, unsigned int count); |
| 378 | extern int qdio_cleanup(struct ccw_device*, int); | ||
| 379 | extern int qdio_shutdown(struct ccw_device*, int); | 377 | extern int qdio_shutdown(struct ccw_device*, int); |
| 380 | extern int qdio_free(struct ccw_device *); | 378 | extern int qdio_free(struct ccw_device *); |
| 381 | extern int qdio_get_ssqd_desc(struct ccw_device *dev, struct qdio_ssqd_desc*); | 379 | extern int qdio_get_ssqd_desc(struct ccw_device *dev, struct qdio_ssqd_desc*); |
diff --git a/arch/s390/include/asm/setup.h b/arch/s390/include/asm/setup.h index 9ab6bd3a65d1..25e831d58e1e 100644 --- a/arch/s390/include/asm/setup.h +++ b/arch/s390/include/asm/setup.h | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | * include/asm-s390/setup.h | 2 | * include/asm-s390/setup.h |
| 3 | * | 3 | * |
| 4 | * S390 version | 4 | * S390 version |
| 5 | * Copyright IBM Corp. 1999,2006 | 5 | * Copyright IBM Corp. 1999,2010 |
| 6 | */ | 6 | */ |
| 7 | 7 | ||
| 8 | #ifndef _ASM_S390_SETUP_H | 8 | #ifndef _ASM_S390_SETUP_H |
| @@ -72,6 +72,7 @@ extern unsigned int user_mode; | |||
| 72 | #define MACHINE_FLAG_HPAGE (1UL << 10) | 72 | #define MACHINE_FLAG_HPAGE (1UL << 10) |
| 73 | #define MACHINE_FLAG_PFMF (1UL << 11) | 73 | #define MACHINE_FLAG_PFMF (1UL << 11) |
| 74 | #define MACHINE_FLAG_LPAR (1UL << 12) | 74 | #define MACHINE_FLAG_LPAR (1UL << 12) |
| 75 | #define MACHINE_FLAG_SPP (1UL << 13) | ||
| 75 | 76 | ||
| 76 | #define MACHINE_IS_VM (S390_lowcore.machine_flags & MACHINE_FLAG_VM) | 77 | #define MACHINE_IS_VM (S390_lowcore.machine_flags & MACHINE_FLAG_VM) |
| 77 | #define MACHINE_IS_KVM (S390_lowcore.machine_flags & MACHINE_FLAG_KVM) | 78 | #define MACHINE_IS_KVM (S390_lowcore.machine_flags & MACHINE_FLAG_KVM) |
| @@ -88,6 +89,7 @@ extern unsigned int user_mode; | |||
| 88 | #define MACHINE_HAS_MVCOS (0) | 89 | #define MACHINE_HAS_MVCOS (0) |
| 89 | #define MACHINE_HAS_HPAGE (0) | 90 | #define MACHINE_HAS_HPAGE (0) |
| 90 | #define MACHINE_HAS_PFMF (0) | 91 | #define MACHINE_HAS_PFMF (0) |
| 92 | #define MACHINE_HAS_SPP (0) | ||
| 91 | #else /* __s390x__ */ | 93 | #else /* __s390x__ */ |
| 92 | #define MACHINE_HAS_IEEE (1) | 94 | #define MACHINE_HAS_IEEE (1) |
| 93 | #define MACHINE_HAS_CSP (1) | 95 | #define MACHINE_HAS_CSP (1) |
| @@ -97,6 +99,7 @@ extern unsigned int user_mode; | |||
| 97 | #define MACHINE_HAS_MVCOS (S390_lowcore.machine_flags & MACHINE_FLAG_MVCOS) | 99 | #define MACHINE_HAS_MVCOS (S390_lowcore.machine_flags & MACHINE_FLAG_MVCOS) |
| 98 | #define MACHINE_HAS_HPAGE (S390_lowcore.machine_flags & MACHINE_FLAG_HPAGE) | 100 | #define MACHINE_HAS_HPAGE (S390_lowcore.machine_flags & MACHINE_FLAG_HPAGE) |
| 99 | #define MACHINE_HAS_PFMF (S390_lowcore.machine_flags & MACHINE_FLAG_PFMF) | 101 | #define MACHINE_HAS_PFMF (S390_lowcore.machine_flags & MACHINE_FLAG_PFMF) |
| 102 | #define MACHINE_HAS_SPP (S390_lowcore.machine_flags & MACHINE_FLAG_SPP) | ||
| 100 | #endif /* __s390x__ */ | 103 | #endif /* __s390x__ */ |
| 101 | 104 | ||
| 102 | #define ZFCPDUMP_HSA_SIZE (32UL<<20) | 105 | #define ZFCPDUMP_HSA_SIZE (32UL<<20) |
diff --git a/arch/s390/include/asm/system.h b/arch/s390/include/asm/system.h index 1741c1556a4e..cef66210c846 100644 --- a/arch/s390/include/asm/system.h +++ b/arch/s390/include/asm/system.h | |||
| @@ -459,11 +459,6 @@ extern void (*_machine_power_off)(void); | |||
| 459 | 459 | ||
| 460 | #define arch_align_stack(x) (x) | 460 | #define arch_align_stack(x) (x) |
| 461 | 461 | ||
| 462 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
| 463 | extern psw_t sysc_restore_trace_psw; | ||
| 464 | extern psw_t io_restore_trace_psw; | ||
| 465 | #endif | ||
| 466 | |||
| 467 | static inline int tprot(unsigned long addr) | 462 | static inline int tprot(unsigned long addr) |
| 468 | { | 463 | { |
| 469 | int rc = -EFAULT; | 464 | int rc = -EFAULT; |
diff --git a/arch/s390/include/asm/thread_info.h b/arch/s390/include/asm/thread_info.h index 34f0873d6525..be3d3f91d86c 100644 --- a/arch/s390/include/asm/thread_info.h +++ b/arch/s390/include/asm/thread_info.h | |||
| @@ -50,6 +50,7 @@ struct thread_info { | |||
| 50 | struct restart_block restart_block; | 50 | struct restart_block restart_block; |
| 51 | __u64 user_timer; | 51 | __u64 user_timer; |
| 52 | __u64 system_timer; | 52 | __u64 system_timer; |
| 53 | unsigned long last_break; /* last breaking-event-address. */ | ||
| 53 | }; | 54 | }; |
| 54 | 55 | ||
| 55 | /* | 56 | /* |
diff --git a/arch/s390/include/asm/timex.h b/arch/s390/include/asm/timex.h index f174bdaa6b59..09d345a701dc 100644 --- a/arch/s390/include/asm/timex.h +++ b/arch/s390/include/asm/timex.h | |||
| @@ -61,11 +61,15 @@ static inline unsigned long long get_clock (void) | |||
| 61 | return clk; | 61 | return clk; |
| 62 | } | 62 | } |
| 63 | 63 | ||
| 64 | static inline void get_clock_ext(char *clk) | ||
| 65 | { | ||
| 66 | asm volatile("stcke %0" : "=Q" (*clk) : : "cc"); | ||
| 67 | } | ||
| 68 | |||
| 64 | static inline unsigned long long get_clock_xt(void) | 69 | static inline unsigned long long get_clock_xt(void) |
| 65 | { | 70 | { |
| 66 | unsigned char clk[16]; | 71 | unsigned char clk[16]; |
| 67 | 72 | get_clock_ext(clk); | |
| 68 | asm volatile("stcke %0" : "=Q" (clk) : : "cc"); | ||
| 69 | return *((unsigned long long *)&clk[1]); | 73 | return *((unsigned long long *)&clk[1]); |
| 70 | } | 74 | } |
| 71 | 75 | ||
diff --git a/arch/s390/include/asm/topology.h b/arch/s390/include/asm/topology.h index 6e7211abd950..dc8a67297d0f 100644 --- a/arch/s390/include/asm/topology.h +++ b/arch/s390/include/asm/topology.h | |||
| @@ -7,8 +7,10 @@ | |||
| 7 | 7 | ||
| 8 | const struct cpumask *cpu_coregroup_mask(unsigned int cpu); | 8 | const struct cpumask *cpu_coregroup_mask(unsigned int cpu); |
| 9 | 9 | ||
| 10 | extern unsigned char cpu_core_id[NR_CPUS]; | ||
| 10 | extern cpumask_t cpu_core_map[NR_CPUS]; | 11 | extern cpumask_t cpu_core_map[NR_CPUS]; |
| 11 | 12 | ||
| 13 | #define topology_core_id(cpu) (cpu_core_id[cpu]) | ||
| 12 | #define topology_core_cpumask(cpu) (&cpu_core_map[cpu]) | 14 | #define topology_core_cpumask(cpu) (&cpu_core_map[cpu]) |
| 13 | 15 | ||
| 14 | int topology_set_cpu_management(int fc); | 16 | int topology_set_cpu_management(int fc); |
diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c index a09408952ed0..d9b490a2716e 100644 --- a/arch/s390/kernel/asm-offsets.c +++ b/arch/s390/kernel/asm-offsets.c | |||
| @@ -39,6 +39,7 @@ int main(void) | |||
| 39 | DEFINE(__TI_precount, offsetof(struct thread_info, preempt_count)); | 39 | DEFINE(__TI_precount, offsetof(struct thread_info, preempt_count)); |
| 40 | DEFINE(__TI_user_timer, offsetof(struct thread_info, user_timer)); | 40 | DEFINE(__TI_user_timer, offsetof(struct thread_info, user_timer)); |
| 41 | DEFINE(__TI_system_timer, offsetof(struct thread_info, system_timer)); | 41 | DEFINE(__TI_system_timer, offsetof(struct thread_info, system_timer)); |
| 42 | DEFINE(__TI_last_break, offsetof(struct thread_info, last_break)); | ||
| 42 | BLANK(); | 43 | BLANK(); |
| 43 | DEFINE(__PT_ARGS, offsetof(struct pt_regs, args)); | 44 | DEFINE(__PT_ARGS, offsetof(struct pt_regs, args)); |
| 44 | DEFINE(__PT_PSW, offsetof(struct pt_regs, psw)); | 45 | DEFINE(__PT_PSW, offsetof(struct pt_regs, psw)); |
| @@ -112,6 +113,7 @@ int main(void) | |||
| 112 | DEFINE(__LC_RETURN_MCCK_PSW, offsetof(struct _lowcore, return_mcck_psw)); | 113 | DEFINE(__LC_RETURN_MCCK_PSW, offsetof(struct _lowcore, return_mcck_psw)); |
| 113 | DEFINE(__LC_SYNC_ENTER_TIMER, offsetof(struct _lowcore, sync_enter_timer)); | 114 | DEFINE(__LC_SYNC_ENTER_TIMER, offsetof(struct _lowcore, sync_enter_timer)); |
| 114 | DEFINE(__LC_ASYNC_ENTER_TIMER, offsetof(struct _lowcore, async_enter_timer)); | 115 | DEFINE(__LC_ASYNC_ENTER_TIMER, offsetof(struct _lowcore, async_enter_timer)); |
| 116 | DEFINE(__LC_MCCK_ENTER_TIMER, offsetof(struct _lowcore, mcck_enter_timer)); | ||
| 115 | DEFINE(__LC_EXIT_TIMER, offsetof(struct _lowcore, exit_timer)); | 117 | DEFINE(__LC_EXIT_TIMER, offsetof(struct _lowcore, exit_timer)); |
| 116 | DEFINE(__LC_USER_TIMER, offsetof(struct _lowcore, user_timer)); | 118 | DEFINE(__LC_USER_TIMER, offsetof(struct _lowcore, user_timer)); |
| 117 | DEFINE(__LC_SYSTEM_TIMER, offsetof(struct _lowcore, system_timer)); | 119 | DEFINE(__LC_SYSTEM_TIMER, offsetof(struct _lowcore, system_timer)); |
| @@ -126,10 +128,12 @@ int main(void) | |||
| 126 | DEFINE(__LC_KERNEL_ASCE, offsetof(struct _lowcore, kernel_asce)); | 128 | DEFINE(__LC_KERNEL_ASCE, offsetof(struct _lowcore, kernel_asce)); |
| 127 | DEFINE(__LC_USER_ASCE, offsetof(struct _lowcore, user_asce)); | 129 | DEFINE(__LC_USER_ASCE, offsetof(struct _lowcore, user_asce)); |
| 128 | DEFINE(__LC_USER_EXEC_ASCE, offsetof(struct _lowcore, user_exec_asce)); | 130 | DEFINE(__LC_USER_EXEC_ASCE, offsetof(struct _lowcore, user_exec_asce)); |
| 129 | DEFINE(__LC_CPUID, offsetof(struct _lowcore, cpu_id)); | ||
| 130 | DEFINE(__LC_INT_CLOCK, offsetof(struct _lowcore, int_clock)); | 131 | DEFINE(__LC_INT_CLOCK, offsetof(struct _lowcore, int_clock)); |
| 132 | DEFINE(__LC_MCCK_CLOCK, offsetof(struct _lowcore, mcck_clock)); | ||
| 131 | DEFINE(__LC_MACHINE_FLAGS, offsetof(struct _lowcore, machine_flags)); | 133 | DEFINE(__LC_MACHINE_FLAGS, offsetof(struct _lowcore, machine_flags)); |
| 132 | DEFINE(__LC_FTRACE_FUNC, offsetof(struct _lowcore, ftrace_func)); | 134 | DEFINE(__LC_FTRACE_FUNC, offsetof(struct _lowcore, ftrace_func)); |
| 135 | DEFINE(__LC_SIE_HOOK, offsetof(struct _lowcore, sie_hook)); | ||
| 136 | DEFINE(__LC_CMF_HPP, offsetof(struct _lowcore, cmf_hpp)); | ||
| 133 | DEFINE(__LC_IRB, offsetof(struct _lowcore, irb)); | 137 | DEFINE(__LC_IRB, offsetof(struct _lowcore, irb)); |
| 134 | DEFINE(__LC_CPU_TIMER_SAVE_AREA, offsetof(struct _lowcore, cpu_timer_save_area)); | 138 | DEFINE(__LC_CPU_TIMER_SAVE_AREA, offsetof(struct _lowcore, cpu_timer_save_area)); |
| 135 | DEFINE(__LC_CLOCK_COMP_SAVE_AREA, offsetof(struct _lowcore, clock_comp_save_area)); | 139 | DEFINE(__LC_CLOCK_COMP_SAVE_AREA, offsetof(struct _lowcore, clock_comp_save_area)); |
diff --git a/arch/s390/kernel/debug.c b/arch/s390/kernel/debug.c index 0168472b2fdf..98192261491d 100644 --- a/arch/s390/kernel/debug.c +++ b/arch/s390/kernel/debug.c | |||
| @@ -655,6 +655,7 @@ found: | |||
| 655 | p_info->act_entry_offset = 0; | 655 | p_info->act_entry_offset = 0; |
| 656 | file->private_data = p_info; | 656 | file->private_data = p_info; |
| 657 | debug_info_get(debug_info); | 657 | debug_info_get(debug_info); |
| 658 | nonseekable_open(inode, file); | ||
| 658 | out: | 659 | out: |
| 659 | mutex_unlock(&debug_mutex); | 660 | mutex_unlock(&debug_mutex); |
| 660 | return rc; | 661 | return rc; |
diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c index 2d92c2cf92d7..c00856ad4e5a 100644 --- a/arch/s390/kernel/early.c +++ b/arch/s390/kernel/early.c | |||
| @@ -356,6 +356,7 @@ static __init void detect_machine_facilities(void) | |||
| 356 | { | 356 | { |
| 357 | #ifdef CONFIG_64BIT | 357 | #ifdef CONFIG_64BIT |
| 358 | unsigned int facilities; | 358 | unsigned int facilities; |
| 359 | unsigned long long facility_bits; | ||
| 359 | 360 | ||
| 360 | facilities = stfl(); | 361 | facilities = stfl(); |
| 361 | if (facilities & (1 << 28)) | 362 | if (facilities & (1 << 28)) |
| @@ -364,6 +365,9 @@ static __init void detect_machine_facilities(void) | |||
| 364 | S390_lowcore.machine_flags |= MACHINE_FLAG_PFMF; | 365 | S390_lowcore.machine_flags |= MACHINE_FLAG_PFMF; |
| 365 | if (facilities & (1 << 4)) | 366 | if (facilities & (1 << 4)) |
| 366 | S390_lowcore.machine_flags |= MACHINE_FLAG_MVCOS; | 367 | S390_lowcore.machine_flags |= MACHINE_FLAG_MVCOS; |
| 368 | if ((stfle(&facility_bits, 1) > 0) && | ||
| 369 | (facility_bits & (1ULL << (63 - 40)))) | ||
| 370 | S390_lowcore.machine_flags |= MACHINE_FLAG_SPP; | ||
| 367 | #endif | 371 | #endif |
| 368 | } | 372 | } |
| 369 | 373 | ||
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index 6af7045280a8..d5e3e6007447 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S | |||
| @@ -73,21 +73,24 @@ STACK_SIZE = 1 << STACK_SHIFT | |||
| 73 | basr %r14,%r1 | 73 | basr %r14,%r1 |
| 74 | .endm | 74 | .endm |
| 75 | 75 | ||
| 76 | .macro TRACE_IRQS_CHECK | 76 | .macro TRACE_IRQS_CHECK_ON |
| 77 | basr %r2,%r0 | ||
| 78 | tm SP_PSW(%r15),0x03 # irqs enabled? | 77 | tm SP_PSW(%r15),0x03 # irqs enabled? |
| 79 | jz 0f | 78 | bz BASED(0f) |
| 80 | l %r1,BASED(.Ltrace_irq_on_caller) | 79 | TRACE_IRQS_ON |
| 81 | basr %r14,%r1 | 80 | 0: |
| 82 | j 1f | 81 | .endm |
| 83 | 0: l %r1,BASED(.Ltrace_irq_off_caller) | 82 | |
| 84 | basr %r14,%r1 | 83 | .macro TRACE_IRQS_CHECK_OFF |
| 85 | 1: | 84 | tm SP_PSW(%r15),0x03 # irqs enabled? |
| 85 | bz BASED(0f) | ||
| 86 | TRACE_IRQS_OFF | ||
| 87 | 0: | ||
| 86 | .endm | 88 | .endm |
| 87 | #else | 89 | #else |
| 88 | #define TRACE_IRQS_ON | 90 | #define TRACE_IRQS_ON |
| 89 | #define TRACE_IRQS_OFF | 91 | #define TRACE_IRQS_OFF |
| 90 | #define TRACE_IRQS_CHECK | 92 | #define TRACE_IRQS_CHECK_ON |
| 93 | #define TRACE_IRQS_CHECK_OFF | ||
| 91 | #endif | 94 | #endif |
| 92 | 95 | ||
| 93 | #ifdef CONFIG_LOCKDEP | 96 | #ifdef CONFIG_LOCKDEP |
| @@ -177,9 +180,9 @@ STACK_SIZE = 1 << STACK_SHIFT | |||
| 177 | s %r15,BASED(.Lc_spsize) # make room for registers & psw | 180 | s %r15,BASED(.Lc_spsize) # make room for registers & psw |
| 178 | mvc SP_PSW(8,%r15),0(%r12) # move user PSW to stack | 181 | mvc SP_PSW(8,%r15),0(%r12) # move user PSW to stack |
| 179 | st %r2,SP_ORIG_R2(%r15) # store original content of gpr 2 | 182 | st %r2,SP_ORIG_R2(%r15) # store original content of gpr 2 |
| 180 | icm %r12,3,__LC_SVC_ILC | 183 | icm %r12,12,__LC_SVC_ILC |
| 181 | stm %r0,%r11,SP_R0(%r15) # store gprs %r0-%r11 to kernel stack | 184 | stm %r0,%r11,SP_R0(%r15) # store gprs %r0-%r11 to kernel stack |
| 182 | st %r12,SP_SVCNR(%r15) | 185 | st %r12,SP_ILC(%r15) |
| 183 | mvc SP_R12(16,%r15),\savearea # move %r12-%r15 to stack | 186 | mvc SP_R12(16,%r15),\savearea # move %r12-%r15 to stack |
| 184 | la %r12,0 | 187 | la %r12,0 |
| 185 | st %r12,__SF_BACKCHAIN(%r15) # clear back chain | 188 | st %r12,__SF_BACKCHAIN(%r15) # clear back chain |
| @@ -273,66 +276,45 @@ sysc_do_restart: | |||
| 273 | st %r2,SP_R2(%r15) # store return value (change R2 on stack) | 276 | st %r2,SP_R2(%r15) # store return value (change R2 on stack) |
| 274 | 277 | ||
| 275 | sysc_return: | 278 | sysc_return: |
| 279 | LOCKDEP_SYS_EXIT | ||
| 280 | sysc_tif: | ||
| 276 | tm __TI_flags+3(%r9),_TIF_WORK_SVC | 281 | tm __TI_flags+3(%r9),_TIF_WORK_SVC |
| 277 | bnz BASED(sysc_work) # there is work to do (signals etc.) | 282 | bnz BASED(sysc_work) # there is work to do (signals etc.) |
| 278 | sysc_restore: | 283 | sysc_restore: |
| 279 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
| 280 | la %r1,BASED(sysc_restore_trace_psw_addr) | ||
| 281 | l %r1,0(%r1) | ||
| 282 | lpsw 0(%r1) | ||
| 283 | sysc_restore_trace: | ||
| 284 | TRACE_IRQS_CHECK | ||
| 285 | LOCKDEP_SYS_EXIT | ||
| 286 | #endif | ||
| 287 | sysc_leave: | ||
| 288 | RESTORE_ALL __LC_RETURN_PSW,1 | 284 | RESTORE_ALL __LC_RETURN_PSW,1 |
| 289 | sysc_done: | 285 | sysc_done: |
| 290 | 286 | ||
| 291 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
| 292 | sysc_restore_trace_psw_addr: | ||
| 293 | .long sysc_restore_trace_psw | ||
| 294 | |||
| 295 | .section .data,"aw",@progbits | ||
| 296 | .align 8 | ||
| 297 | .globl sysc_restore_trace_psw | ||
| 298 | sysc_restore_trace_psw: | ||
| 299 | .long 0, sysc_restore_trace + 0x80000000 | ||
| 300 | .previous | ||
| 301 | #endif | ||
| 302 | |||
| 303 | # | ||
| 304 | # recheck if there is more work to do | ||
| 305 | # | 287 | # |
| 306 | sysc_work_loop: | 288 | # There is work to do, but first we need to check if we return to userspace. |
| 307 | tm __TI_flags+3(%r9),_TIF_WORK_SVC | ||
| 308 | bz BASED(sysc_restore) # there is no work to do | ||
| 309 | # | ||
| 310 | # One of the work bits is on. Find out which one. | ||
| 311 | # | 289 | # |
| 312 | sysc_work: | 290 | sysc_work: |
| 313 | tm SP_PSW+1(%r15),0x01 # returning to user ? | 291 | tm SP_PSW+1(%r15),0x01 # returning to user ? |
| 314 | bno BASED(sysc_restore) | 292 | bno BASED(sysc_restore) |
| 293 | |||
| 294 | # | ||
| 295 | # One of the work bits is on. Find out which one. | ||
| 296 | # | ||
| 297 | sysc_work_tif: | ||
| 315 | tm __TI_flags+3(%r9),_TIF_MCCK_PENDING | 298 | tm __TI_flags+3(%r9),_TIF_MCCK_PENDING |
| 316 | bo BASED(sysc_mcck_pending) | 299 | bo BASED(sysc_mcck_pending) |
| 317 | tm __TI_flags+3(%r9),_TIF_NEED_RESCHED | 300 | tm __TI_flags+3(%r9),_TIF_NEED_RESCHED |
| 318 | bo BASED(sysc_reschedule) | 301 | bo BASED(sysc_reschedule) |
| 319 | tm __TI_flags+3(%r9),_TIF_SIGPENDING | 302 | tm __TI_flags+3(%r9),_TIF_SIGPENDING |
| 320 | bnz BASED(sysc_sigpending) | 303 | bo BASED(sysc_sigpending) |
| 321 | tm __TI_flags+3(%r9),_TIF_NOTIFY_RESUME | 304 | tm __TI_flags+3(%r9),_TIF_NOTIFY_RESUME |
| 322 | bnz BASED(sysc_notify_resume) | 305 | bo BASED(sysc_notify_resume) |
| 323 | tm __TI_flags+3(%r9),_TIF_RESTART_SVC | 306 | tm __TI_flags+3(%r9),_TIF_RESTART_SVC |
| 324 | bo BASED(sysc_restart) | 307 | bo BASED(sysc_restart) |
| 325 | tm __TI_flags+3(%r9),_TIF_SINGLE_STEP | 308 | tm __TI_flags+3(%r9),_TIF_SINGLE_STEP |
| 326 | bo BASED(sysc_singlestep) | 309 | bo BASED(sysc_singlestep) |
| 327 | b BASED(sysc_restore) | 310 | b BASED(sysc_return) # beware of critical section cleanup |
| 328 | sysc_work_done: | ||
| 329 | 311 | ||
| 330 | # | 312 | # |
| 331 | # _TIF_NEED_RESCHED is set, call schedule | 313 | # _TIF_NEED_RESCHED is set, call schedule |
| 332 | # | 314 | # |
| 333 | sysc_reschedule: | 315 | sysc_reschedule: |
| 334 | l %r1,BASED(.Lschedule) | 316 | l %r1,BASED(.Lschedule) |
| 335 | la %r14,BASED(sysc_work_loop) | 317 | la %r14,BASED(sysc_return) |
| 336 | br %r1 # call scheduler | 318 | br %r1 # call scheduler |
| 337 | 319 | ||
| 338 | # | 320 | # |
| @@ -340,7 +322,7 @@ sysc_reschedule: | |||
| 340 | # | 322 | # |
| 341 | sysc_mcck_pending: | 323 | sysc_mcck_pending: |
| 342 | l %r1,BASED(.Ls390_handle_mcck) | 324 | l %r1,BASED(.Ls390_handle_mcck) |
| 343 | la %r14,BASED(sysc_work_loop) | 325 | la %r14,BASED(sysc_return) |
| 344 | br %r1 # TIF bit will be cleared by handler | 326 | br %r1 # TIF bit will be cleared by handler |
| 345 | 327 | ||
| 346 | # | 328 | # |
| @@ -355,7 +337,7 @@ sysc_sigpending: | |||
| 355 | bo BASED(sysc_restart) | 337 | bo BASED(sysc_restart) |
| 356 | tm __TI_flags+3(%r9),_TIF_SINGLE_STEP | 338 | tm __TI_flags+3(%r9),_TIF_SINGLE_STEP |
| 357 | bo BASED(sysc_singlestep) | 339 | bo BASED(sysc_singlestep) |
| 358 | b BASED(sysc_work_loop) | 340 | b BASED(sysc_return) |
| 359 | 341 | ||
| 360 | # | 342 | # |
| 361 | # _TIF_NOTIFY_RESUME is set, call do_notify_resume | 343 | # _TIF_NOTIFY_RESUME is set, call do_notify_resume |
| @@ -363,7 +345,7 @@ sysc_sigpending: | |||
| 363 | sysc_notify_resume: | 345 | sysc_notify_resume: |
| 364 | la %r2,SP_PTREGS(%r15) # load pt_regs | 346 | la %r2,SP_PTREGS(%r15) # load pt_regs |
| 365 | l %r1,BASED(.Ldo_notify_resume) | 347 | l %r1,BASED(.Ldo_notify_resume) |
| 366 | la %r14,BASED(sysc_work_loop) | 348 | la %r14,BASED(sysc_return) |
| 367 | br %r1 # call do_notify_resume | 349 | br %r1 # call do_notify_resume |
| 368 | 350 | ||
| 369 | 351 | ||
| @@ -458,11 +440,13 @@ kernel_execve: | |||
| 458 | br %r14 | 440 | br %r14 |
| 459 | # execve succeeded. | 441 | # execve succeeded. |
| 460 | 0: stnsm __SF_EMPTY(%r15),0xfc # disable interrupts | 442 | 0: stnsm __SF_EMPTY(%r15),0xfc # disable interrupts |
| 443 | TRACE_IRQS_OFF | ||
| 461 | l %r15,__LC_KERNEL_STACK # load ksp | 444 | l %r15,__LC_KERNEL_STACK # load ksp |
| 462 | s %r15,BASED(.Lc_spsize) # make room for registers & psw | 445 | s %r15,BASED(.Lc_spsize) # make room for registers & psw |
| 463 | l %r9,__LC_THREAD_INFO | 446 | l %r9,__LC_THREAD_INFO |
| 464 | mvc SP_PTREGS(__PT_SIZE,%r15),0(%r12) # copy pt_regs | 447 | mvc SP_PTREGS(__PT_SIZE,%r15),0(%r12) # copy pt_regs |
| 465 | xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) | 448 | xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) |
| 449 | TRACE_IRQS_ON | ||
| 466 | stosm __SF_EMPTY(%r15),0x03 # reenable interrupts | 450 | stosm __SF_EMPTY(%r15),0x03 # reenable interrupts |
| 467 | l %r1,BASED(.Lexecve_tail) | 451 | l %r1,BASED(.Lexecve_tail) |
| 468 | basr %r14,%r1 | 452 | basr %r14,%r1 |
| @@ -499,8 +483,8 @@ pgm_check_handler: | |||
| 499 | UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER | 483 | UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER |
| 500 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER | 484 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER |
| 501 | pgm_no_vtime: | 485 | pgm_no_vtime: |
| 486 | TRACE_IRQS_CHECK_OFF | ||
| 502 | l %r9,__LC_THREAD_INFO # load pointer to thread_info struct | 487 | l %r9,__LC_THREAD_INFO # load pointer to thread_info struct |
| 503 | TRACE_IRQS_OFF | ||
| 504 | l %r3,__LC_PGM_ILC # load program interruption code | 488 | l %r3,__LC_PGM_ILC # load program interruption code |
| 505 | la %r8,0x7f | 489 | la %r8,0x7f |
| 506 | nr %r8,%r3 | 490 | nr %r8,%r3 |
| @@ -509,8 +493,10 @@ pgm_do_call: | |||
| 509 | sll %r8,2 | 493 | sll %r8,2 |
| 510 | l %r7,0(%r8,%r7) # load address of handler routine | 494 | l %r7,0(%r8,%r7) # load address of handler routine |
| 511 | la %r2,SP_PTREGS(%r15) # address of register-save area | 495 | la %r2,SP_PTREGS(%r15) # address of register-save area |
| 512 | la %r14,BASED(sysc_return) | 496 | basr %r14,%r7 # branch to interrupt-handler |
| 513 | br %r7 # branch to interrupt-handler | 497 | pgm_exit: |
| 498 | TRACE_IRQS_CHECK_ON | ||
| 499 | b BASED(sysc_return) | ||
| 514 | 500 | ||
| 515 | # | 501 | # |
| 516 | # handle per exception | 502 | # handle per exception |
| @@ -537,19 +523,19 @@ pgm_per_std: | |||
| 537 | UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER | 523 | UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER |
| 538 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER | 524 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER |
| 539 | pgm_no_vtime2: | 525 | pgm_no_vtime2: |
| 526 | TRACE_IRQS_CHECK_OFF | ||
| 540 | l %r9,__LC_THREAD_INFO # load pointer to thread_info struct | 527 | l %r9,__LC_THREAD_INFO # load pointer to thread_info struct |
| 541 | TRACE_IRQS_OFF | ||
| 542 | l %r1,__TI_task(%r9) | 528 | l %r1,__TI_task(%r9) |
| 529 | tm SP_PSW+1(%r15),0x01 # kernel per event ? | ||
| 530 | bz BASED(kernel_per) | ||
| 543 | mvc __THREAD_per+__PER_atmid(2,%r1),__LC_PER_ATMID | 531 | mvc __THREAD_per+__PER_atmid(2,%r1),__LC_PER_ATMID |
| 544 | mvc __THREAD_per+__PER_address(4,%r1),__LC_PER_ADDRESS | 532 | mvc __THREAD_per+__PER_address(4,%r1),__LC_PER_ADDRESS |
| 545 | mvc __THREAD_per+__PER_access_id(1,%r1),__LC_PER_ACCESS_ID | 533 | mvc __THREAD_per+__PER_access_id(1,%r1),__LC_PER_ACCESS_ID |
| 546 | oi __TI_flags+3(%r9),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP | 534 | oi __TI_flags+3(%r9),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP |
| 547 | tm SP_PSW+1(%r15),0x01 # kernel per event ? | ||
| 548 | bz BASED(kernel_per) | ||
| 549 | l %r3,__LC_PGM_ILC # load program interruption code | 535 | l %r3,__LC_PGM_ILC # load program interruption code |
| 550 | la %r8,0x7f | 536 | la %r8,0x7f |
| 551 | nr %r8,%r3 # clear per-event-bit and ilc | 537 | nr %r8,%r3 # clear per-event-bit and ilc |
| 552 | be BASED(sysc_return) # only per or per+check ? | 538 | be BASED(pgm_exit) # only per or per+check ? |
| 553 | b BASED(pgm_do_call) | 539 | b BASED(pgm_do_call) |
| 554 | 540 | ||
| 555 | # | 541 | # |
| @@ -570,8 +556,8 @@ pgm_svcper: | |||
| 570 | mvc __THREAD_per+__PER_access_id(1,%r8),__LC_PER_ACCESS_ID | 556 | mvc __THREAD_per+__PER_access_id(1,%r8),__LC_PER_ACCESS_ID |
| 571 | oi __TI_flags+3(%r9),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP | 557 | oi __TI_flags+3(%r9),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP |
| 572 | TRACE_IRQS_ON | 558 | TRACE_IRQS_ON |
| 573 | lm %r2,%r6,SP_R2(%r15) # load svc arguments | ||
| 574 | stosm __SF_EMPTY(%r15),0x03 # reenable interrupts | 559 | stosm __SF_EMPTY(%r15),0x03 # reenable interrupts |
| 560 | lm %r2,%r6,SP_R2(%r15) # load svc arguments | ||
| 575 | b BASED(sysc_do_svc) | 561 | b BASED(sysc_do_svc) |
| 576 | 562 | ||
| 577 | # | 563 | # |
| @@ -582,8 +568,8 @@ kernel_per: | |||
| 582 | mvi SP_SVCNR+1(%r15),0xff | 568 | mvi SP_SVCNR+1(%r15),0xff |
| 583 | la %r2,SP_PTREGS(%r15) # address of register-save area | 569 | la %r2,SP_PTREGS(%r15) # address of register-save area |
| 584 | l %r1,BASED(.Lhandle_per) # load adr. of per handler | 570 | l %r1,BASED(.Lhandle_per) # load adr. of per handler |
| 585 | la %r14,BASED(sysc_restore)# load adr. of system return | 571 | basr %r14,%r1 # branch to do_single_step |
| 586 | br %r1 # branch to do_single_step | 572 | b BASED(pgm_exit) |
| 587 | 573 | ||
| 588 | /* | 574 | /* |
| 589 | * IO interrupt handler routine | 575 | * IO interrupt handler routine |
| @@ -602,134 +588,126 @@ io_int_handler: | |||
| 602 | UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER | 588 | UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER |
| 603 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER | 589 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER |
| 604 | io_no_vtime: | 590 | io_no_vtime: |
| 605 | l %r9,__LC_THREAD_INFO # load pointer to thread_info struct | ||
| 606 | TRACE_IRQS_OFF | 591 | TRACE_IRQS_OFF |
| 592 | l %r9,__LC_THREAD_INFO # load pointer to thread_info struct | ||
| 607 | l %r1,BASED(.Ldo_IRQ) # load address of do_IRQ | 593 | l %r1,BASED(.Ldo_IRQ) # load address of do_IRQ |
| 608 | la %r2,SP_PTREGS(%r15) # address of register-save area | 594 | la %r2,SP_PTREGS(%r15) # address of register-save area |
| 609 | basr %r14,%r1 # branch to standard irq handler | 595 | basr %r14,%r1 # branch to standard irq handler |
| 610 | io_return: | 596 | io_return: |
| 597 | LOCKDEP_SYS_EXIT | ||
| 598 | TRACE_IRQS_ON | ||
| 599 | io_tif: | ||
| 611 | tm __TI_flags+3(%r9),_TIF_WORK_INT | 600 | tm __TI_flags+3(%r9),_TIF_WORK_INT |
| 612 | bnz BASED(io_work) # there is work to do (signals etc.) | 601 | bnz BASED(io_work) # there is work to do (signals etc.) |
| 613 | io_restore: | 602 | io_restore: |
| 614 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
| 615 | la %r1,BASED(io_restore_trace_psw_addr) | ||
| 616 | l %r1,0(%r1) | ||
| 617 | lpsw 0(%r1) | ||
| 618 | io_restore_trace: | ||
| 619 | TRACE_IRQS_CHECK | ||
| 620 | LOCKDEP_SYS_EXIT | ||
| 621 | #endif | ||
| 622 | io_leave: | ||
| 623 | RESTORE_ALL __LC_RETURN_PSW,0 | 603 | RESTORE_ALL __LC_RETURN_PSW,0 |
| 624 | io_done: | 604 | io_done: |
| 625 | 605 | ||
| 626 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
| 627 | io_restore_trace_psw_addr: | ||
| 628 | .long io_restore_trace_psw | ||
| 629 | |||
| 630 | .section .data,"aw",@progbits | ||
| 631 | .align 8 | ||
| 632 | .globl io_restore_trace_psw | ||
| 633 | io_restore_trace_psw: | ||
| 634 | .long 0, io_restore_trace + 0x80000000 | ||
| 635 | .previous | ||
| 636 | #endif | ||
| 637 | |||
| 638 | # | 606 | # |
| 639 | # switch to kernel stack, then check the TIF bits | 607 | # There is work todo, find out in which context we have been interrupted: |
| 608 | # 1) if we return to user space we can do all _TIF_WORK_INT work | ||
| 609 | # 2) if we return to kernel code and preemptive scheduling is enabled check | ||
| 610 | # the preemption counter and if it is zero call preempt_schedule_irq | ||
| 611 | # Before any work can be done, a switch to the kernel stack is required. | ||
| 640 | # | 612 | # |
| 641 | io_work: | 613 | io_work: |
| 642 | tm SP_PSW+1(%r15),0x01 # returning to user ? | 614 | tm SP_PSW+1(%r15),0x01 # returning to user ? |
| 643 | #ifndef CONFIG_PREEMPT | 615 | bo BASED(io_work_user) # yes -> do resched & signal |
| 644 | bno BASED(io_restore) # no-> skip resched & signal | 616 | #ifdef CONFIG_PREEMPT |
| 645 | #else | ||
| 646 | bnz BASED(io_work_user) # no -> check for preemptive scheduling | ||
| 647 | # check for preemptive scheduling | 617 | # check for preemptive scheduling |
| 648 | icm %r0,15,__TI_precount(%r9) | 618 | icm %r0,15,__TI_precount(%r9) |
| 649 | bnz BASED(io_restore) # preemption disabled | 619 | bnz BASED(io_restore) # preemption disabled |
| 620 | tm __TI_flags+3(%r9),_TIF_NEED_RESCHED | ||
| 621 | bno BASED(io_restore) | ||
| 622 | # switch to kernel stack | ||
| 650 | l %r1,SP_R15(%r15) | 623 | l %r1,SP_R15(%r15) |
| 651 | s %r1,BASED(.Lc_spsize) | 624 | s %r1,BASED(.Lc_spsize) |
| 652 | mvc SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15) | 625 | mvc SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15) |
| 653 | xc __SF_BACKCHAIN(4,%r1),__SF_BACKCHAIN(%r1) # clear back chain | 626 | xc __SF_BACKCHAIN(4,%r1),__SF_BACKCHAIN(%r1) # clear back chain |
| 654 | lr %r15,%r1 | 627 | lr %r15,%r1 |
| 655 | io_resume_loop: | 628 | # TRACE_IRQS_ON already done at io_return, call |
| 656 | tm __TI_flags+3(%r9),_TIF_NEED_RESCHED | 629 | # TRACE_IRQS_OFF to keep things symmetrical |
| 657 | bno BASED(io_restore) | 630 | TRACE_IRQS_OFF |
| 658 | l %r1,BASED(.Lpreempt_schedule_irq) | 631 | l %r1,BASED(.Lpreempt_schedule_irq) |
| 659 | la %r14,BASED(io_resume_loop) | 632 | basr %r14,%r1 # call preempt_schedule_irq |
| 660 | br %r1 # call schedule | 633 | b BASED(io_return) |
| 634 | #else | ||
| 635 | b BASED(io_restore) | ||
| 661 | #endif | 636 | #endif |
| 662 | 637 | ||
| 638 | # | ||
| 639 | # Need to do work before returning to userspace, switch to kernel stack | ||
| 640 | # | ||
| 663 | io_work_user: | 641 | io_work_user: |
| 664 | l %r1,__LC_KERNEL_STACK | 642 | l %r1,__LC_KERNEL_STACK |
| 665 | s %r1,BASED(.Lc_spsize) | 643 | s %r1,BASED(.Lc_spsize) |
| 666 | mvc SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15) | 644 | mvc SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15) |
| 667 | xc __SF_BACKCHAIN(4,%r1),__SF_BACKCHAIN(%r1) # clear back chain | 645 | xc __SF_BACKCHAIN(4,%r1),__SF_BACKCHAIN(%r1) # clear back chain |
| 668 | lr %r15,%r1 | 646 | lr %r15,%r1 |
| 647 | |||
| 669 | # | 648 | # |
| 670 | # One of the work bits is on. Find out which one. | 649 | # One of the work bits is on. Find out which one. |
| 671 | # Checked are: _TIF_SIGPENDING, _TIF_NEED_RESCHED | 650 | # Checked are: _TIF_SIGPENDING, _TIF_NOTIFY_RESUME, _TIF_NEED_RESCHED |
| 672 | # and _TIF_MCCK_PENDING | 651 | # and _TIF_MCCK_PENDING |
| 673 | # | 652 | # |
| 674 | io_work_loop: | 653 | io_work_tif: |
| 675 | tm __TI_flags+3(%r9),_TIF_MCCK_PENDING | 654 | tm __TI_flags+3(%r9),_TIF_MCCK_PENDING |
| 676 | bo BASED(io_mcck_pending) | 655 | bo BASED(io_mcck_pending) |
| 677 | tm __TI_flags+3(%r9),_TIF_NEED_RESCHED | 656 | tm __TI_flags+3(%r9),_TIF_NEED_RESCHED |
| 678 | bo BASED(io_reschedule) | 657 | bo BASED(io_reschedule) |
| 679 | tm __TI_flags+3(%r9),_TIF_SIGPENDING | 658 | tm __TI_flags+3(%r9),_TIF_SIGPENDING |
| 680 | bnz BASED(io_sigpending) | 659 | bo BASED(io_sigpending) |
| 681 | tm __TI_flags+3(%r9),_TIF_NOTIFY_RESUME | 660 | tm __TI_flags+3(%r9),_TIF_NOTIFY_RESUME |
| 682 | bnz BASED(io_notify_resume) | 661 | bo BASED(io_notify_resume) |
| 683 | b BASED(io_restore) | 662 | b BASED(io_return) # beware of critical section cleanup |
| 684 | io_work_done: | ||
| 685 | 663 | ||
| 686 | # | 664 | # |
| 687 | # _TIF_MCCK_PENDING is set, call handler | 665 | # _TIF_MCCK_PENDING is set, call handler |
| 688 | # | 666 | # |
| 689 | io_mcck_pending: | 667 | io_mcck_pending: |
| 668 | # TRACE_IRQS_ON already done at io_return | ||
| 690 | l %r1,BASED(.Ls390_handle_mcck) | 669 | l %r1,BASED(.Ls390_handle_mcck) |
| 691 | basr %r14,%r1 # TIF bit will be cleared by handler | 670 | basr %r14,%r1 # TIF bit will be cleared by handler |
| 692 | b BASED(io_work_loop) | 671 | TRACE_IRQS_OFF |
| 672 | b BASED(io_return) | ||
| 693 | 673 | ||
| 694 | # | 674 | # |
| 695 | # _TIF_NEED_RESCHED is set, call schedule | 675 | # _TIF_NEED_RESCHED is set, call schedule |
| 696 | # | 676 | # |
| 697 | io_reschedule: | 677 | io_reschedule: |
| 698 | TRACE_IRQS_ON | 678 | # TRACE_IRQS_ON already done at io_return |
| 699 | l %r1,BASED(.Lschedule) | 679 | l %r1,BASED(.Lschedule) |
| 700 | stosm __SF_EMPTY(%r15),0x03 # reenable interrupts | 680 | stosm __SF_EMPTY(%r15),0x03 # reenable interrupts |
| 701 | basr %r14,%r1 # call scheduler | 681 | basr %r14,%r1 # call scheduler |
| 702 | stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts | 682 | stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts |
| 703 | TRACE_IRQS_OFF | 683 | TRACE_IRQS_OFF |
| 704 | tm __TI_flags+3(%r9),_TIF_WORK_INT | 684 | b BASED(io_return) |
| 705 | bz BASED(io_restore) # there is no work to do | ||
| 706 | b BASED(io_work_loop) | ||
| 707 | 685 | ||
| 708 | # | 686 | # |
| 709 | # _TIF_SIGPENDING is set, call do_signal | 687 | # _TIF_SIGPENDING is set, call do_signal |
| 710 | # | 688 | # |
| 711 | io_sigpending: | 689 | io_sigpending: |
| 712 | TRACE_IRQS_ON | 690 | # TRACE_IRQS_ON already done at io_return |
| 713 | stosm __SF_EMPTY(%r15),0x03 # reenable interrupts | 691 | stosm __SF_EMPTY(%r15),0x03 # reenable interrupts |
| 714 | la %r2,SP_PTREGS(%r15) # load pt_regs | 692 | la %r2,SP_PTREGS(%r15) # load pt_regs |
| 715 | l %r1,BASED(.Ldo_signal) | 693 | l %r1,BASED(.Ldo_signal) |
| 716 | basr %r14,%r1 # call do_signal | 694 | basr %r14,%r1 # call do_signal |
| 717 | stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts | 695 | stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts |
| 718 | TRACE_IRQS_OFF | 696 | TRACE_IRQS_OFF |
| 719 | b BASED(io_work_loop) | 697 | b BASED(io_return) |
| 720 | 698 | ||
| 721 | # | 699 | # |
| 722 | # _TIF_SIGPENDING is set, call do_signal | 700 | # _TIF_SIGPENDING is set, call do_signal |
| 723 | # | 701 | # |
| 724 | io_notify_resume: | 702 | io_notify_resume: |
| 725 | TRACE_IRQS_ON | 703 | # TRACE_IRQS_ON already done at io_return |
| 726 | stosm __SF_EMPTY(%r15),0x03 # reenable interrupts | 704 | stosm __SF_EMPTY(%r15),0x03 # reenable interrupts |
| 727 | la %r2,SP_PTREGS(%r15) # load pt_regs | 705 | la %r2,SP_PTREGS(%r15) # load pt_regs |
| 728 | l %r1,BASED(.Ldo_notify_resume) | 706 | l %r1,BASED(.Ldo_notify_resume) |
| 729 | basr %r14,%r1 # call do_signal | 707 | basr %r14,%r1 # call do_signal |
| 730 | stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts | 708 | stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts |
| 731 | TRACE_IRQS_OFF | 709 | TRACE_IRQS_OFF |
| 732 | b BASED(io_work_loop) | 710 | b BASED(io_return) |
| 733 | 711 | ||
| 734 | /* | 712 | /* |
| 735 | * External interrupt handler routine | 713 | * External interrupt handler routine |
| @@ -764,15 +742,14 @@ __critical_end: | |||
| 764 | 742 | ||
| 765 | .globl mcck_int_handler | 743 | .globl mcck_int_handler |
| 766 | mcck_int_handler: | 744 | mcck_int_handler: |
| 767 | stck __LC_INT_CLOCK | 745 | stck __LC_MCCK_CLOCK |
| 768 | spt __LC_CPU_TIMER_SAVE_AREA # revalidate cpu timer | 746 | spt __LC_CPU_TIMER_SAVE_AREA # revalidate cpu timer |
| 769 | lm %r0,%r15,__LC_GPREGS_SAVE_AREA # revalidate gprs | 747 | lm %r0,%r15,__LC_GPREGS_SAVE_AREA # revalidate gprs |
| 770 | SAVE_ALL_BASE __LC_SAVE_AREA+32 | 748 | SAVE_ALL_BASE __LC_SAVE_AREA+32 |
| 771 | la %r12,__LC_MCK_OLD_PSW | 749 | la %r12,__LC_MCK_OLD_PSW |
| 772 | tm __LC_MCCK_CODE,0x80 # system damage? | 750 | tm __LC_MCCK_CODE,0x80 # system damage? |
| 773 | bo BASED(mcck_int_main) # yes -> rest of mcck code invalid | 751 | bo BASED(mcck_int_main) # yes -> rest of mcck code invalid |
| 774 | mvc __LC_SAVE_AREA+52(8),__LC_ASYNC_ENTER_TIMER | 752 | mvc __LC_MCCK_ENTER_TIMER(8),__LC_CPU_TIMER_SAVE_AREA |
| 775 | mvc __LC_ASYNC_ENTER_TIMER(8),__LC_CPU_TIMER_SAVE_AREA | ||
| 776 | tm __LC_MCCK_CODE+5,0x02 # stored cpu timer value valid? | 753 | tm __LC_MCCK_CODE+5,0x02 # stored cpu timer value valid? |
| 777 | bo BASED(1f) | 754 | bo BASED(1f) |
| 778 | la %r14,__LC_SYNC_ENTER_TIMER | 755 | la %r14,__LC_SYNC_ENTER_TIMER |
| @@ -786,7 +763,7 @@ mcck_int_handler: | |||
| 786 | bl BASED(0f) | 763 | bl BASED(0f) |
| 787 | la %r14,__LC_LAST_UPDATE_TIMER | 764 | la %r14,__LC_LAST_UPDATE_TIMER |
| 788 | 0: spt 0(%r14) | 765 | 0: spt 0(%r14) |
| 789 | mvc __LC_ASYNC_ENTER_TIMER(8),0(%r14) | 766 | mvc __LC_MCCK_ENTER_TIMER(8),0(%r14) |
| 790 | 1: tm __LC_MCCK_CODE+2,0x09 # mwp + ia of old psw valid? | 767 | 1: tm __LC_MCCK_CODE+2,0x09 # mwp + ia of old psw valid? |
| 791 | bno BASED(mcck_int_main) # no -> skip cleanup critical | 768 | bno BASED(mcck_int_main) # no -> skip cleanup critical |
| 792 | tm __LC_MCK_OLD_PSW+1,0x01 # test problem state bit | 769 | tm __LC_MCK_OLD_PSW+1,0x01 # test problem state bit |
| @@ -808,9 +785,9 @@ mcck_int_main: | |||
| 808 | bno BASED(mcck_no_vtime) # no -> skip cleanup critical | 785 | bno BASED(mcck_no_vtime) # no -> skip cleanup critical |
| 809 | tm SP_PSW+1(%r15),0x01 # interrupting from user ? | 786 | tm SP_PSW+1(%r15),0x01 # interrupting from user ? |
| 810 | bz BASED(mcck_no_vtime) | 787 | bz BASED(mcck_no_vtime) |
| 811 | UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER | 788 | UPDATE_VTIME __LC_EXIT_TIMER,__LC_MCCK_ENTER_TIMER,__LC_USER_TIMER |
| 812 | UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER | 789 | UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER |
| 813 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER | 790 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_MCCK_ENTER_TIMER |
| 814 | mcck_no_vtime: | 791 | mcck_no_vtime: |
| 815 | l %r9,__LC_THREAD_INFO # load pointer to thread_info struct | 792 | l %r9,__LC_THREAD_INFO # load pointer to thread_info struct |
| 816 | la %r2,SP_PTREGS(%r15) # load pt_regs | 793 | la %r2,SP_PTREGS(%r15) # load pt_regs |
| @@ -833,7 +810,6 @@ mcck_no_vtime: | |||
| 833 | mcck_return: | 810 | mcck_return: |
| 834 | mvc __LC_RETURN_MCCK_PSW(8),SP_PSW(%r15) # move return PSW | 811 | mvc __LC_RETURN_MCCK_PSW(8),SP_PSW(%r15) # move return PSW |
| 835 | ni __LC_RETURN_MCCK_PSW+1,0xfd # clear wait state bit | 812 | ni __LC_RETURN_MCCK_PSW+1,0xfd # clear wait state bit |
| 836 | mvc __LC_ASYNC_ENTER_TIMER(8),__LC_SAVE_AREA+52 | ||
| 837 | tm __LC_RETURN_MCCK_PSW+1,0x01 # returning to user ? | 813 | tm __LC_RETURN_MCCK_PSW+1,0x01 # returning to user ? |
| 838 | bno BASED(0f) | 814 | bno BASED(0f) |
| 839 | lm %r0,%r15,SP_R0(%r15) # load gprs 0-15 | 815 | lm %r0,%r15,SP_R0(%r15) # load gprs 0-15 |
| @@ -917,18 +893,14 @@ stack_overflow: | |||
| 917 | 893 | ||
| 918 | cleanup_table_system_call: | 894 | cleanup_table_system_call: |
| 919 | .long system_call + 0x80000000, sysc_do_svc + 0x80000000 | 895 | .long system_call + 0x80000000, sysc_do_svc + 0x80000000 |
| 920 | cleanup_table_sysc_return: | 896 | cleanup_table_sysc_tif: |
| 921 | .long sysc_return + 0x80000000, sysc_leave + 0x80000000 | 897 | .long sysc_tif + 0x80000000, sysc_restore + 0x80000000 |
| 922 | cleanup_table_sysc_leave: | 898 | cleanup_table_sysc_restore: |
| 923 | .long sysc_leave + 0x80000000, sysc_done + 0x80000000 | 899 | .long sysc_restore + 0x80000000, sysc_done + 0x80000000 |
| 924 | cleanup_table_sysc_work_loop: | 900 | cleanup_table_io_tif: |
| 925 | .long sysc_work_loop + 0x80000000, sysc_work_done + 0x80000000 | 901 | .long io_tif + 0x80000000, io_restore + 0x80000000 |
| 926 | cleanup_table_io_return: | 902 | cleanup_table_io_restore: |
| 927 | .long io_return + 0x80000000, io_leave + 0x80000000 | 903 | .long io_restore + 0x80000000, io_done + 0x80000000 |
| 928 | cleanup_table_io_leave: | ||
| 929 | .long io_leave + 0x80000000, io_done + 0x80000000 | ||
| 930 | cleanup_table_io_work_loop: | ||
| 931 | .long io_work_loop + 0x80000000, io_work_done + 0x80000000 | ||
| 932 | 904 | ||
| 933 | cleanup_critical: | 905 | cleanup_critical: |
| 934 | clc 4(4,%r12),BASED(cleanup_table_system_call) | 906 | clc 4(4,%r12),BASED(cleanup_table_system_call) |
| @@ -936,49 +908,40 @@ cleanup_critical: | |||
| 936 | clc 4(4,%r12),BASED(cleanup_table_system_call+4) | 908 | clc 4(4,%r12),BASED(cleanup_table_system_call+4) |
| 937 | bl BASED(cleanup_system_call) | 909 | bl BASED(cleanup_system_call) |
| 938 | 0: | 910 | 0: |
| 939 | clc 4(4,%r12),BASED(cleanup_table_sysc_return) | 911 | clc 4(4,%r12),BASED(cleanup_table_sysc_tif) |
| 940 | bl BASED(0f) | ||
| 941 | clc 4(4,%r12),BASED(cleanup_table_sysc_return+4) | ||
| 942 | bl BASED(cleanup_sysc_return) | ||
| 943 | 0: | ||
| 944 | clc 4(4,%r12),BASED(cleanup_table_sysc_leave) | ||
| 945 | bl BASED(0f) | ||
| 946 | clc 4(4,%r12),BASED(cleanup_table_sysc_leave+4) | ||
| 947 | bl BASED(cleanup_sysc_leave) | ||
| 948 | 0: | ||
| 949 | clc 4(4,%r12),BASED(cleanup_table_sysc_work_loop) | ||
| 950 | bl BASED(0f) | 912 | bl BASED(0f) |
| 951 | clc 4(4,%r12),BASED(cleanup_table_sysc_work_loop+4) | 913 | clc 4(4,%r12),BASED(cleanup_table_sysc_tif+4) |
| 952 | bl BASED(cleanup_sysc_return) | 914 | bl BASED(cleanup_sysc_tif) |
| 953 | 0: | 915 | 0: |
| 954 | clc 4(4,%r12),BASED(cleanup_table_io_return) | 916 | clc 4(4,%r12),BASED(cleanup_table_sysc_restore) |
| 955 | bl BASED(0f) | 917 | bl BASED(0f) |
| 956 | clc 4(4,%r12),BASED(cleanup_table_io_return+4) | 918 | clc 4(4,%r12),BASED(cleanup_table_sysc_restore+4) |
| 957 | bl BASED(cleanup_io_return) | 919 | bl BASED(cleanup_sysc_restore) |
| 958 | 0: | 920 | 0: |
| 959 | clc 4(4,%r12),BASED(cleanup_table_io_leave) | 921 | clc 4(4,%r12),BASED(cleanup_table_io_tif) |
| 960 | bl BASED(0f) | 922 | bl BASED(0f) |
| 961 | clc 4(4,%r12),BASED(cleanup_table_io_leave+4) | 923 | clc 4(4,%r12),BASED(cleanup_table_io_tif+4) |
| 962 | bl BASED(cleanup_io_leave) | 924 | bl BASED(cleanup_io_tif) |
| 963 | 0: | 925 | 0: |
| 964 | clc 4(4,%r12),BASED(cleanup_table_io_work_loop) | 926 | clc 4(4,%r12),BASED(cleanup_table_io_restore) |
| 965 | bl BASED(0f) | 927 | bl BASED(0f) |
| 966 | clc 4(4,%r12),BASED(cleanup_table_io_work_loop+4) | 928 | clc 4(4,%r12),BASED(cleanup_table_io_restore+4) |
| 967 | bl BASED(cleanup_io_work_loop) | 929 | bl BASED(cleanup_io_restore) |
| 968 | 0: | 930 | 0: |
| 969 | br %r14 | 931 | br %r14 |
| 970 | 932 | ||
| 971 | cleanup_system_call: | 933 | cleanup_system_call: |
| 972 | mvc __LC_RETURN_PSW(8),0(%r12) | 934 | mvc __LC_RETURN_PSW(8),0(%r12) |
| 973 | c %r12,BASED(.Lmck_old_psw) | ||
| 974 | be BASED(0f) | ||
| 975 | la %r12,__LC_SAVE_AREA+16 | ||
| 976 | b BASED(1f) | ||
| 977 | 0: la %r12,__LC_SAVE_AREA+32 | ||
| 978 | 1: | ||
| 979 | clc __LC_RETURN_PSW+4(4),BASED(cleanup_system_call_insn+4) | 935 | clc __LC_RETURN_PSW+4(4),BASED(cleanup_system_call_insn+4) |
| 980 | bh BASED(0f) | 936 | bh BASED(0f) |
| 937 | mvc __LC_SYNC_ENTER_TIMER(8),__LC_MCCK_ENTER_TIMER | ||
| 938 | c %r12,BASED(.Lmck_old_psw) | ||
| 939 | be BASED(0f) | ||
| 981 | mvc __LC_SYNC_ENTER_TIMER(8),__LC_ASYNC_ENTER_TIMER | 940 | mvc __LC_SYNC_ENTER_TIMER(8),__LC_ASYNC_ENTER_TIMER |
| 941 | 0: c %r12,BASED(.Lmck_old_psw) | ||
| 942 | la %r12,__LC_SAVE_AREA+32 | ||
| 943 | be BASED(0f) | ||
| 944 | la %r12,__LC_SAVE_AREA+16 | ||
| 982 | 0: clc __LC_RETURN_PSW+4(4),BASED(cleanup_system_call_insn+8) | 945 | 0: clc __LC_RETURN_PSW+4(4),BASED(cleanup_system_call_insn+8) |
| 983 | bhe BASED(cleanup_vtime) | 946 | bhe BASED(cleanup_vtime) |
| 984 | clc __LC_RETURN_PSW+4(4),BASED(cleanup_system_call_insn) | 947 | clc __LC_RETURN_PSW+4(4),BASED(cleanup_system_call_insn) |
| @@ -1011,61 +974,54 @@ cleanup_system_call_insn: | |||
| 1011 | .long sysc_stime + 0x80000000 | 974 | .long sysc_stime + 0x80000000 |
| 1012 | .long sysc_update + 0x80000000 | 975 | .long sysc_update + 0x80000000 |
| 1013 | 976 | ||
| 1014 | cleanup_sysc_return: | 977 | cleanup_sysc_tif: |
| 1015 | mvc __LC_RETURN_PSW(4),0(%r12) | 978 | mvc __LC_RETURN_PSW(4),0(%r12) |
| 1016 | mvc __LC_RETURN_PSW+4(4),BASED(cleanup_table_sysc_return) | 979 | mvc __LC_RETURN_PSW+4(4),BASED(cleanup_table_sysc_tif) |
| 1017 | la %r12,__LC_RETURN_PSW | 980 | la %r12,__LC_RETURN_PSW |
| 1018 | br %r14 | 981 | br %r14 |
| 1019 | 982 | ||
| 1020 | cleanup_sysc_leave: | 983 | cleanup_sysc_restore: |
| 1021 | clc 4(4,%r12),BASED(cleanup_sysc_leave_insn) | 984 | clc 4(4,%r12),BASED(cleanup_sysc_restore_insn) |
| 1022 | be BASED(2f) | 985 | be BASED(2f) |
| 986 | mvc __LC_EXIT_TIMER(8),__LC_MCCK_ENTER_TIMER | ||
| 987 | c %r12,BASED(.Lmck_old_psw) | ||
| 988 | be BASED(0f) | ||
| 1023 | mvc __LC_EXIT_TIMER(8),__LC_ASYNC_ENTER_TIMER | 989 | mvc __LC_EXIT_TIMER(8),__LC_ASYNC_ENTER_TIMER |
| 1024 | clc 4(4,%r12),BASED(cleanup_sysc_leave_insn+4) | 990 | 0: clc 4(4,%r12),BASED(cleanup_sysc_restore_insn+4) |
| 1025 | be BASED(2f) | 991 | be BASED(2f) |
| 1026 | mvc __LC_RETURN_PSW(8),SP_PSW(%r15) | 992 | mvc __LC_RETURN_PSW(8),SP_PSW(%r15) |
| 1027 | c %r12,BASED(.Lmck_old_psw) | 993 | c %r12,BASED(.Lmck_old_psw) |
| 1028 | bne BASED(0f) | 994 | la %r12,__LC_SAVE_AREA+32 |
| 1029 | mvc __LC_SAVE_AREA+32(16),SP_R12(%r15) | 995 | be BASED(1f) |
| 1030 | b BASED(1f) | 996 | la %r12,__LC_SAVE_AREA+16 |
| 1031 | 0: mvc __LC_SAVE_AREA+16(16),SP_R12(%r15) | 997 | 1: mvc 0(16,%r12),SP_R12(%r15) |
| 1032 | 1: lm %r0,%r11,SP_R0(%r15) | 998 | lm %r0,%r11,SP_R0(%r15) |
| 1033 | l %r15,SP_R15(%r15) | 999 | l %r15,SP_R15(%r15) |
| 1034 | 2: la %r12,__LC_RETURN_PSW | 1000 | 2: la %r12,__LC_RETURN_PSW |
| 1035 | br %r14 | 1001 | br %r14 |
| 1036 | cleanup_sysc_leave_insn: | 1002 | cleanup_sysc_restore_insn: |
| 1037 | .long sysc_done - 4 + 0x80000000 | 1003 | .long sysc_done - 4 + 0x80000000 |
| 1038 | .long sysc_done - 8 + 0x80000000 | 1004 | .long sysc_done - 8 + 0x80000000 |
| 1039 | 1005 | ||
| 1040 | cleanup_io_return: | 1006 | cleanup_io_tif: |
| 1041 | mvc __LC_RETURN_PSW(4),0(%r12) | 1007 | mvc __LC_RETURN_PSW(4),0(%r12) |
| 1042 | mvc __LC_RETURN_PSW+4(4),BASED(cleanup_table_io_return) | 1008 | mvc __LC_RETURN_PSW+4(4),BASED(cleanup_table_io_tif) |
| 1043 | la %r12,__LC_RETURN_PSW | 1009 | la %r12,__LC_RETURN_PSW |
| 1044 | br %r14 | 1010 | br %r14 |
| 1045 | 1011 | ||
| 1046 | cleanup_io_work_loop: | 1012 | cleanup_io_restore: |
| 1047 | mvc __LC_RETURN_PSW(4),0(%r12) | 1013 | clc 4(4,%r12),BASED(cleanup_io_restore_insn) |
| 1048 | mvc __LC_RETURN_PSW+4(4),BASED(cleanup_table_io_work_loop) | 1014 | be BASED(1f) |
| 1049 | la %r12,__LC_RETURN_PSW | 1015 | mvc __LC_EXIT_TIMER(8),__LC_MCCK_ENTER_TIMER |
| 1050 | br %r14 | 1016 | clc 4(4,%r12),BASED(cleanup_io_restore_insn+4) |
| 1051 | 1017 | be BASED(1f) | |
| 1052 | cleanup_io_leave: | ||
| 1053 | clc 4(4,%r12),BASED(cleanup_io_leave_insn) | ||
| 1054 | be BASED(2f) | ||
| 1055 | mvc __LC_EXIT_TIMER(8),__LC_ASYNC_ENTER_TIMER | ||
| 1056 | clc 4(4,%r12),BASED(cleanup_io_leave_insn+4) | ||
| 1057 | be BASED(2f) | ||
| 1058 | mvc __LC_RETURN_PSW(8),SP_PSW(%r15) | 1018 | mvc __LC_RETURN_PSW(8),SP_PSW(%r15) |
| 1059 | c %r12,BASED(.Lmck_old_psw) | ||
| 1060 | bne BASED(0f) | ||
| 1061 | mvc __LC_SAVE_AREA+32(16),SP_R12(%r15) | 1019 | mvc __LC_SAVE_AREA+32(16),SP_R12(%r15) |
| 1062 | b BASED(1f) | 1020 | lm %r0,%r11,SP_R0(%r15) |
| 1063 | 0: mvc __LC_SAVE_AREA+16(16),SP_R12(%r15) | ||
| 1064 | 1: lm %r0,%r11,SP_R0(%r15) | ||
| 1065 | l %r15,SP_R15(%r15) | 1021 | l %r15,SP_R15(%r15) |
| 1066 | 2: la %r12,__LC_RETURN_PSW | 1022 | 1: la %r12,__LC_RETURN_PSW |
| 1067 | br %r14 | 1023 | br %r14 |
| 1068 | cleanup_io_leave_insn: | 1024 | cleanup_io_restore_insn: |
| 1069 | .long io_done - 4 + 0x80000000 | 1025 | .long io_done - 4 + 0x80000000 |
| 1070 | .long io_done - 8 + 0x80000000 | 1026 | .long io_done - 8 + 0x80000000 |
| 1071 | 1027 | ||
diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S index 52106d53271c..178d92536d90 100644 --- a/arch/s390/kernel/entry64.S +++ b/arch/s390/kernel/entry64.S | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | * arch/s390/kernel/entry64.S | 2 | * arch/s390/kernel/entry64.S |
| 3 | * S390 low-level entry points. | 3 | * S390 low-level entry points. |
| 4 | * | 4 | * |
| 5 | * Copyright (C) IBM Corp. 1999,2006 | 5 | * Copyright (C) IBM Corp. 1999,2010 |
| 6 | * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), | 6 | * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), |
| 7 | * Hartmut Penner (hp@de.ibm.com), | 7 | * Hartmut Penner (hp@de.ibm.com), |
| 8 | * Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com), | 8 | * Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com), |
| @@ -59,30 +59,45 @@ _TIF_SYSCALL = (_TIF_SYSCALL_TRACE>>8 | _TIF_SYSCALL_AUDIT>>8 | \ | |||
| 59 | 59 | ||
| 60 | #define BASED(name) name-system_call(%r13) | 60 | #define BASED(name) name-system_call(%r13) |
| 61 | 61 | ||
| 62 | .macro HANDLE_SIE_INTERCEPT | ||
| 63 | #if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE) | ||
| 64 | lg %r3,__LC_SIE_HOOK | ||
| 65 | ltgr %r3,%r3 | ||
| 66 | jz 0f | ||
| 67 | basr %r14,%r3 | ||
| 68 | 0: | ||
| 69 | #endif | ||
| 70 | .endm | ||
| 71 | |||
| 62 | #ifdef CONFIG_TRACE_IRQFLAGS | 72 | #ifdef CONFIG_TRACE_IRQFLAGS |
| 63 | .macro TRACE_IRQS_ON | 73 | .macro TRACE_IRQS_ON |
| 64 | basr %r2,%r0 | 74 | basr %r2,%r0 |
| 65 | brasl %r14,trace_hardirqs_on_caller | 75 | brasl %r14,trace_hardirqs_on_caller |
| 66 | .endm | 76 | .endm |
| 67 | 77 | ||
| 68 | .macro TRACE_IRQS_OFF | 78 | .macro TRACE_IRQS_OFF |
| 69 | basr %r2,%r0 | 79 | basr %r2,%r0 |
| 70 | brasl %r14,trace_hardirqs_off_caller | 80 | brasl %r14,trace_hardirqs_off_caller |
| 71 | .endm | 81 | .endm |
| 72 | 82 | ||
| 73 | .macro TRACE_IRQS_CHECK | 83 | .macro TRACE_IRQS_CHECK_ON |
| 74 | basr %r2,%r0 | ||
| 75 | tm SP_PSW(%r15),0x03 # irqs enabled? | 84 | tm SP_PSW(%r15),0x03 # irqs enabled? |
| 76 | jz 0f | 85 | jz 0f |
| 77 | brasl %r14,trace_hardirqs_on_caller | 86 | TRACE_IRQS_ON |
| 78 | j 1f | 87 | 0: |
| 79 | 0: brasl %r14,trace_hardirqs_off_caller | 88 | .endm |
| 80 | 1: | 89 | |
| 90 | .macro TRACE_IRQS_CHECK_OFF | ||
| 91 | tm SP_PSW(%r15),0x03 # irqs enabled? | ||
| 92 | jz 0f | ||
| 93 | TRACE_IRQS_OFF | ||
| 94 | 0: | ||
| 81 | .endm | 95 | .endm |
| 82 | #else | 96 | #else |
| 83 | #define TRACE_IRQS_ON | 97 | #define TRACE_IRQS_ON |
| 84 | #define TRACE_IRQS_OFF | 98 | #define TRACE_IRQS_OFF |
| 85 | #define TRACE_IRQS_CHECK | 99 | #define TRACE_IRQS_CHECK_ON |
| 100 | #define TRACE_IRQS_CHECK_OFF | ||
| 86 | #endif | 101 | #endif |
| 87 | 102 | ||
| 88 | #ifdef CONFIG_LOCKDEP | 103 | #ifdef CONFIG_LOCKDEP |
| @@ -111,31 +126,35 @@ _TIF_SYSCALL = (_TIF_SYSCALL_TRACE>>8 | _TIF_SYSCALL_AUDIT>>8 | \ | |||
| 111 | * R15 - kernel stack pointer | 126 | * R15 - kernel stack pointer |
| 112 | */ | 127 | */ |
| 113 | 128 | ||
| 114 | .macro SAVE_ALL_BASE savearea | ||
| 115 | stmg %r12,%r15,\savearea | ||
| 116 | larl %r13,system_call | ||
| 117 | .endm | ||
| 118 | |||
| 119 | .macro SAVE_ALL_SVC psworg,savearea | 129 | .macro SAVE_ALL_SVC psworg,savearea |
| 120 | la %r12,\psworg | 130 | stmg %r11,%r15,\savearea |
| 121 | lg %r15,__LC_KERNEL_STACK # problem state -> load ksp | 131 | lg %r15,__LC_KERNEL_STACK # problem state -> load ksp |
| 132 | aghi %r15,-SP_SIZE # make room for registers & psw | ||
| 133 | lg %r11,__LC_LAST_BREAK | ||
| 122 | .endm | 134 | .endm |
| 123 | 135 | ||
| 124 | .macro SAVE_ALL_SYNC psworg,savearea | 136 | .macro SAVE_ALL_PGM psworg,savearea |
| 125 | la %r12,\psworg | 137 | stmg %r11,%r15,\savearea |
| 126 | tm \psworg+1,0x01 # test problem state bit | 138 | tm \psworg+1,0x01 # test problem state bit |
| 127 | jz 2f # skip stack setup save | ||
| 128 | lg %r15,__LC_KERNEL_STACK # problem state -> load ksp | ||
| 129 | #ifdef CONFIG_CHECK_STACK | 139 | #ifdef CONFIG_CHECK_STACK |
| 130 | j 3f | 140 | jnz 1f |
| 131 | 2: tml %r15,STACK_SIZE - CONFIG_STACK_GUARD | 141 | tml %r15,STACK_SIZE - CONFIG_STACK_GUARD |
| 132 | jz stack_overflow | 142 | jnz 2f |
| 133 | 3: | 143 | la %r12,\psworg |
| 144 | j stack_overflow | ||
| 145 | #else | ||
| 146 | jz 2f | ||
| 134 | #endif | 147 | #endif |
| 135 | 2: | 148 | 1: lg %r15,__LC_KERNEL_STACK # problem state -> load ksp |
| 149 | 2: aghi %r15,-SP_SIZE # make room for registers & psw | ||
| 150 | larl %r13,system_call | ||
| 151 | lg %r11,__LC_LAST_BREAK | ||
| 136 | .endm | 152 | .endm |
| 137 | 153 | ||
| 138 | .macro SAVE_ALL_ASYNC psworg,savearea | 154 | .macro SAVE_ALL_ASYNC psworg,savearea |
| 155 | stmg %r11,%r15,\savearea | ||
| 156 | larl %r13,system_call | ||
| 157 | lg %r11,__LC_LAST_BREAK | ||
| 139 | la %r12,\psworg | 158 | la %r12,\psworg |
| 140 | tm \psworg+1,0x01 # test problem state bit | 159 | tm \psworg+1,0x01 # test problem state bit |
| 141 | jnz 1f # from user -> load kernel stack | 160 | jnz 1f # from user -> load kernel stack |
| @@ -149,27 +168,23 @@ _TIF_SYSCALL = (_TIF_SYSCALL_TRACE>>8 | _TIF_SYSCALL_AUDIT>>8 | \ | |||
| 149 | 0: lg %r14,__LC_ASYNC_STACK # are we already on the async. stack ? | 168 | 0: lg %r14,__LC_ASYNC_STACK # are we already on the async. stack ? |
| 150 | slgr %r14,%r15 | 169 | slgr %r14,%r15 |
| 151 | srag %r14,%r14,STACK_SHIFT | 170 | srag %r14,%r14,STACK_SHIFT |
| 152 | jz 2f | ||
| 153 | 1: lg %r15,__LC_ASYNC_STACK # load async stack | ||
| 154 | #ifdef CONFIG_CHECK_STACK | 171 | #ifdef CONFIG_CHECK_STACK |
| 155 | j 3f | 172 | jnz 1f |
| 156 | 2: tml %r15,STACK_SIZE - CONFIG_STACK_GUARD | 173 | tml %r15,STACK_SIZE - CONFIG_STACK_GUARD |
| 157 | jz stack_overflow | 174 | jnz 2f |
| 158 | 3: | 175 | j stack_overflow |
| 176 | #else | ||
| 177 | jz 2f | ||
| 159 | #endif | 178 | #endif |
| 160 | 2: | 179 | 1: lg %r15,__LC_ASYNC_STACK # load async stack |
| 180 | 2: aghi %r15,-SP_SIZE # make room for registers & psw | ||
| 161 | .endm | 181 | .endm |
| 162 | 182 | ||
| 163 | .macro CREATE_STACK_FRAME psworg,savearea | 183 | .macro CREATE_STACK_FRAME savearea |
| 164 | aghi %r15,-SP_SIZE # make room for registers & psw | 184 | xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) |
| 165 | mvc SP_PSW(16,%r15),0(%r12) # move user PSW to stack | ||
| 166 | stg %r2,SP_ORIG_R2(%r15) # store original content of gpr 2 | 185 | stg %r2,SP_ORIG_R2(%r15) # store original content of gpr 2 |
| 167 | icm %r12,3,__LC_SVC_ILC | 186 | mvc SP_R11(40,%r15),\savearea # move %r11-%r15 to stack |
| 168 | stmg %r0,%r11,SP_R0(%r15) # store gprs %r0-%r11 to kernel stack | 187 | stmg %r0,%r10,SP_R0(%r15) # store gprs %r0-%r10 to kernel stack |
| 169 | st %r12,SP_SVCNR(%r15) | ||
| 170 | mvc SP_R12(32,%r15),\savearea # move %r12-%r15 to stack | ||
| 171 | la %r12,0 | ||
| 172 | stg %r12,__SF_BACKCHAIN(%r15) | ||
| 173 | .endm | 188 | .endm |
| 174 | 189 | ||
| 175 | .macro RESTORE_ALL psworg,sync | 190 | .macro RESTORE_ALL psworg,sync |
| @@ -185,6 +200,13 @@ _TIF_SYSCALL = (_TIF_SYSCALL_TRACE>>8 | _TIF_SYSCALL_AUDIT>>8 | \ | |||
| 185 | lpswe \psworg # back to caller | 200 | lpswe \psworg # back to caller |
| 186 | .endm | 201 | .endm |
| 187 | 202 | ||
| 203 | .macro LAST_BREAK | ||
| 204 | srag %r10,%r11,23 | ||
| 205 | jz 0f | ||
| 206 | stg %r11,__TI_last_break(%r12) | ||
| 207 | 0: | ||
| 208 | .endm | ||
| 209 | |||
| 188 | /* | 210 | /* |
| 189 | * Scheduler resume function, called by switch_to | 211 | * Scheduler resume function, called by switch_to |
| 190 | * gpr2 = (task_struct *) prev | 212 | * gpr2 = (task_struct *) prev |
| @@ -230,143 +252,129 @@ __critical_start: | |||
| 230 | system_call: | 252 | system_call: |
| 231 | stpt __LC_SYNC_ENTER_TIMER | 253 | stpt __LC_SYNC_ENTER_TIMER |
| 232 | sysc_saveall: | 254 | sysc_saveall: |
| 233 | SAVE_ALL_BASE __LC_SAVE_AREA | ||
| 234 | SAVE_ALL_SVC __LC_SVC_OLD_PSW,__LC_SAVE_AREA | 255 | SAVE_ALL_SVC __LC_SVC_OLD_PSW,__LC_SAVE_AREA |
| 235 | CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA | 256 | CREATE_STACK_FRAME __LC_SAVE_AREA |
| 236 | llgh %r7,__LC_SVC_INT_CODE # get svc number from lowcore | 257 | mvc SP_PSW(16,%r15),__LC_SVC_OLD_PSW |
| 258 | mvc SP_ILC(4,%r15),__LC_SVC_ILC | ||
| 259 | stg %r7,SP_ARGS(%r15) | ||
| 260 | lg %r12,__LC_THREAD_INFO # load pointer to thread_info struct | ||
| 237 | sysc_vtime: | 261 | sysc_vtime: |
| 238 | UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER | 262 | UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER |
| 239 | sysc_stime: | 263 | sysc_stime: |
| 240 | UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER | 264 | UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER |
| 241 | sysc_update: | 265 | sysc_update: |
| 242 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER | 266 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER |
| 267 | LAST_BREAK | ||
| 243 | sysc_do_svc: | 268 | sysc_do_svc: |
| 244 | lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct | 269 | llgh %r7,SP_SVCNR(%r15) |
| 245 | ltgr %r7,%r7 # test for svc 0 | 270 | slag %r7,%r7,2 # shift and test for svc 0 |
| 246 | jnz sysc_nr_ok | 271 | jnz sysc_nr_ok |
| 247 | # svc 0: system call number in %r1 | 272 | # svc 0: system call number in %r1 |
| 248 | cl %r1,BASED(.Lnr_syscalls) | 273 | llgfr %r1,%r1 # clear high word in r1 |
| 274 | cghi %r1,NR_syscalls | ||
| 249 | jnl sysc_nr_ok | 275 | jnl sysc_nr_ok |
| 250 | lgfr %r7,%r1 # clear high word in r1 | 276 | sth %r1,SP_SVCNR(%r15) |
| 277 | slag %r7,%r1,2 # shift and test for svc 0 | ||
| 251 | sysc_nr_ok: | 278 | sysc_nr_ok: |
| 252 | mvc SP_ARGS(8,%r15),SP_R7(%r15) | ||
| 253 | sysc_do_restart: | ||
| 254 | sth %r7,SP_SVCNR(%r15) | ||
| 255 | sllg %r7,%r7,2 # svc number * 4 | ||
| 256 | larl %r10,sys_call_table | 279 | larl %r10,sys_call_table |
| 257 | #ifdef CONFIG_COMPAT | 280 | #ifdef CONFIG_COMPAT |
| 258 | tm __TI_flags+5(%r9),(_TIF_31BIT>>16) # running in 31 bit mode ? | 281 | tm __TI_flags+5(%r12),(_TIF_31BIT>>16) # running in 31 bit mode ? |
| 259 | jno sysc_noemu | 282 | jno sysc_noemu |
| 260 | larl %r10,sys_call_table_emu # use 31 bit emulation system calls | 283 | larl %r10,sys_call_table_emu # use 31 bit emulation system calls |
| 261 | sysc_noemu: | 284 | sysc_noemu: |
| 262 | #endif | 285 | #endif |
| 263 | tm __TI_flags+6(%r9),_TIF_SYSCALL | 286 | tm __TI_flags+6(%r12),_TIF_SYSCALL |
| 264 | lgf %r8,0(%r7,%r10) # load address of system call routine | 287 | lgf %r8,0(%r7,%r10) # load address of system call routine |
| 265 | jnz sysc_tracesys | 288 | jnz sysc_tracesys |
| 266 | basr %r14,%r8 # call sys_xxxx | 289 | basr %r14,%r8 # call sys_xxxx |
| 267 | stg %r2,SP_R2(%r15) # store return value (change R2 on stack) | 290 | stg %r2,SP_R2(%r15) # store return value (change R2 on stack) |
| 268 | 291 | ||
| 269 | sysc_return: | 292 | sysc_return: |
| 270 | tm __TI_flags+7(%r9),_TIF_WORK_SVC | 293 | LOCKDEP_SYS_EXIT |
| 294 | sysc_tif: | ||
| 295 | tm __TI_flags+7(%r12),_TIF_WORK_SVC | ||
| 271 | jnz sysc_work # there is work to do (signals etc.) | 296 | jnz sysc_work # there is work to do (signals etc.) |
| 272 | sysc_restore: | 297 | sysc_restore: |
| 273 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
| 274 | larl %r1,sysc_restore_trace_psw | ||
| 275 | lpswe 0(%r1) | ||
| 276 | sysc_restore_trace: | ||
| 277 | TRACE_IRQS_CHECK | ||
| 278 | LOCKDEP_SYS_EXIT | ||
| 279 | #endif | ||
| 280 | sysc_leave: | ||
| 281 | RESTORE_ALL __LC_RETURN_PSW,1 | 298 | RESTORE_ALL __LC_RETURN_PSW,1 |
| 282 | sysc_done: | 299 | sysc_done: |
| 283 | 300 | ||
| 284 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
| 285 | .section .data,"aw",@progbits | ||
| 286 | .align 8 | ||
| 287 | .globl sysc_restore_trace_psw | ||
| 288 | sysc_restore_trace_psw: | ||
| 289 | .quad 0, sysc_restore_trace | ||
| 290 | .previous | ||
| 291 | #endif | ||
| 292 | |||
| 293 | # | ||
| 294 | # recheck if there is more work to do | ||
| 295 | # | 301 | # |
| 296 | sysc_work_loop: | 302 | # There is work to do, but first we need to check if we return to userspace. |
| 297 | tm __TI_flags+7(%r9),_TIF_WORK_SVC | ||
| 298 | jz sysc_restore # there is no work to do | ||
| 299 | # | ||
| 300 | # One of the work bits is on. Find out which one. | ||
| 301 | # | 303 | # |
| 302 | sysc_work: | 304 | sysc_work: |
| 303 | tm SP_PSW+1(%r15),0x01 # returning to user ? | 305 | tm SP_PSW+1(%r15),0x01 # returning to user ? |
| 304 | jno sysc_restore | 306 | jno sysc_restore |
| 305 | tm __TI_flags+7(%r9),_TIF_MCCK_PENDING | 307 | |
| 308 | # | ||
| 309 | # One of the work bits is on. Find out which one. | ||
| 310 | # | ||
| 311 | sysc_work_tif: | ||
| 312 | tm __TI_flags+7(%r12),_TIF_MCCK_PENDING | ||
| 306 | jo sysc_mcck_pending | 313 | jo sysc_mcck_pending |
| 307 | tm __TI_flags+7(%r9),_TIF_NEED_RESCHED | 314 | tm __TI_flags+7(%r12),_TIF_NEED_RESCHED |
| 308 | jo sysc_reschedule | 315 | jo sysc_reschedule |
| 309 | tm __TI_flags+7(%r9),_TIF_SIGPENDING | 316 | tm __TI_flags+7(%r12),_TIF_SIGPENDING |
| 310 | jnz sysc_sigpending | 317 | jo sysc_sigpending |
| 311 | tm __TI_flags+7(%r9),_TIF_NOTIFY_RESUME | 318 | tm __TI_flags+7(%r12),_TIF_NOTIFY_RESUME |
| 312 | jnz sysc_notify_resume | 319 | jo sysc_notify_resume |
| 313 | tm __TI_flags+7(%r9),_TIF_RESTART_SVC | 320 | tm __TI_flags+7(%r12),_TIF_RESTART_SVC |
| 314 | jo sysc_restart | 321 | jo sysc_restart |
| 315 | tm __TI_flags+7(%r9),_TIF_SINGLE_STEP | 322 | tm __TI_flags+7(%r12),_TIF_SINGLE_STEP |
| 316 | jo sysc_singlestep | 323 | jo sysc_singlestep |
| 317 | j sysc_restore | 324 | j sysc_return # beware of critical section cleanup |
| 318 | sysc_work_done: | ||
| 319 | 325 | ||
| 320 | # | 326 | # |
| 321 | # _TIF_NEED_RESCHED is set, call schedule | 327 | # _TIF_NEED_RESCHED is set, call schedule |
| 322 | # | 328 | # |
| 323 | sysc_reschedule: | 329 | sysc_reschedule: |
| 324 | larl %r14,sysc_work_loop | 330 | larl %r14,sysc_return |
| 325 | jg schedule # return point is sysc_return | 331 | jg schedule # return point is sysc_return |
| 326 | 332 | ||
| 327 | # | 333 | # |
| 328 | # _TIF_MCCK_PENDING is set, call handler | 334 | # _TIF_MCCK_PENDING is set, call handler |
| 329 | # | 335 | # |
| 330 | sysc_mcck_pending: | 336 | sysc_mcck_pending: |
| 331 | larl %r14,sysc_work_loop | 337 | larl %r14,sysc_return |
| 332 | jg s390_handle_mcck # TIF bit will be cleared by handler | 338 | jg s390_handle_mcck # TIF bit will be cleared by handler |
| 333 | 339 | ||
| 334 | # | 340 | # |
| 335 | # _TIF_SIGPENDING is set, call do_signal | 341 | # _TIF_SIGPENDING is set, call do_signal |
| 336 | # | 342 | # |
| 337 | sysc_sigpending: | 343 | sysc_sigpending: |
| 338 | ni __TI_flags+7(%r9),255-_TIF_SINGLE_STEP # clear TIF_SINGLE_STEP | 344 | ni __TI_flags+7(%r12),255-_TIF_SINGLE_STEP # clear TIF_SINGLE_STEP |
| 339 | la %r2,SP_PTREGS(%r15) # load pt_regs | 345 | la %r2,SP_PTREGS(%r15) # load pt_regs |
| 340 | brasl %r14,do_signal # call do_signal | 346 | brasl %r14,do_signal # call do_signal |
| 341 | tm __TI_flags+7(%r9),_TIF_RESTART_SVC | 347 | tm __TI_flags+7(%r12),_TIF_RESTART_SVC |
| 342 | jo sysc_restart | 348 | jo sysc_restart |
| 343 | tm __TI_flags+7(%r9),_TIF_SINGLE_STEP | 349 | tm __TI_flags+7(%r12),_TIF_SINGLE_STEP |
| 344 | jo sysc_singlestep | 350 | jo sysc_singlestep |
| 345 | j sysc_work_loop | 351 | j sysc_return |
| 346 | 352 | ||
| 347 | # | 353 | # |
| 348 | # _TIF_NOTIFY_RESUME is set, call do_notify_resume | 354 | # _TIF_NOTIFY_RESUME is set, call do_notify_resume |
| 349 | # | 355 | # |
| 350 | sysc_notify_resume: | 356 | sysc_notify_resume: |
| 351 | la %r2,SP_PTREGS(%r15) # load pt_regs | 357 | la %r2,SP_PTREGS(%r15) # load pt_regs |
| 352 | larl %r14,sysc_work_loop | 358 | larl %r14,sysc_return |
| 353 | jg do_notify_resume # call do_notify_resume | 359 | jg do_notify_resume # call do_notify_resume |
| 354 | 360 | ||
| 355 | # | 361 | # |
| 356 | # _TIF_RESTART_SVC is set, set up registers and restart svc | 362 | # _TIF_RESTART_SVC is set, set up registers and restart svc |
| 357 | # | 363 | # |
| 358 | sysc_restart: | 364 | sysc_restart: |
| 359 | ni __TI_flags+7(%r9),255-_TIF_RESTART_SVC # clear TIF_RESTART_SVC | 365 | ni __TI_flags+7(%r12),255-_TIF_RESTART_SVC # clear TIF_RESTART_SVC |
| 360 | lg %r7,SP_R2(%r15) # load new svc number | 366 | lg %r7,SP_R2(%r15) # load new svc number |
| 361 | mvc SP_R2(8,%r15),SP_ORIG_R2(%r15) # restore first argument | 367 | mvc SP_R2(8,%r15),SP_ORIG_R2(%r15) # restore first argument |
| 362 | lmg %r2,%r6,SP_R2(%r15) # load svc arguments | 368 | lmg %r2,%r6,SP_R2(%r15) # load svc arguments |
| 363 | j sysc_do_restart # restart svc | 369 | sth %r7,SP_SVCNR(%r15) |
| 370 | slag %r7,%r7,2 | ||
| 371 | j sysc_nr_ok # restart svc | ||
| 364 | 372 | ||
| 365 | # | 373 | # |
| 366 | # _TIF_SINGLE_STEP is set, call do_single_step | 374 | # _TIF_SINGLE_STEP is set, call do_single_step |
| 367 | # | 375 | # |
| 368 | sysc_singlestep: | 376 | sysc_singlestep: |
| 369 | ni __TI_flags+7(%r9),255-_TIF_SINGLE_STEP # clear TIF_SINGLE_STEP | 377 | ni __TI_flags+7(%r12),255-_TIF_SINGLE_STEP # clear TIF_SINGLE_STEP |
| 370 | xc SP_SVCNR(2,%r15),SP_SVCNR(%r15) # clear svc number | 378 | xc SP_SVCNR(2,%r15),SP_SVCNR(%r15) # clear svc number |
| 371 | la %r2,SP_PTREGS(%r15) # address of register-save area | 379 | la %r2,SP_PTREGS(%r15) # address of register-save area |
| 372 | larl %r14,sysc_return # load adr. of system return | 380 | larl %r14,sysc_return # load adr. of system return |
| @@ -379,8 +387,8 @@ sysc_singlestep: | |||
| 379 | sysc_tracesys: | 387 | sysc_tracesys: |
| 380 | la %r2,SP_PTREGS(%r15) # load pt_regs | 388 | la %r2,SP_PTREGS(%r15) # load pt_regs |
| 381 | la %r3,0 | 389 | la %r3,0 |
| 382 | srl %r7,2 | 390 | llgh %r0,SP_SVCNR(%r15) |
| 383 | stg %r7,SP_R2(%r15) | 391 | stg %r0,SP_R2(%r15) |
| 384 | brasl %r14,do_syscall_trace_enter | 392 | brasl %r14,do_syscall_trace_enter |
| 385 | lghi %r0,NR_syscalls | 393 | lghi %r0,NR_syscalls |
| 386 | clgr %r0,%r2 | 394 | clgr %r0,%r2 |
| @@ -393,7 +401,7 @@ sysc_tracego: | |||
| 393 | basr %r14,%r8 # call sys_xxx | 401 | basr %r14,%r8 # call sys_xxx |
| 394 | stg %r2,SP_R2(%r15) # store return value | 402 | stg %r2,SP_R2(%r15) # store return value |
| 395 | sysc_tracenogo: | 403 | sysc_tracenogo: |
| 396 | tm __TI_flags+6(%r9),_TIF_SYSCALL | 404 | tm __TI_flags+6(%r12),_TIF_SYSCALL |
| 397 | jz sysc_return | 405 | jz sysc_return |
| 398 | la %r2,SP_PTREGS(%r15) # load pt_regs | 406 | la %r2,SP_PTREGS(%r15) # load pt_regs |
| 399 | larl %r14,sysc_return # return point is sysc_return | 407 | larl %r14,sysc_return # return point is sysc_return |
| @@ -405,7 +413,7 @@ sysc_tracenogo: | |||
| 405 | .globl ret_from_fork | 413 | .globl ret_from_fork |
| 406 | ret_from_fork: | 414 | ret_from_fork: |
| 407 | lg %r13,__LC_SVC_NEW_PSW+8 | 415 | lg %r13,__LC_SVC_NEW_PSW+8 |
| 408 | lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct | 416 | lg %r12,__LC_THREAD_INFO # load pointer to thread_info struct |
| 409 | tm SP_PSW+1(%r15),0x01 # forking a kernel thread ? | 417 | tm SP_PSW+1(%r15),0x01 # forking a kernel thread ? |
| 410 | jo 0f | 418 | jo 0f |
| 411 | stg %r15,SP_R15(%r15) # store stack pointer for new kthread | 419 | stg %r15,SP_R15(%r15) # store stack pointer for new kthread |
| @@ -435,12 +443,14 @@ kernel_execve: | |||
| 435 | br %r14 | 443 | br %r14 |
| 436 | # execve succeeded. | 444 | # execve succeeded. |
| 437 | 0: stnsm __SF_EMPTY(%r15),0xfc # disable interrupts | 445 | 0: stnsm __SF_EMPTY(%r15),0xfc # disable interrupts |
| 446 | # TRACE_IRQS_OFF | ||
| 438 | lg %r15,__LC_KERNEL_STACK # load ksp | 447 | lg %r15,__LC_KERNEL_STACK # load ksp |
| 439 | aghi %r15,-SP_SIZE # make room for registers & psw | 448 | aghi %r15,-SP_SIZE # make room for registers & psw |
| 440 | lg %r13,__LC_SVC_NEW_PSW+8 | 449 | lg %r13,__LC_SVC_NEW_PSW+8 |
| 441 | lg %r9,__LC_THREAD_INFO | ||
| 442 | mvc SP_PTREGS(__PT_SIZE,%r15),0(%r12) # copy pt_regs | 450 | mvc SP_PTREGS(__PT_SIZE,%r15),0(%r12) # copy pt_regs |
| 451 | lg %r12,__LC_THREAD_INFO | ||
| 443 | xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) | 452 | xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) |
| 453 | # TRACE_IRQS_ON | ||
| 444 | stosm __SF_EMPTY(%r15),0x03 # reenable interrupts | 454 | stosm __SF_EMPTY(%r15),0x03 # reenable interrupts |
| 445 | brasl %r14,execve_tail | 455 | brasl %r14,execve_tail |
| 446 | j sysc_return | 456 | j sysc_return |
| @@ -465,20 +475,23 @@ pgm_check_handler: | |||
| 465 | * for LPSW?). | 475 | * for LPSW?). |
| 466 | */ | 476 | */ |
| 467 | stpt __LC_SYNC_ENTER_TIMER | 477 | stpt __LC_SYNC_ENTER_TIMER |
| 468 | SAVE_ALL_BASE __LC_SAVE_AREA | ||
| 469 | tm __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception | 478 | tm __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception |
| 470 | jnz pgm_per # got per exception -> special case | 479 | jnz pgm_per # got per exception -> special case |
| 471 | SAVE_ALL_SYNC __LC_PGM_OLD_PSW,__LC_SAVE_AREA | 480 | SAVE_ALL_PGM __LC_PGM_OLD_PSW,__LC_SAVE_AREA |
| 472 | CREATE_STACK_FRAME __LC_PGM_OLD_PSW,__LC_SAVE_AREA | 481 | CREATE_STACK_FRAME __LC_SAVE_AREA |
| 482 | xc SP_ILC(4,%r15),SP_ILC(%r15) | ||
| 483 | mvc SP_PSW(16,%r15),__LC_PGM_OLD_PSW | ||
| 484 | lg %r12,__LC_THREAD_INFO # load pointer to thread_info struct | ||
| 473 | tm SP_PSW+1(%r15),0x01 # interrupting from user ? | 485 | tm SP_PSW+1(%r15),0x01 # interrupting from user ? |
| 474 | jz pgm_no_vtime | 486 | jz pgm_no_vtime |
| 475 | UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER | 487 | UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER |
| 476 | UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER | 488 | UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER |
| 477 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER | 489 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER |
| 490 | LAST_BREAK | ||
| 478 | pgm_no_vtime: | 491 | pgm_no_vtime: |
| 479 | lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct | 492 | HANDLE_SIE_INTERCEPT |
| 480 | mvc SP_ARGS(8,%r15),__LC_LAST_BREAK | 493 | TRACE_IRQS_CHECK_OFF |
| 481 | TRACE_IRQS_OFF | 494 | stg %r11,SP_ARGS(%r15) |
| 482 | lgf %r3,__LC_PGM_ILC # load program interruption code | 495 | lgf %r3,__LC_PGM_ILC # load program interruption code |
| 483 | lghi %r8,0x7f | 496 | lghi %r8,0x7f |
| 484 | ngr %r8,%r3 | 497 | ngr %r8,%r3 |
| @@ -487,8 +500,10 @@ pgm_do_call: | |||
| 487 | larl %r1,pgm_check_table | 500 | larl %r1,pgm_check_table |
| 488 | lg %r1,0(%r8,%r1) # load address of handler routine | 501 | lg %r1,0(%r8,%r1) # load address of handler routine |
| 489 | la %r2,SP_PTREGS(%r15) # address of register-save area | 502 | la %r2,SP_PTREGS(%r15) # address of register-save area |
| 490 | larl %r14,sysc_return | 503 | basr %r14,%r1 # branch to interrupt-handler |
| 491 | br %r1 # branch to interrupt-handler | 504 | pgm_exit: |
| 505 | TRACE_IRQS_CHECK_ON | ||
| 506 | j sysc_return | ||
| 492 | 507 | ||
| 493 | # | 508 | # |
| 494 | # handle per exception | 509 | # handle per exception |
| @@ -500,55 +515,60 @@ pgm_per: | |||
| 500 | clc __LC_PGM_OLD_PSW(16),__LC_SVC_NEW_PSW | 515 | clc __LC_PGM_OLD_PSW(16),__LC_SVC_NEW_PSW |
| 501 | je pgm_svcper | 516 | je pgm_svcper |
| 502 | # no interesting special case, ignore PER event | 517 | # no interesting special case, ignore PER event |
| 503 | lmg %r12,%r15,__LC_SAVE_AREA | ||
| 504 | lpswe __LC_PGM_OLD_PSW | 518 | lpswe __LC_PGM_OLD_PSW |
| 505 | 519 | ||
| 506 | # | 520 | # |
| 507 | # Normal per exception | 521 | # Normal per exception |
| 508 | # | 522 | # |
| 509 | pgm_per_std: | 523 | pgm_per_std: |
| 510 | SAVE_ALL_SYNC __LC_PGM_OLD_PSW,__LC_SAVE_AREA | 524 | SAVE_ALL_PGM __LC_PGM_OLD_PSW,__LC_SAVE_AREA |
| 511 | CREATE_STACK_FRAME __LC_PGM_OLD_PSW,__LC_SAVE_AREA | 525 | CREATE_STACK_FRAME __LC_SAVE_AREA |
| 526 | mvc SP_PSW(16,%r15),__LC_PGM_OLD_PSW | ||
| 527 | lg %r12,__LC_THREAD_INFO # load pointer to thread_info struct | ||
| 512 | tm SP_PSW+1(%r15),0x01 # interrupting from user ? | 528 | tm SP_PSW+1(%r15),0x01 # interrupting from user ? |
| 513 | jz pgm_no_vtime2 | 529 | jz pgm_no_vtime2 |
| 514 | UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER | 530 | UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER |
| 515 | UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER | 531 | UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER |
| 516 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER | 532 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER |
| 533 | LAST_BREAK | ||
| 517 | pgm_no_vtime2: | 534 | pgm_no_vtime2: |
| 518 | lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct | 535 | HANDLE_SIE_INTERCEPT |
| 519 | TRACE_IRQS_OFF | 536 | TRACE_IRQS_CHECK_OFF |
| 520 | lg %r1,__TI_task(%r9) | 537 | lg %r1,__TI_task(%r12) |
| 521 | tm SP_PSW+1(%r15),0x01 # kernel per event ? | 538 | tm SP_PSW+1(%r15),0x01 # kernel per event ? |
| 522 | jz kernel_per | 539 | jz kernel_per |
| 523 | mvc __THREAD_per+__PER_atmid(2,%r1),__LC_PER_ATMID | 540 | mvc __THREAD_per+__PER_atmid(2,%r1),__LC_PER_ATMID |
| 524 | mvc __THREAD_per+__PER_address(8,%r1),__LC_PER_ADDRESS | 541 | mvc __THREAD_per+__PER_address(8,%r1),__LC_PER_ADDRESS |
| 525 | mvc __THREAD_per+__PER_access_id(1,%r1),__LC_PER_ACCESS_ID | 542 | mvc __THREAD_per+__PER_access_id(1,%r1),__LC_PER_ACCESS_ID |
| 526 | oi __TI_flags+7(%r9),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP | 543 | oi __TI_flags+7(%r12),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP |
| 527 | lgf %r3,__LC_PGM_ILC # load program interruption code | 544 | lgf %r3,__LC_PGM_ILC # load program interruption code |
| 528 | lghi %r8,0x7f | 545 | lghi %r8,0x7f |
| 529 | ngr %r8,%r3 # clear per-event-bit and ilc | 546 | ngr %r8,%r3 # clear per-event-bit and ilc |
| 530 | je sysc_return | 547 | je pgm_exit |
| 531 | j pgm_do_call | 548 | j pgm_do_call |
| 532 | 549 | ||
| 533 | # | 550 | # |
| 534 | # it was a single stepped SVC that is causing all the trouble | 551 | # it was a single stepped SVC that is causing all the trouble |
| 535 | # | 552 | # |
| 536 | pgm_svcper: | 553 | pgm_svcper: |
| 537 | SAVE_ALL_SYNC __LC_SVC_OLD_PSW,__LC_SAVE_AREA | 554 | SAVE_ALL_PGM __LC_SVC_OLD_PSW,__LC_SAVE_AREA |
| 538 | CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA | 555 | CREATE_STACK_FRAME __LC_SAVE_AREA |
| 556 | mvc SP_PSW(16,%r15),__LC_SVC_OLD_PSW | ||
| 557 | mvc SP_ILC(4,%r15),__LC_SVC_ILC | ||
| 558 | lg %r12,__LC_THREAD_INFO # load pointer to thread_info struct | ||
| 539 | UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER | 559 | UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER |
| 540 | UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER | 560 | UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER |
| 541 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER | 561 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER |
| 542 | llgh %r7,__LC_SVC_INT_CODE # get svc number from lowcore | 562 | LAST_BREAK |
| 543 | lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct | 563 | TRACE_IRQS_OFF |
| 544 | lg %r8,__TI_task(%r9) | 564 | lg %r8,__TI_task(%r12) |
| 545 | mvc __THREAD_per+__PER_atmid(2,%r8),__LC_PER_ATMID | 565 | mvc __THREAD_per+__PER_atmid(2,%r8),__LC_PER_ATMID |
| 546 | mvc __THREAD_per+__PER_address(8,%r8),__LC_PER_ADDRESS | 566 | mvc __THREAD_per+__PER_address(8,%r8),__LC_PER_ADDRESS |
| 547 | mvc __THREAD_per+__PER_access_id(1,%r8),__LC_PER_ACCESS_ID | 567 | mvc __THREAD_per+__PER_access_id(1,%r8),__LC_PER_ACCESS_ID |
| 548 | oi __TI_flags+7(%r9),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP | 568 | oi __TI_flags+7(%r12),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP |
| 549 | TRACE_IRQS_ON | 569 | TRACE_IRQS_ON |
| 550 | lmg %r2,%r6,SP_R2(%r15) # load svc arguments | ||
| 551 | stosm __SF_EMPTY(%r15),0x03 # reenable interrupts | 570 | stosm __SF_EMPTY(%r15),0x03 # reenable interrupts |
| 571 | lmg %r2,%r6,SP_R2(%r15) # load svc arguments | ||
| 552 | j sysc_do_svc | 572 | j sysc_do_svc |
| 553 | 573 | ||
| 554 | # | 574 | # |
| @@ -557,8 +577,8 @@ pgm_svcper: | |||
| 557 | kernel_per: | 577 | kernel_per: |
| 558 | xc SP_SVCNR(2,%r15),SP_SVCNR(%r15) # clear svc number | 578 | xc SP_SVCNR(2,%r15),SP_SVCNR(%r15) # clear svc number |
| 559 | la %r2,SP_PTREGS(%r15) # address of register-save area | 579 | la %r2,SP_PTREGS(%r15) # address of register-save area |
| 560 | larl %r14,sysc_restore # load adr. of system ret, no work | 580 | brasl %r14,do_single_step |
| 561 | jg do_single_step # branch to do_single_step | 581 | j pgm_exit |
| 562 | 582 | ||
| 563 | /* | 583 | /* |
| 564 | * IO interrupt handler routine | 584 | * IO interrupt handler routine |
| @@ -567,162 +587,133 @@ kernel_per: | |||
| 567 | io_int_handler: | 587 | io_int_handler: |
| 568 | stck __LC_INT_CLOCK | 588 | stck __LC_INT_CLOCK |
| 569 | stpt __LC_ASYNC_ENTER_TIMER | 589 | stpt __LC_ASYNC_ENTER_TIMER |
| 570 | SAVE_ALL_BASE __LC_SAVE_AREA+32 | 590 | SAVE_ALL_ASYNC __LC_IO_OLD_PSW,__LC_SAVE_AREA+40 |
| 571 | SAVE_ALL_ASYNC __LC_IO_OLD_PSW,__LC_SAVE_AREA+32 | 591 | CREATE_STACK_FRAME __LC_SAVE_AREA+40 |
| 572 | CREATE_STACK_FRAME __LC_IO_OLD_PSW,__LC_SAVE_AREA+32 | 592 | mvc SP_PSW(16,%r15),0(%r12) # move user PSW to stack |
| 593 | lg %r12,__LC_THREAD_INFO # load pointer to thread_info struct | ||
| 573 | tm SP_PSW+1(%r15),0x01 # interrupting from user ? | 594 | tm SP_PSW+1(%r15),0x01 # interrupting from user ? |
| 574 | jz io_no_vtime | 595 | jz io_no_vtime |
| 575 | UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER | 596 | UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER |
| 576 | UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER | 597 | UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER |
| 577 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER | 598 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER |
| 599 | LAST_BREAK | ||
| 578 | io_no_vtime: | 600 | io_no_vtime: |
| 579 | lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct | 601 | HANDLE_SIE_INTERCEPT |
| 580 | TRACE_IRQS_OFF | 602 | TRACE_IRQS_OFF |
| 581 | la %r2,SP_PTREGS(%r15) # address of register-save area | 603 | la %r2,SP_PTREGS(%r15) # address of register-save area |
| 582 | brasl %r14,do_IRQ # call standard irq handler | 604 | brasl %r14,do_IRQ # call standard irq handler |
| 583 | io_return: | 605 | io_return: |
| 584 | tm __TI_flags+7(%r9),_TIF_WORK_INT | 606 | LOCKDEP_SYS_EXIT |
| 607 | TRACE_IRQS_ON | ||
| 608 | io_tif: | ||
| 609 | tm __TI_flags+7(%r12),_TIF_WORK_INT | ||
| 585 | jnz io_work # there is work to do (signals etc.) | 610 | jnz io_work # there is work to do (signals etc.) |
| 586 | io_restore: | 611 | io_restore: |
| 587 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
| 588 | larl %r1,io_restore_trace_psw | ||
| 589 | lpswe 0(%r1) | ||
| 590 | io_restore_trace: | ||
| 591 | TRACE_IRQS_CHECK | ||
| 592 | LOCKDEP_SYS_EXIT | ||
| 593 | #endif | ||
| 594 | io_leave: | ||
| 595 | RESTORE_ALL __LC_RETURN_PSW,0 | 612 | RESTORE_ALL __LC_RETURN_PSW,0 |
| 596 | io_done: | 613 | io_done: |
| 597 | 614 | ||
| 598 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
| 599 | .section .data,"aw",@progbits | ||
| 600 | .align 8 | ||
| 601 | .globl io_restore_trace_psw | ||
| 602 | io_restore_trace_psw: | ||
| 603 | .quad 0, io_restore_trace | ||
| 604 | .previous | ||
| 605 | #endif | ||
| 606 | |||
| 607 | # | 615 | # |
| 608 | # There is work todo, we need to check if we return to userspace, then | 616 | # There is work todo, find out in which context we have been interrupted: |
| 609 | # check, if we are in SIE, if yes leave it | 617 | # 1) if we return to user space we can do all _TIF_WORK_INT work |
| 618 | # 2) if we return to kernel code and kvm is enabled check if we need to | ||
| 619 | # modify the psw to leave SIE | ||
| 620 | # 3) if we return to kernel code and preemptive scheduling is enabled check | ||
| 621 | # the preemption counter and if it is zero call preempt_schedule_irq | ||
| 622 | # Before any work can be done, a switch to the kernel stack is required. | ||
| 610 | # | 623 | # |
| 611 | io_work: | 624 | io_work: |
| 612 | tm SP_PSW+1(%r15),0x01 # returning to user ? | 625 | tm SP_PSW+1(%r15),0x01 # returning to user ? |
| 613 | #ifndef CONFIG_PREEMPT | 626 | jo io_work_user # yes -> do resched & signal |
| 614 | #if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE) | 627 | #ifdef CONFIG_PREEMPT |
| 615 | jnz io_work_user # yes -> no need to check for SIE | ||
| 616 | la %r1, BASED(sie_opcode) # we return to kernel here | ||
| 617 | lg %r2, SP_PSW+8(%r15) | ||
| 618 | clc 0(2,%r1), 0(%r2) # is current instruction = SIE? | ||
| 619 | jne io_restore # no-> return to kernel | ||
| 620 | lg %r1, SP_PSW+8(%r15) # yes-> add 4 bytes to leave SIE | ||
| 621 | aghi %r1, 4 | ||
| 622 | stg %r1, SP_PSW+8(%r15) | ||
| 623 | j io_restore # return to kernel | ||
| 624 | #else | ||
| 625 | jno io_restore # no-> skip resched & signal | ||
| 626 | #endif | ||
| 627 | #else | ||
| 628 | jnz io_work_user # yes -> do resched & signal | ||
| 629 | #if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE) | ||
| 630 | la %r1, BASED(sie_opcode) | ||
| 631 | lg %r2, SP_PSW+8(%r15) | ||
| 632 | clc 0(2,%r1), 0(%r2) # is current instruction = SIE? | ||
| 633 | jne 0f # no -> leave PSW alone | ||
| 634 | lg %r1, SP_PSW+8(%r15) # yes-> add 4 bytes to leave SIE | ||
| 635 | aghi %r1, 4 | ||
| 636 | stg %r1, SP_PSW+8(%r15) | ||
| 637 | 0: | ||
| 638 | #endif | ||
| 639 | # check for preemptive scheduling | 628 | # check for preemptive scheduling |
| 640 | icm %r0,15,__TI_precount(%r9) | 629 | icm %r0,15,__TI_precount(%r12) |
| 641 | jnz io_restore # preemption is disabled | 630 | jnz io_restore # preemption is disabled |
| 631 | tm __TI_flags+7(%r12),_TIF_NEED_RESCHED | ||
| 632 | jno io_restore | ||
| 642 | # switch to kernel stack | 633 | # switch to kernel stack |
| 643 | lg %r1,SP_R15(%r15) | 634 | lg %r1,SP_R15(%r15) |
| 644 | aghi %r1,-SP_SIZE | 635 | aghi %r1,-SP_SIZE |
| 645 | mvc SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15) | 636 | mvc SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15) |
| 646 | xc __SF_BACKCHAIN(8,%r1),__SF_BACKCHAIN(%r1) # clear back chain | 637 | xc __SF_BACKCHAIN(8,%r1),__SF_BACKCHAIN(%r1) # clear back chain |
| 647 | lgr %r15,%r1 | 638 | lgr %r15,%r1 |
| 648 | io_resume_loop: | 639 | # TRACE_IRQS_ON already done at io_return, call |
| 649 | tm __TI_flags+7(%r9),_TIF_NEED_RESCHED | 640 | # TRACE_IRQS_OFF to keep things symmetrical |
| 650 | jno io_restore | 641 | TRACE_IRQS_OFF |
| 651 | larl %r14,io_resume_loop | 642 | brasl %r14,preempt_schedule_irq |
| 652 | jg preempt_schedule_irq | 643 | j io_return |
| 644 | #else | ||
| 645 | j io_restore | ||
| 653 | #endif | 646 | #endif |
| 654 | 647 | ||
| 648 | # | ||
| 649 | # Need to do work before returning to userspace, switch to kernel stack | ||
| 650 | # | ||
| 655 | io_work_user: | 651 | io_work_user: |
| 656 | lg %r1,__LC_KERNEL_STACK | 652 | lg %r1,__LC_KERNEL_STACK |
| 657 | aghi %r1,-SP_SIZE | 653 | aghi %r1,-SP_SIZE |
| 658 | mvc SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15) | 654 | mvc SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15) |
| 659 | xc __SF_BACKCHAIN(8,%r1),__SF_BACKCHAIN(%r1) # clear back chain | 655 | xc __SF_BACKCHAIN(8,%r1),__SF_BACKCHAIN(%r1) # clear back chain |
| 660 | lgr %r15,%r1 | 656 | lgr %r15,%r1 |
| 657 | |||
| 661 | # | 658 | # |
| 662 | # One of the work bits is on. Find out which one. | 659 | # One of the work bits is on. Find out which one. |
| 663 | # Checked are: _TIF_SIGPENDING, _TIF_RESTORE_SIGPENDING, _TIF_NEED_RESCHED | 660 | # Checked are: _TIF_SIGPENDING, _TIF_NOTIFY_RESUME, _TIF_NEED_RESCHED |
| 664 | # and _TIF_MCCK_PENDING | 661 | # and _TIF_MCCK_PENDING |
| 665 | # | 662 | # |
| 666 | io_work_loop: | 663 | io_work_tif: |
| 667 | tm __TI_flags+7(%r9),_TIF_MCCK_PENDING | 664 | tm __TI_flags+7(%r12),_TIF_MCCK_PENDING |
| 668 | jo io_mcck_pending | 665 | jo io_mcck_pending |
| 669 | tm __TI_flags+7(%r9),_TIF_NEED_RESCHED | 666 | tm __TI_flags+7(%r12),_TIF_NEED_RESCHED |
| 670 | jo io_reschedule | 667 | jo io_reschedule |
| 671 | tm __TI_flags+7(%r9),_TIF_SIGPENDING | 668 | tm __TI_flags+7(%r12),_TIF_SIGPENDING |
| 672 | jnz io_sigpending | 669 | jo io_sigpending |
| 673 | tm __TI_flags+7(%r9),_TIF_NOTIFY_RESUME | 670 | tm __TI_flags+7(%r12),_TIF_NOTIFY_RESUME |
| 674 | jnz io_notify_resume | 671 | jo io_notify_resume |
| 675 | j io_restore | 672 | j io_return # beware of critical section cleanup |
| 676 | io_work_done: | ||
| 677 | |||
| 678 | #if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE) | ||
| 679 | sie_opcode: | ||
| 680 | .long 0xb2140000 | ||
| 681 | #endif | ||
| 682 | 673 | ||
| 683 | # | 674 | # |
| 684 | # _TIF_MCCK_PENDING is set, call handler | 675 | # _TIF_MCCK_PENDING is set, call handler |
| 685 | # | 676 | # |
| 686 | io_mcck_pending: | 677 | io_mcck_pending: |
| 678 | # TRACE_IRQS_ON already done at io_return | ||
| 687 | brasl %r14,s390_handle_mcck # TIF bit will be cleared by handler | 679 | brasl %r14,s390_handle_mcck # TIF bit will be cleared by handler |
| 688 | j io_work_loop | 680 | TRACE_IRQS_OFF |
| 681 | j io_return | ||
| 689 | 682 | ||
| 690 | # | 683 | # |
| 691 | # _TIF_NEED_RESCHED is set, call schedule | 684 | # _TIF_NEED_RESCHED is set, call schedule |
| 692 | # | 685 | # |
| 693 | io_reschedule: | 686 | io_reschedule: |
| 694 | TRACE_IRQS_ON | 687 | # TRACE_IRQS_ON already done at io_return |
| 695 | stosm __SF_EMPTY(%r15),0x03 # reenable interrupts | 688 | stosm __SF_EMPTY(%r15),0x03 # reenable interrupts |
| 696 | brasl %r14,schedule # call scheduler | 689 | brasl %r14,schedule # call scheduler |
| 697 | stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts | 690 | stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts |
| 698 | TRACE_IRQS_OFF | 691 | TRACE_IRQS_OFF |
| 699 | tm __TI_flags+7(%r9),_TIF_WORK_INT | 692 | j io_return |
| 700 | jz io_restore # there is no work to do | ||
| 701 | j io_work_loop | ||
| 702 | 693 | ||
| 703 | # | 694 | # |
| 704 | # _TIF_SIGPENDING or is set, call do_signal | 695 | # _TIF_SIGPENDING or is set, call do_signal |
| 705 | # | 696 | # |
| 706 | io_sigpending: | 697 | io_sigpending: |
| 707 | TRACE_IRQS_ON | 698 | # TRACE_IRQS_ON already done at io_return |
| 708 | stosm __SF_EMPTY(%r15),0x03 # reenable interrupts | 699 | stosm __SF_EMPTY(%r15),0x03 # reenable interrupts |
| 709 | la %r2,SP_PTREGS(%r15) # load pt_regs | 700 | la %r2,SP_PTREGS(%r15) # load pt_regs |
| 710 | brasl %r14,do_signal # call do_signal | 701 | brasl %r14,do_signal # call do_signal |
| 711 | stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts | 702 | stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts |
| 712 | TRACE_IRQS_OFF | 703 | TRACE_IRQS_OFF |
| 713 | j io_work_loop | 704 | j io_return |
| 714 | 705 | ||
| 715 | # | 706 | # |
| 716 | # _TIF_NOTIFY_RESUME or is set, call do_notify_resume | 707 | # _TIF_NOTIFY_RESUME or is set, call do_notify_resume |
| 717 | # | 708 | # |
| 718 | io_notify_resume: | 709 | io_notify_resume: |
| 719 | TRACE_IRQS_ON | 710 | # TRACE_IRQS_ON already done at io_return |
| 720 | stosm __SF_EMPTY(%r15),0x03 # reenable interrupts | 711 | stosm __SF_EMPTY(%r15),0x03 # reenable interrupts |
| 721 | la %r2,SP_PTREGS(%r15) # load pt_regs | 712 | la %r2,SP_PTREGS(%r15) # load pt_regs |
| 722 | brasl %r14,do_notify_resume # call do_notify_resume | 713 | brasl %r14,do_notify_resume # call do_notify_resume |
| 723 | stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts | 714 | stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts |
| 724 | TRACE_IRQS_OFF | 715 | TRACE_IRQS_OFF |
| 725 | j io_work_loop | 716 | j io_return |
| 726 | 717 | ||
| 727 | /* | 718 | /* |
| 728 | * External interrupt handler routine | 719 | * External interrupt handler routine |
| @@ -731,16 +722,18 @@ io_notify_resume: | |||
| 731 | ext_int_handler: | 722 | ext_int_handler: |
| 732 | stck __LC_INT_CLOCK | 723 | stck __LC_INT_CLOCK |
| 733 | stpt __LC_ASYNC_ENTER_TIMER | 724 | stpt __LC_ASYNC_ENTER_TIMER |
| 734 | SAVE_ALL_BASE __LC_SAVE_AREA+32 | 725 | SAVE_ALL_ASYNC __LC_EXT_OLD_PSW,__LC_SAVE_AREA+40 |
| 735 | SAVE_ALL_ASYNC __LC_EXT_OLD_PSW,__LC_SAVE_AREA+32 | 726 | CREATE_STACK_FRAME __LC_SAVE_AREA+40 |
| 736 | CREATE_STACK_FRAME __LC_EXT_OLD_PSW,__LC_SAVE_AREA+32 | 727 | mvc SP_PSW(16,%r15),0(%r12) # move user PSW to stack |
| 728 | lg %r12,__LC_THREAD_INFO # load pointer to thread_info struct | ||
| 737 | tm SP_PSW+1(%r15),0x01 # interrupting from user ? | 729 | tm SP_PSW+1(%r15),0x01 # interrupting from user ? |
| 738 | jz ext_no_vtime | 730 | jz ext_no_vtime |
| 739 | UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER | 731 | UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER |
| 740 | UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER | 732 | UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER |
| 741 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER | 733 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER |
| 734 | LAST_BREAK | ||
| 742 | ext_no_vtime: | 735 | ext_no_vtime: |
| 743 | lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct | 736 | HANDLE_SIE_INTERCEPT |
| 744 | TRACE_IRQS_OFF | 737 | TRACE_IRQS_OFF |
| 745 | la %r2,SP_PTREGS(%r15) # address of register-save area | 738 | la %r2,SP_PTREGS(%r15) # address of register-save area |
| 746 | llgh %r3,__LC_EXT_INT_CODE # get interruption code | 739 | llgh %r3,__LC_EXT_INT_CODE # get interruption code |
| @@ -754,17 +747,18 @@ __critical_end: | |||
| 754 | */ | 747 | */ |
| 755 | .globl mcck_int_handler | 748 | .globl mcck_int_handler |
| 756 | mcck_int_handler: | 749 | mcck_int_handler: |
| 757 | stck __LC_INT_CLOCK | 750 | stck __LC_MCCK_CLOCK |
| 758 | la %r1,4095 # revalidate r1 | 751 | la %r1,4095 # revalidate r1 |
| 759 | spt __LC_CPU_TIMER_SAVE_AREA-4095(%r1) # revalidate cpu timer | 752 | spt __LC_CPU_TIMER_SAVE_AREA-4095(%r1) # revalidate cpu timer |
| 760 | lmg %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1)# revalidate gprs | 753 | lmg %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1)# revalidate gprs |
| 761 | SAVE_ALL_BASE __LC_SAVE_AREA+64 | 754 | stmg %r11,%r15,__LC_SAVE_AREA+80 |
| 755 | larl %r13,system_call | ||
| 756 | lg %r11,__LC_LAST_BREAK | ||
| 762 | la %r12,__LC_MCK_OLD_PSW | 757 | la %r12,__LC_MCK_OLD_PSW |
| 763 | tm __LC_MCCK_CODE,0x80 # system damage? | 758 | tm __LC_MCCK_CODE,0x80 # system damage? |
| 764 | jo mcck_int_main # yes -> rest of mcck code invalid | 759 | jo mcck_int_main # yes -> rest of mcck code invalid |
| 765 | la %r14,4095 | 760 | la %r14,4095 |
| 766 | mvc __LC_SAVE_AREA+104(8),__LC_ASYNC_ENTER_TIMER | 761 | mvc __LC_MCCK_ENTER_TIMER(8),__LC_CPU_TIMER_SAVE_AREA-4095(%r14) |
| 767 | mvc __LC_ASYNC_ENTER_TIMER(8),__LC_CPU_TIMER_SAVE_AREA-4095(%r14) | ||
| 768 | tm __LC_MCCK_CODE+5,0x02 # stored cpu timer value valid? | 762 | tm __LC_MCCK_CODE+5,0x02 # stored cpu timer value valid? |
| 769 | jo 1f | 763 | jo 1f |
| 770 | la %r14,__LC_SYNC_ENTER_TIMER | 764 | la %r14,__LC_SYNC_ENTER_TIMER |
| @@ -778,7 +772,7 @@ mcck_int_handler: | |||
| 778 | jl 0f | 772 | jl 0f |
| 779 | la %r14,__LC_LAST_UPDATE_TIMER | 773 | la %r14,__LC_LAST_UPDATE_TIMER |
| 780 | 0: spt 0(%r14) | 774 | 0: spt 0(%r14) |
| 781 | mvc __LC_ASYNC_ENTER_TIMER(8),0(%r14) | 775 | mvc __LC_MCCK_ENTER_TIMER(8),0(%r14) |
| 782 | 1: tm __LC_MCCK_CODE+2,0x09 # mwp + ia of old psw valid? | 776 | 1: tm __LC_MCCK_CODE+2,0x09 # mwp + ia of old psw valid? |
| 783 | jno mcck_int_main # no -> skip cleanup critical | 777 | jno mcck_int_main # no -> skip cleanup critical |
| 784 | tm __LC_MCK_OLD_PSW+1,0x01 # test problem state bit | 778 | tm __LC_MCK_OLD_PSW+1,0x01 # test problem state bit |
| @@ -794,16 +788,19 @@ mcck_int_main: | |||
| 794 | srag %r14,%r14,PAGE_SHIFT | 788 | srag %r14,%r14,PAGE_SHIFT |
| 795 | jz 0f | 789 | jz 0f |
| 796 | lg %r15,__LC_PANIC_STACK # load panic stack | 790 | lg %r15,__LC_PANIC_STACK # load panic stack |
| 797 | 0: CREATE_STACK_FRAME __LC_MCK_OLD_PSW,__LC_SAVE_AREA+64 | 791 | 0: aghi %r15,-SP_SIZE # make room for registers & psw |
| 792 | CREATE_STACK_FRAME __LC_SAVE_AREA+80 | ||
| 793 | mvc SP_PSW(16,%r15),0(%r12) | ||
| 794 | lg %r12,__LC_THREAD_INFO # load pointer to thread_info struct | ||
| 798 | tm __LC_MCCK_CODE+2,0x08 # mwp of old psw valid? | 795 | tm __LC_MCCK_CODE+2,0x08 # mwp of old psw valid? |
| 799 | jno mcck_no_vtime # no -> no timer update | 796 | jno mcck_no_vtime # no -> no timer update |
| 800 | tm SP_PSW+1(%r15),0x01 # interrupting from user ? | 797 | tm SP_PSW+1(%r15),0x01 # interrupting from user ? |
| 801 | jz mcck_no_vtime | 798 | jz mcck_no_vtime |
| 802 | UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER | 799 | UPDATE_VTIME __LC_EXIT_TIMER,__LC_MCCK_ENTER_TIMER,__LC_USER_TIMER |
| 803 | UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER | 800 | UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER |
| 804 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER | 801 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_MCCK_ENTER_TIMER |
| 802 | LAST_BREAK | ||
| 805 | mcck_no_vtime: | 803 | mcck_no_vtime: |
| 806 | lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct | ||
| 807 | la %r2,SP_PTREGS(%r15) # load pt_regs | 804 | la %r2,SP_PTREGS(%r15) # load pt_regs |
| 808 | brasl %r14,s390_do_machine_check | 805 | brasl %r14,s390_do_machine_check |
| 809 | tm SP_PSW+1(%r15),0x01 # returning to user ? | 806 | tm SP_PSW+1(%r15),0x01 # returning to user ? |
| @@ -814,8 +811,9 @@ mcck_no_vtime: | |||
| 814 | xc __SF_BACKCHAIN(8,%r1),__SF_BACKCHAIN(%r1) # clear back chain | 811 | xc __SF_BACKCHAIN(8,%r1),__SF_BACKCHAIN(%r1) # clear back chain |
| 815 | lgr %r15,%r1 | 812 | lgr %r15,%r1 |
| 816 | stosm __SF_EMPTY(%r15),0x04 # turn dat on | 813 | stosm __SF_EMPTY(%r15),0x04 # turn dat on |
| 817 | tm __TI_flags+7(%r9),_TIF_MCCK_PENDING | 814 | tm __TI_flags+7(%r12),_TIF_MCCK_PENDING |
| 818 | jno mcck_return | 815 | jno mcck_return |
| 816 | HANDLE_SIE_INTERCEPT | ||
| 819 | TRACE_IRQS_OFF | 817 | TRACE_IRQS_OFF |
| 820 | brasl %r14,s390_handle_mcck | 818 | brasl %r14,s390_handle_mcck |
| 821 | TRACE_IRQS_ON | 819 | TRACE_IRQS_ON |
| @@ -823,11 +821,11 @@ mcck_return: | |||
| 823 | mvc __LC_RETURN_MCCK_PSW(16),SP_PSW(%r15) # move return PSW | 821 | mvc __LC_RETURN_MCCK_PSW(16),SP_PSW(%r15) # move return PSW |
| 824 | ni __LC_RETURN_MCCK_PSW+1,0xfd # clear wait state bit | 822 | ni __LC_RETURN_MCCK_PSW+1,0xfd # clear wait state bit |
| 825 | lmg %r0,%r15,SP_R0(%r15) # load gprs 0-15 | 823 | lmg %r0,%r15,SP_R0(%r15) # load gprs 0-15 |
| 826 | mvc __LC_ASYNC_ENTER_TIMER(8),__LC_SAVE_AREA+104 | ||
| 827 | tm __LC_RETURN_MCCK_PSW+1,0x01 # returning to user ? | 824 | tm __LC_RETURN_MCCK_PSW+1,0x01 # returning to user ? |
| 828 | jno 0f | 825 | jno 0f |
| 829 | stpt __LC_EXIT_TIMER | 826 | stpt __LC_EXIT_TIMER |
| 830 | 0: lpswe __LC_RETURN_MCCK_PSW # back to caller | 827 | 0: lpswe __LC_RETURN_MCCK_PSW # back to caller |
| 828 | mcck_done: | ||
| 831 | 829 | ||
| 832 | /* | 830 | /* |
| 833 | * Restart interruption handler, kick starter for additional CPUs | 831 | * Restart interruption handler, kick starter for additional CPUs |
| @@ -883,14 +881,14 @@ stack_overflow: | |||
| 883 | lg %r15,__LC_PANIC_STACK # change to panic stack | 881 | lg %r15,__LC_PANIC_STACK # change to panic stack |
| 884 | aghi %r15,-SP_SIZE | 882 | aghi %r15,-SP_SIZE |
| 885 | mvc SP_PSW(16,%r15),0(%r12) # move user PSW to stack | 883 | mvc SP_PSW(16,%r15),0(%r12) # move user PSW to stack |
| 886 | stmg %r0,%r11,SP_R0(%r15) # store gprs %r0-%r11 to kernel stack | 884 | stmg %r0,%r10,SP_R0(%r15) # store gprs %r0-%r10 to kernel stack |
| 887 | la %r1,__LC_SAVE_AREA | 885 | la %r1,__LC_SAVE_AREA |
| 888 | chi %r12,__LC_SVC_OLD_PSW | 886 | chi %r12,__LC_SVC_OLD_PSW |
| 889 | je 0f | 887 | je 0f |
| 890 | chi %r12,__LC_PGM_OLD_PSW | 888 | chi %r12,__LC_PGM_OLD_PSW |
| 891 | je 0f | 889 | je 0f |
| 892 | la %r1,__LC_SAVE_AREA+32 | 890 | la %r1,__LC_SAVE_AREA+40 |
| 893 | 0: mvc SP_R12(32,%r15),0(%r1) # move %r12-%r15 to stack | 891 | 0: mvc SP_R11(40,%r15),0(%r1) # move %r11-%r15 to stack |
| 894 | mvc SP_ARGS(8,%r15),__LC_LAST_BREAK | 892 | mvc SP_ARGS(8,%r15),__LC_LAST_BREAK |
| 895 | xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) # clear back chain | 893 | xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) # clear back chain |
| 896 | la %r2,SP_PTREGS(%r15) # load pt_regs | 894 | la %r2,SP_PTREGS(%r15) # load pt_regs |
| @@ -899,18 +897,14 @@ stack_overflow: | |||
| 899 | 897 | ||
| 900 | cleanup_table_system_call: | 898 | cleanup_table_system_call: |
| 901 | .quad system_call, sysc_do_svc | 899 | .quad system_call, sysc_do_svc |
| 902 | cleanup_table_sysc_return: | 900 | cleanup_table_sysc_tif: |
| 903 | .quad sysc_return, sysc_leave | 901 | .quad sysc_tif, sysc_restore |
| 904 | cleanup_table_sysc_leave: | 902 | cleanup_table_sysc_restore: |
| 905 | .quad sysc_leave, sysc_done | 903 | .quad sysc_restore, sysc_done |
| 906 | cleanup_table_sysc_work_loop: | 904 | cleanup_table_io_tif: |
| 907 | .quad sysc_work_loop, sysc_work_done | 905 | .quad io_tif, io_restore |
| 908 | cleanup_table_io_return: | 906 | cleanup_table_io_restore: |
| 909 | .quad io_return, io_leave | 907 | .quad io_restore, io_done |
| 910 | cleanup_table_io_leave: | ||
| 911 | .quad io_leave, io_done | ||
| 912 | cleanup_table_io_work_loop: | ||
| 913 | .quad io_work_loop, io_work_done | ||
| 914 | 908 | ||
| 915 | cleanup_critical: | 909 | cleanup_critical: |
| 916 | clc 8(8,%r12),BASED(cleanup_table_system_call) | 910 | clc 8(8,%r12),BASED(cleanup_table_system_call) |
| @@ -918,61 +912,54 @@ cleanup_critical: | |||
| 918 | clc 8(8,%r12),BASED(cleanup_table_system_call+8) | 912 | clc 8(8,%r12),BASED(cleanup_table_system_call+8) |
| 919 | jl cleanup_system_call | 913 | jl cleanup_system_call |
| 920 | 0: | 914 | 0: |
| 921 | clc 8(8,%r12),BASED(cleanup_table_sysc_return) | 915 | clc 8(8,%r12),BASED(cleanup_table_sysc_tif) |
| 922 | jl 0f | ||
| 923 | clc 8(8,%r12),BASED(cleanup_table_sysc_return+8) | ||
| 924 | jl cleanup_sysc_return | ||
| 925 | 0: | ||
| 926 | clc 8(8,%r12),BASED(cleanup_table_sysc_leave) | ||
| 927 | jl 0f | 916 | jl 0f |
| 928 | clc 8(8,%r12),BASED(cleanup_table_sysc_leave+8) | 917 | clc 8(8,%r12),BASED(cleanup_table_sysc_tif+8) |
| 929 | jl cleanup_sysc_leave | 918 | jl cleanup_sysc_tif |
| 930 | 0: | 919 | 0: |
| 931 | clc 8(8,%r12),BASED(cleanup_table_sysc_work_loop) | 920 | clc 8(8,%r12),BASED(cleanup_table_sysc_restore) |
| 932 | jl 0f | 921 | jl 0f |
| 933 | clc 8(8,%r12),BASED(cleanup_table_sysc_work_loop+8) | 922 | clc 8(8,%r12),BASED(cleanup_table_sysc_restore+8) |
| 934 | jl cleanup_sysc_return | 923 | jl cleanup_sysc_restore |
| 935 | 0: | 924 | 0: |
| 936 | clc 8(8,%r12),BASED(cleanup_table_io_return) | 925 | clc 8(8,%r12),BASED(cleanup_table_io_tif) |
| 937 | jl 0f | 926 | jl 0f |
| 938 | clc 8(8,%r12),BASED(cleanup_table_io_return+8) | 927 | clc 8(8,%r12),BASED(cleanup_table_io_tif+8) |
| 939 | jl cleanup_io_return | 928 | jl cleanup_io_tif |
| 940 | 0: | 929 | 0: |
| 941 | clc 8(8,%r12),BASED(cleanup_table_io_leave) | 930 | clc 8(8,%r12),BASED(cleanup_table_io_restore) |
| 942 | jl 0f | 931 | jl 0f |
| 943 | clc 8(8,%r12),BASED(cleanup_table_io_leave+8) | 932 | clc 8(8,%r12),BASED(cleanup_table_io_restore+8) |
| 944 | jl cleanup_io_leave | 933 | jl cleanup_io_restore |
| 945 | 0: | ||
| 946 | clc 8(8,%r12),BASED(cleanup_table_io_work_loop) | ||
| 947 | jl 0f | ||
| 948 | clc 8(8,%r12),BASED(cleanup_table_io_work_loop+8) | ||
| 949 | jl cleanup_io_work_loop | ||
| 950 | 0: | 934 | 0: |
| 951 | br %r14 | 935 | br %r14 |
| 952 | 936 | ||
| 953 | cleanup_system_call: | 937 | cleanup_system_call: |
| 954 | mvc __LC_RETURN_PSW(16),0(%r12) | 938 | mvc __LC_RETURN_PSW(16),0(%r12) |
| 955 | cghi %r12,__LC_MCK_OLD_PSW | ||
| 956 | je 0f | ||
| 957 | la %r12,__LC_SAVE_AREA+32 | ||
| 958 | j 1f | ||
| 959 | 0: la %r12,__LC_SAVE_AREA+64 | ||
| 960 | 1: | ||
| 961 | clc __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn+8) | 939 | clc __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn+8) |
| 962 | jh 0f | 940 | jh 0f |
| 941 | mvc __LC_SYNC_ENTER_TIMER(8),__LC_MCCK_ENTER_TIMER | ||
| 942 | cghi %r12,__LC_MCK_OLD_PSW | ||
| 943 | je 0f | ||
| 963 | mvc __LC_SYNC_ENTER_TIMER(8),__LC_ASYNC_ENTER_TIMER | 944 | mvc __LC_SYNC_ENTER_TIMER(8),__LC_ASYNC_ENTER_TIMER |
| 945 | 0: cghi %r12,__LC_MCK_OLD_PSW | ||
| 946 | la %r12,__LC_SAVE_AREA+80 | ||
| 947 | je 0f | ||
| 948 | la %r12,__LC_SAVE_AREA+40 | ||
| 964 | 0: clc __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn+16) | 949 | 0: clc __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn+16) |
| 965 | jhe cleanup_vtime | 950 | jhe cleanup_vtime |
| 966 | clc __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn) | 951 | clc __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn) |
| 967 | jh 0f | 952 | jh 0f |
| 968 | mvc __LC_SAVE_AREA(32),0(%r12) | 953 | mvc __LC_SAVE_AREA(40),0(%r12) |
| 969 | 0: stg %r13,8(%r12) | 954 | 0: lg %r15,__LC_KERNEL_STACK # problem state -> load ksp |
| 970 | stg %r12,__LC_SAVE_AREA+96 # argh | 955 | aghi %r15,-SP_SIZE # make room for registers & psw |
| 971 | SAVE_ALL_SYNC __LC_SVC_OLD_PSW,__LC_SAVE_AREA | 956 | stg %r15,32(%r12) |
| 972 | CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA | 957 | stg %r11,0(%r12) |
| 973 | lg %r12,__LC_SAVE_AREA+96 # argh | 958 | CREATE_STACK_FRAME __LC_SAVE_AREA |
| 974 | stg %r15,24(%r12) | 959 | mvc SP_PSW(16,%r15),__LC_SVC_OLD_PSW |
| 975 | llgh %r7,__LC_SVC_INT_CODE | 960 | mvc SP_ILC(4,%r15),__LC_SVC_ILC |
| 961 | stg %r7,SP_ARGS(%r15) | ||
| 962 | mvc 8(8,%r12),__LC_THREAD_INFO | ||
| 976 | cleanup_vtime: | 963 | cleanup_vtime: |
| 977 | clc __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn+24) | 964 | clc __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn+24) |
| 978 | jhe cleanup_stime | 965 | jhe cleanup_stime |
| @@ -983,7 +970,11 @@ cleanup_stime: | |||
| 983 | UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER | 970 | UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER |
| 984 | cleanup_update: | 971 | cleanup_update: |
| 985 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER | 972 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER |
| 986 | mvc __LC_RETURN_PSW+8(8),BASED(cleanup_table_system_call+8) | 973 | srag %r12,%r11,23 |
| 974 | lg %r12,__LC_THREAD_INFO | ||
| 975 | jz 0f | ||
| 976 | stg %r11,__TI_last_break(%r12) | ||
| 977 | 0: mvc __LC_RETURN_PSW+8(8),BASED(cleanup_table_system_call+8) | ||
| 987 | la %r12,__LC_RETURN_PSW | 978 | la %r12,__LC_RETURN_PSW |
| 988 | br %r14 | 979 | br %r14 |
| 989 | cleanup_system_call_insn: | 980 | cleanup_system_call_insn: |
| @@ -993,61 +984,54 @@ cleanup_system_call_insn: | |||
| 993 | .quad sysc_stime | 984 | .quad sysc_stime |
| 994 | .quad sysc_update | 985 | .quad sysc_update |
| 995 | 986 | ||
| 996 | cleanup_sysc_return: | 987 | cleanup_sysc_tif: |
| 997 | mvc __LC_RETURN_PSW(8),0(%r12) | 988 | mvc __LC_RETURN_PSW(8),0(%r12) |
| 998 | mvc __LC_RETURN_PSW+8(8),BASED(cleanup_table_sysc_return) | 989 | mvc __LC_RETURN_PSW+8(8),BASED(cleanup_table_sysc_tif) |
| 999 | la %r12,__LC_RETURN_PSW | 990 | la %r12,__LC_RETURN_PSW |
| 1000 | br %r14 | 991 | br %r14 |
| 1001 | 992 | ||
| 1002 | cleanup_sysc_leave: | 993 | cleanup_sysc_restore: |
| 1003 | clc 8(8,%r12),BASED(cleanup_sysc_leave_insn) | 994 | clc 8(8,%r12),BASED(cleanup_sysc_restore_insn) |
| 1004 | je 3f | 995 | je 2f |
| 1005 | clc 8(8,%r12),BASED(cleanup_sysc_leave_insn+8) | 996 | clc 8(8,%r12),BASED(cleanup_sysc_restore_insn+8) |
| 1006 | jhe 0f | 997 | jhe 0f |
| 998 | mvc __LC_EXIT_TIMER(8),__LC_MCCK_ENTER_TIMER | ||
| 999 | cghi %r12,__LC_MCK_OLD_PSW | ||
| 1000 | je 0f | ||
| 1007 | mvc __LC_EXIT_TIMER(8),__LC_ASYNC_ENTER_TIMER | 1001 | mvc __LC_EXIT_TIMER(8),__LC_ASYNC_ENTER_TIMER |
| 1008 | 0: mvc __LC_RETURN_PSW(16),SP_PSW(%r15) | 1002 | 0: mvc __LC_RETURN_PSW(16),SP_PSW(%r15) |
| 1009 | cghi %r12,__LC_MCK_OLD_PSW | 1003 | cghi %r12,__LC_MCK_OLD_PSW |
| 1010 | jne 1f | 1004 | la %r12,__LC_SAVE_AREA+80 |
| 1011 | mvc __LC_SAVE_AREA+64(32),SP_R12(%r15) | 1005 | je 1f |
| 1012 | j 2f | 1006 | la %r12,__LC_SAVE_AREA+40 |
| 1013 | 1: mvc __LC_SAVE_AREA+32(32),SP_R12(%r15) | 1007 | 1: mvc 0(40,%r12),SP_R11(%r15) |
| 1014 | 2: lmg %r0,%r11,SP_R0(%r15) | 1008 | lmg %r0,%r10,SP_R0(%r15) |
| 1015 | lg %r15,SP_R15(%r15) | 1009 | lg %r15,SP_R15(%r15) |
| 1016 | 3: la %r12,__LC_RETURN_PSW | 1010 | 2: la %r12,__LC_RETURN_PSW |
| 1017 | br %r14 | 1011 | br %r14 |
| 1018 | cleanup_sysc_leave_insn: | 1012 | cleanup_sysc_restore_insn: |
| 1019 | .quad sysc_done - 4 | 1013 | .quad sysc_done - 4 |
| 1020 | .quad sysc_done - 16 | 1014 | .quad sysc_done - 16 |
| 1021 | 1015 | ||
| 1022 | cleanup_io_return: | 1016 | cleanup_io_tif: |
| 1023 | mvc __LC_RETURN_PSW(8),0(%r12) | ||
| 1024 | mvc __LC_RETURN_PSW+8(8),BASED(cleanup_table_io_return) | ||
| 1025 | la %r12,__LC_RETURN_PSW | ||
| 1026 | br %r14 | ||
| 1027 | |||
| 1028 | cleanup_io_work_loop: | ||
| 1029 | mvc __LC_RETURN_PSW(8),0(%r12) | 1017 | mvc __LC_RETURN_PSW(8),0(%r12) |
| 1030 | mvc __LC_RETURN_PSW+8(8),BASED(cleanup_table_io_work_loop) | 1018 | mvc __LC_RETURN_PSW+8(8),BASED(cleanup_table_io_tif) |
| 1031 | la %r12,__LC_RETURN_PSW | 1019 | la %r12,__LC_RETURN_PSW |
| 1032 | br %r14 | 1020 | br %r14 |
| 1033 | 1021 | ||
| 1034 | cleanup_io_leave: | 1022 | cleanup_io_restore: |
| 1035 | clc 8(8,%r12),BASED(cleanup_io_leave_insn) | 1023 | clc 8(8,%r12),BASED(cleanup_io_restore_insn) |
| 1036 | je 3f | 1024 | je 1f |
| 1037 | clc 8(8,%r12),BASED(cleanup_io_leave_insn+8) | 1025 | clc 8(8,%r12),BASED(cleanup_io_restore_insn+8) |
| 1038 | jhe 0f | 1026 | jhe 0f |
| 1039 | mvc __LC_EXIT_TIMER(8),__LC_ASYNC_ENTER_TIMER | 1027 | mvc __LC_EXIT_TIMER(8),__LC_MCCK_ENTER_TIMER |
| 1040 | 0: mvc __LC_RETURN_PSW(16),SP_PSW(%r15) | 1028 | 0: mvc __LC_RETURN_PSW(16),SP_PSW(%r15) |
| 1041 | cghi %r12,__LC_MCK_OLD_PSW | 1029 | mvc __LC_SAVE_AREA+80(40),SP_R11(%r15) |
| 1042 | jne 1f | 1030 | lmg %r0,%r10,SP_R0(%r15) |
| 1043 | mvc __LC_SAVE_AREA+64(32),SP_R12(%r15) | ||
| 1044 | j 2f | ||
| 1045 | 1: mvc __LC_SAVE_AREA+32(32),SP_R12(%r15) | ||
| 1046 | 2: lmg %r0,%r11,SP_R0(%r15) | ||
| 1047 | lg %r15,SP_R15(%r15) | 1031 | lg %r15,SP_R15(%r15) |
| 1048 | 3: la %r12,__LC_RETURN_PSW | 1032 | 1: la %r12,__LC_RETURN_PSW |
| 1049 | br %r14 | 1033 | br %r14 |
| 1050 | cleanup_io_leave_insn: | 1034 | cleanup_io_restore_insn: |
| 1051 | .quad io_done - 4 | 1035 | .quad io_done - 4 |
| 1052 | .quad io_done - 16 | 1036 | .quad io_done - 16 |
| 1053 | 1037 | ||
| @@ -1055,13 +1039,6 @@ cleanup_io_leave_insn: | |||
| 1055 | * Integer constants | 1039 | * Integer constants |
| 1056 | */ | 1040 | */ |
| 1057 | .align 4 | 1041 | .align 4 |
| 1058 | .Lconst: | ||
| 1059 | .Lnr_syscalls: .long NR_syscalls | ||
| 1060 | .L0x0130: .short 0x130 | ||
| 1061 | .L0x0140: .short 0x140 | ||
| 1062 | .L0x0150: .short 0x150 | ||
| 1063 | .L0x0160: .short 0x160 | ||
| 1064 | .L0x0170: .short 0x170 | ||
| 1065 | .Lcritical_start: | 1042 | .Lcritical_start: |
| 1066 | .quad __critical_start | 1043 | .quad __critical_start |
| 1067 | .Lcritical_end: | 1044 | .Lcritical_end: |
diff --git a/arch/s390/kernel/head.S b/arch/s390/kernel/head.S index 9d1f76702d47..51838ad42d56 100644 --- a/arch/s390/kernel/head.S +++ b/arch/s390/kernel/head.S | |||
| @@ -328,8 +328,8 @@ iplstart: | |||
| 328 | # | 328 | # |
| 329 | # reset files in VM reader | 329 | # reset files in VM reader |
| 330 | # | 330 | # |
| 331 | stidp __LC_CPUID # store cpuid | 331 | stidp __LC_SAVE_AREA # store cpuid |
| 332 | tm __LC_CPUID,0xff # running VM ? | 332 | tm __LC_SAVE_AREA,0xff # running VM ? |
| 333 | bno .Lnoreset | 333 | bno .Lnoreset |
| 334 | la %r2,.Lreset | 334 | la %r2,.Lreset |
| 335 | lhi %r3,26 | 335 | lhi %r3,26 |
diff --git a/arch/s390/kernel/nmi.c b/arch/s390/kernel/nmi.c index 015e27da40eb..ac151399ef34 100644 --- a/arch/s390/kernel/nmi.c +++ b/arch/s390/kernel/nmi.c | |||
| @@ -255,7 +255,8 @@ void notrace s390_do_machine_check(struct pt_regs *regs) | |||
| 255 | int umode; | 255 | int umode; |
| 256 | 256 | ||
| 257 | nmi_enter(); | 257 | nmi_enter(); |
| 258 | s390_idle_check(); | 258 | s390_idle_check(regs, S390_lowcore.mcck_clock, |
| 259 | S390_lowcore.mcck_enter_timer); | ||
| 259 | 260 | ||
| 260 | mci = (struct mci *) &S390_lowcore.mcck_interruption_code; | 261 | mci = (struct mci *) &S390_lowcore.mcck_interruption_code; |
| 261 | mcck = &__get_cpu_var(cpu_mcck); | 262 | mcck = &__get_cpu_var(cpu_mcck); |
diff --git a/arch/s390/kernel/processor.c b/arch/s390/kernel/processor.c index 0729f36c2fe3..ecb2d02b02e4 100644 --- a/arch/s390/kernel/processor.c +++ b/arch/s390/kernel/processor.c | |||
| @@ -18,24 +18,42 @@ | |||
| 18 | #include <asm/lowcore.h> | 18 | #include <asm/lowcore.h> |
| 19 | #include <asm/param.h> | 19 | #include <asm/param.h> |
| 20 | 20 | ||
| 21 | static DEFINE_PER_CPU(struct cpuid, cpu_id); | ||
| 22 | |||
| 23 | /* | ||
| 24 | * cpu_init - initializes state that is per-CPU. | ||
| 25 | */ | ||
| 26 | void __cpuinit cpu_init(void) | ||
| 27 | { | ||
| 28 | struct cpuid *id = &per_cpu(cpu_id, smp_processor_id()); | ||
| 29 | |||
| 30 | get_cpu_id(id); | ||
| 31 | atomic_inc(&init_mm.mm_count); | ||
| 32 | current->active_mm = &init_mm; | ||
| 33 | BUG_ON(current->mm); | ||
| 34 | enter_lazy_tlb(&init_mm, current); | ||
| 35 | } | ||
| 36 | |||
| 37 | /* | ||
| 38 | * print_cpu_info - print basic information about a cpu | ||
| 39 | */ | ||
| 21 | void __cpuinit print_cpu_info(void) | 40 | void __cpuinit print_cpu_info(void) |
| 22 | { | 41 | { |
| 42 | struct cpuid *id = &per_cpu(cpu_id, smp_processor_id()); | ||
| 43 | |||
| 23 | pr_info("Processor %d started, address %d, identification %06X\n", | 44 | pr_info("Processor %d started, address %d, identification %06X\n", |
| 24 | S390_lowcore.cpu_nr, S390_lowcore.cpu_addr, | 45 | S390_lowcore.cpu_nr, S390_lowcore.cpu_addr, id->ident); |
| 25 | S390_lowcore.cpu_id.ident); | ||
| 26 | } | 46 | } |
| 27 | 47 | ||
| 28 | /* | 48 | /* |
| 29 | * show_cpuinfo - Get information on one CPU for use by procfs. | 49 | * show_cpuinfo - Get information on one CPU for use by procfs. |
| 30 | */ | 50 | */ |
| 31 | |||
| 32 | static int show_cpuinfo(struct seq_file *m, void *v) | 51 | static int show_cpuinfo(struct seq_file *m, void *v) |
| 33 | { | 52 | { |
| 34 | static const char *hwcap_str[10] = { | 53 | static const char *hwcap_str[10] = { |
| 35 | "esan3", "zarch", "stfle", "msa", "ldisp", "eimm", "dfp", | 54 | "esan3", "zarch", "stfle", "msa", "ldisp", "eimm", "dfp", |
| 36 | "edat", "etf3eh", "highgprs" | 55 | "edat", "etf3eh", "highgprs" |
| 37 | }; | 56 | }; |
| 38 | struct _lowcore *lc; | ||
| 39 | unsigned long n = (unsigned long) v - 1; | 57 | unsigned long n = (unsigned long) v - 1; |
| 40 | int i; | 58 | int i; |
| 41 | 59 | ||
| @@ -55,19 +73,12 @@ static int show_cpuinfo(struct seq_file *m, void *v) | |||
| 55 | } | 73 | } |
| 56 | 74 | ||
| 57 | if (cpu_online(n)) { | 75 | if (cpu_online(n)) { |
| 58 | #ifdef CONFIG_SMP | 76 | struct cpuid *id = &per_cpu(cpu_id, n); |
| 59 | lc = (smp_processor_id() == n) ? | ||
| 60 | &S390_lowcore : lowcore_ptr[n]; | ||
| 61 | #else | ||
| 62 | lc = &S390_lowcore; | ||
| 63 | #endif | ||
| 64 | seq_printf(m, "processor %li: " | 77 | seq_printf(m, "processor %li: " |
| 65 | "version = %02X, " | 78 | "version = %02X, " |
| 66 | "identification = %06X, " | 79 | "identification = %06X, " |
| 67 | "machine = %04X\n", | 80 | "machine = %04X\n", |
| 68 | n, lc->cpu_id.version, | 81 | n, id->version, id->ident, id->machine); |
| 69 | lc->cpu_id.ident, | ||
| 70 | lc->cpu_id.machine); | ||
| 71 | } | 82 | } |
| 72 | preempt_enable(); | 83 | preempt_enable(); |
| 73 | return 0; | 84 | return 0; |
diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c index 9f654da4cecc..83339d33c4b1 100644 --- a/arch/s390/kernel/ptrace.c +++ b/arch/s390/kernel/ptrace.c | |||
| @@ -57,6 +57,7 @@ | |||
| 57 | enum s390_regset { | 57 | enum s390_regset { |
| 58 | REGSET_GENERAL, | 58 | REGSET_GENERAL, |
| 59 | REGSET_FP, | 59 | REGSET_FP, |
| 60 | REGSET_LAST_BREAK, | ||
| 60 | REGSET_GENERAL_EXTENDED, | 61 | REGSET_GENERAL_EXTENDED, |
| 61 | }; | 62 | }; |
| 62 | 63 | ||
| @@ -381,6 +382,10 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
| 381 | copied += sizeof(unsigned long); | 382 | copied += sizeof(unsigned long); |
| 382 | } | 383 | } |
| 383 | return 0; | 384 | return 0; |
| 385 | case PTRACE_GET_LAST_BREAK: | ||
| 386 | put_user(task_thread_info(child)->last_break, | ||
| 387 | (unsigned long __user *) data); | ||
| 388 | return 0; | ||
| 384 | default: | 389 | default: |
| 385 | /* Removing high order bit from addr (only for 31 bit). */ | 390 | /* Removing high order bit from addr (only for 31 bit). */ |
| 386 | addr &= PSW_ADDR_INSN; | 391 | addr &= PSW_ADDR_INSN; |
| @@ -633,6 +638,10 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, | |||
| 633 | copied += sizeof(unsigned int); | 638 | copied += sizeof(unsigned int); |
| 634 | } | 639 | } |
| 635 | return 0; | 640 | return 0; |
| 641 | case PTRACE_GET_LAST_BREAK: | ||
| 642 | put_user(task_thread_info(child)->last_break, | ||
| 643 | (unsigned int __user *) data); | ||
| 644 | return 0; | ||
| 636 | } | 645 | } |
| 637 | return compat_ptrace_request(child, request, addr, data); | 646 | return compat_ptrace_request(child, request, addr, data); |
| 638 | } | 647 | } |
| @@ -797,6 +806,28 @@ static int s390_fpregs_set(struct task_struct *target, | |||
| 797 | return rc; | 806 | return rc; |
| 798 | } | 807 | } |
| 799 | 808 | ||
| 809 | #ifdef CONFIG_64BIT | ||
| 810 | |||
| 811 | static int s390_last_break_get(struct task_struct *target, | ||
| 812 | const struct user_regset *regset, | ||
| 813 | unsigned int pos, unsigned int count, | ||
| 814 | void *kbuf, void __user *ubuf) | ||
| 815 | { | ||
| 816 | if (count > 0) { | ||
| 817 | if (kbuf) { | ||
| 818 | unsigned long *k = kbuf; | ||
| 819 | *k = task_thread_info(target)->last_break; | ||
| 820 | } else { | ||
| 821 | unsigned long __user *u = ubuf; | ||
| 822 | if (__put_user(task_thread_info(target)->last_break, u)) | ||
| 823 | return -EFAULT; | ||
| 824 | } | ||
| 825 | } | ||
| 826 | return 0; | ||
| 827 | } | ||
| 828 | |||
| 829 | #endif | ||
| 830 | |||
| 800 | static const struct user_regset s390_regsets[] = { | 831 | static const struct user_regset s390_regsets[] = { |
| 801 | [REGSET_GENERAL] = { | 832 | [REGSET_GENERAL] = { |
| 802 | .core_note_type = NT_PRSTATUS, | 833 | .core_note_type = NT_PRSTATUS, |
| @@ -814,6 +845,15 @@ static const struct user_regset s390_regsets[] = { | |||
| 814 | .get = s390_fpregs_get, | 845 | .get = s390_fpregs_get, |
| 815 | .set = s390_fpregs_set, | 846 | .set = s390_fpregs_set, |
| 816 | }, | 847 | }, |
| 848 | #ifdef CONFIG_64BIT | ||
| 849 | [REGSET_LAST_BREAK] = { | ||
| 850 | .core_note_type = NT_S390_LAST_BREAK, | ||
| 851 | .n = 1, | ||
| 852 | .size = sizeof(long), | ||
| 853 | .align = sizeof(long), | ||
| 854 | .get = s390_last_break_get, | ||
| 855 | }, | ||
| 856 | #endif | ||
| 817 | }; | 857 | }; |
| 818 | 858 | ||
| 819 | static const struct user_regset_view user_s390_view = { | 859 | static const struct user_regset_view user_s390_view = { |
| @@ -948,6 +988,27 @@ static int s390_compat_regs_high_set(struct task_struct *target, | |||
| 948 | return rc; | 988 | return rc; |
| 949 | } | 989 | } |
| 950 | 990 | ||
| 991 | static int s390_compat_last_break_get(struct task_struct *target, | ||
| 992 | const struct user_regset *regset, | ||
| 993 | unsigned int pos, unsigned int count, | ||
| 994 | void *kbuf, void __user *ubuf) | ||
| 995 | { | ||
| 996 | compat_ulong_t last_break; | ||
| 997 | |||
| 998 | if (count > 0) { | ||
| 999 | last_break = task_thread_info(target)->last_break; | ||
| 1000 | if (kbuf) { | ||
| 1001 | unsigned long *k = kbuf; | ||
| 1002 | *k = last_break; | ||
| 1003 | } else { | ||
| 1004 | unsigned long __user *u = ubuf; | ||
| 1005 | if (__put_user(last_break, u)) | ||
| 1006 | return -EFAULT; | ||
| 1007 | } | ||
| 1008 | } | ||
| 1009 | return 0; | ||
| 1010 | } | ||
| 1011 | |||
| 951 | static const struct user_regset s390_compat_regsets[] = { | 1012 | static const struct user_regset s390_compat_regsets[] = { |
| 952 | [REGSET_GENERAL] = { | 1013 | [REGSET_GENERAL] = { |
| 953 | .core_note_type = NT_PRSTATUS, | 1014 | .core_note_type = NT_PRSTATUS, |
| @@ -965,6 +1026,13 @@ static const struct user_regset s390_compat_regsets[] = { | |||
| 965 | .get = s390_fpregs_get, | 1026 | .get = s390_fpregs_get, |
| 966 | .set = s390_fpregs_set, | 1027 | .set = s390_fpregs_set, |
| 967 | }, | 1028 | }, |
| 1029 | [REGSET_LAST_BREAK] = { | ||
| 1030 | .core_note_type = NT_S390_LAST_BREAK, | ||
| 1031 | .n = 1, | ||
| 1032 | .size = sizeof(long), | ||
| 1033 | .align = sizeof(long), | ||
| 1034 | .get = s390_compat_last_break_get, | ||
| 1035 | }, | ||
| 968 | [REGSET_GENERAL_EXTENDED] = { | 1036 | [REGSET_GENERAL_EXTENDED] = { |
| 969 | .core_note_type = NT_S390_HIGH_GPRS, | 1037 | .core_note_type = NT_S390_HIGH_GPRS, |
| 970 | .n = sizeof(s390_compat_regs_high) / sizeof(compat_long_t), | 1038 | .n = sizeof(s390_compat_regs_high) / sizeof(compat_long_t), |
diff --git a/arch/s390/kernel/s390_ext.c b/arch/s390/kernel/s390_ext.c index 59618bcd99b7..9ce641b5291f 100644 --- a/arch/s390/kernel/s390_ext.c +++ b/arch/s390/kernel/s390_ext.c | |||
| @@ -120,7 +120,8 @@ void __irq_entry do_extint(struct pt_regs *regs, unsigned short code) | |||
| 120 | struct pt_regs *old_regs; | 120 | struct pt_regs *old_regs; |
| 121 | 121 | ||
| 122 | old_regs = set_irq_regs(regs); | 122 | old_regs = set_irq_regs(regs); |
| 123 | s390_idle_check(); | 123 | s390_idle_check(regs, S390_lowcore.int_clock, |
| 124 | S390_lowcore.async_enter_timer); | ||
| 124 | irq_enter(); | 125 | irq_enter(); |
| 125 | if (S390_lowcore.int_clock >= S390_lowcore.clock_comparator) | 126 | if (S390_lowcore.int_clock >= S390_lowcore.clock_comparator) |
| 126 | /* Serve timer interrupts first. */ | 127 | /* Serve timer interrupts first. */ |
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 91625f759ccd..7d893248d265 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | * arch/s390/kernel/setup.c | 2 | * arch/s390/kernel/setup.c |
| 3 | * | 3 | * |
| 4 | * S390 version | 4 | * S390 version |
| 5 | * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation | 5 | * Copyright (C) IBM Corp. 1999,2010 |
| 6 | * Author(s): Hartmut Penner (hp@de.ibm.com), | 6 | * Author(s): Hartmut Penner (hp@de.ibm.com), |
| 7 | * Martin Schwidefsky (schwidefsky@de.ibm.com) | 7 | * Martin Schwidefsky (schwidefsky@de.ibm.com) |
| 8 | * | 8 | * |
| @@ -113,22 +113,6 @@ static struct resource data_resource = { | |||
| 113 | }; | 113 | }; |
| 114 | 114 | ||
| 115 | /* | 115 | /* |
| 116 | * cpu_init() initializes state that is per-CPU. | ||
| 117 | */ | ||
| 118 | void __cpuinit cpu_init(void) | ||
| 119 | { | ||
| 120 | /* | ||
| 121 | * Store processor id in lowcore (used e.g. in timer_interrupt) | ||
| 122 | */ | ||
| 123 | get_cpu_id(&S390_lowcore.cpu_id); | ||
| 124 | |||
| 125 | atomic_inc(&init_mm.mm_count); | ||
| 126 | current->active_mm = &init_mm; | ||
| 127 | BUG_ON(current->mm); | ||
| 128 | enter_lazy_tlb(&init_mm, current); | ||
| 129 | } | ||
| 130 | |||
| 131 | /* | ||
| 132 | * condev= and conmode= setup parameter. | 116 | * condev= and conmode= setup parameter. |
| 133 | */ | 117 | */ |
| 134 | 118 | ||
| @@ -385,10 +369,6 @@ static void setup_addressing_mode(void) | |||
| 385 | pr_info("Address spaces switched, " | 369 | pr_info("Address spaces switched, " |
| 386 | "mvcos not available\n"); | 370 | "mvcos not available\n"); |
| 387 | } | 371 | } |
| 388 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
| 389 | sysc_restore_trace_psw.mask = psw_kernel_bits & ~PSW_MASK_MCHECK; | ||
| 390 | io_restore_trace_psw.mask = psw_kernel_bits & ~PSW_MASK_MCHECK; | ||
| 391 | #endif | ||
| 392 | } | 372 | } |
| 393 | 373 | ||
| 394 | static void __init | 374 | static void __init |
| @@ -421,6 +401,7 @@ setup_lowcore(void) | |||
| 421 | lc->io_new_psw.mask = psw_kernel_bits; | 401 | lc->io_new_psw.mask = psw_kernel_bits; |
| 422 | lc->io_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) io_int_handler; | 402 | lc->io_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) io_int_handler; |
| 423 | lc->clock_comparator = -1ULL; | 403 | lc->clock_comparator = -1ULL; |
| 404 | lc->cmf_hpp = -1ULL; | ||
| 424 | lc->kernel_stack = ((unsigned long) &init_thread_union) + THREAD_SIZE; | 405 | lc->kernel_stack = ((unsigned long) &init_thread_union) + THREAD_SIZE; |
| 425 | lc->async_stack = (unsigned long) | 406 | lc->async_stack = (unsigned long) |
| 426 | __alloc_bootmem(ASYNC_SIZE, ASYNC_SIZE, 0) + ASYNC_SIZE; | 407 | __alloc_bootmem(ASYNC_SIZE, ASYNC_SIZE, 0) + ASYNC_SIZE; |
| @@ -695,6 +676,7 @@ static void __init setup_hwcaps(void) | |||
| 695 | static const int stfl_bits[6] = { 0, 2, 7, 17, 19, 21 }; | 676 | static const int stfl_bits[6] = { 0, 2, 7, 17, 19, 21 }; |
| 696 | unsigned long long facility_list_extended; | 677 | unsigned long long facility_list_extended; |
| 697 | unsigned int facility_list; | 678 | unsigned int facility_list; |
| 679 | struct cpuid cpu_id; | ||
| 698 | int i; | 680 | int i; |
| 699 | 681 | ||
| 700 | facility_list = stfl(); | 682 | facility_list = stfl(); |
| @@ -756,7 +738,8 @@ static void __init setup_hwcaps(void) | |||
| 756 | */ | 738 | */ |
| 757 | elf_hwcap |= HWCAP_S390_HIGH_GPRS; | 739 | elf_hwcap |= HWCAP_S390_HIGH_GPRS; |
| 758 | 740 | ||
| 759 | switch (S390_lowcore.cpu_id.machine) { | 741 | get_cpu_id(&cpu_id); |
| 742 | switch (cpu_id.machine) { | ||
| 760 | case 0x9672: | 743 | case 0x9672: |
| 761 | #if !defined(CONFIG_64BIT) | 744 | #if !defined(CONFIG_64BIT) |
| 762 | default: /* Use "g5" as default for 31 bit kernels. */ | 745 | default: /* Use "g5" as default for 31 bit kernels. */ |
diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c index 6289945562b0..ee7ac8b11782 100644 --- a/arch/s390/kernel/signal.c +++ b/arch/s390/kernel/signal.c | |||
| @@ -313,6 +313,7 @@ static int setup_frame(int sig, struct k_sigaction *ka, | |||
| 313 | To avoid breaking binary compatibility, they are passed as args. */ | 313 | To avoid breaking binary compatibility, they are passed as args. */ |
| 314 | regs->gprs[4] = current->thread.trap_no; | 314 | regs->gprs[4] = current->thread.trap_no; |
| 315 | regs->gprs[5] = current->thread.prot_addr; | 315 | regs->gprs[5] = current->thread.prot_addr; |
| 316 | regs->gprs[6] = task_thread_info(current)->last_break; | ||
| 316 | 317 | ||
| 317 | /* Place signal number on stack to allow backtrace from handler. */ | 318 | /* Place signal number on stack to allow backtrace from handler. */ |
| 318 | if (__put_user(regs->gprs[2], (int __user *) &frame->signo)) | 319 | if (__put_user(regs->gprs[2], (int __user *) &frame->signo)) |
| @@ -376,6 +377,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
| 376 | regs->gprs[2] = map_signal(sig); | 377 | regs->gprs[2] = map_signal(sig); |
| 377 | regs->gprs[3] = (unsigned long) &frame->info; | 378 | regs->gprs[3] = (unsigned long) &frame->info; |
| 378 | regs->gprs[4] = (unsigned long) &frame->uc; | 379 | regs->gprs[4] = (unsigned long) &frame->uc; |
| 380 | regs->gprs[5] = task_thread_info(current)->last_break; | ||
| 379 | return 0; | 381 | return 0; |
| 380 | 382 | ||
| 381 | give_sigsegv: | 383 | give_sigsegv: |
diff --git a/arch/s390/kernel/topology.c b/arch/s390/kernel/topology.c index 247b4c2d1e51..bcef00766a64 100644 --- a/arch/s390/kernel/topology.c +++ b/arch/s390/kernel/topology.c | |||
| @@ -37,7 +37,8 @@ struct tl_cpu { | |||
| 37 | }; | 37 | }; |
| 38 | 38 | ||
| 39 | struct tl_container { | 39 | struct tl_container { |
| 40 | unsigned char reserved[8]; | 40 | unsigned char reserved[7]; |
| 41 | unsigned char id; | ||
| 41 | }; | 42 | }; |
| 42 | 43 | ||
| 43 | union tl_entry { | 44 | union tl_entry { |
| @@ -58,6 +59,7 @@ struct tl_info { | |||
| 58 | 59 | ||
| 59 | struct core_info { | 60 | struct core_info { |
| 60 | struct core_info *next; | 61 | struct core_info *next; |
| 62 | unsigned char id; | ||
| 61 | cpumask_t mask; | 63 | cpumask_t mask; |
| 62 | }; | 64 | }; |
| 63 | 65 | ||
| @@ -73,6 +75,7 @@ static DECLARE_WORK(topology_work, topology_work_fn); | |||
| 73 | static DEFINE_SPINLOCK(topology_lock); | 75 | static DEFINE_SPINLOCK(topology_lock); |
| 74 | 76 | ||
| 75 | cpumask_t cpu_core_map[NR_CPUS]; | 77 | cpumask_t cpu_core_map[NR_CPUS]; |
| 78 | unsigned char cpu_core_id[NR_CPUS]; | ||
| 76 | 79 | ||
| 77 | static cpumask_t cpu_coregroup_map(unsigned int cpu) | 80 | static cpumask_t cpu_coregroup_map(unsigned int cpu) |
| 78 | { | 81 | { |
| @@ -116,6 +119,7 @@ static void add_cpus_to_core(struct tl_cpu *tl_cpu, struct core_info *core) | |||
| 116 | for_each_present_cpu(lcpu) { | 119 | for_each_present_cpu(lcpu) { |
| 117 | if (cpu_logical_map(lcpu) == rcpu) { | 120 | if (cpu_logical_map(lcpu) == rcpu) { |
| 118 | cpu_set(lcpu, core->mask); | 121 | cpu_set(lcpu, core->mask); |
| 122 | cpu_core_id[lcpu] = core->id; | ||
| 119 | smp_cpu_polarization[lcpu] = tl_cpu->pp; | 123 | smp_cpu_polarization[lcpu] = tl_cpu->pp; |
| 120 | } | 124 | } |
| 121 | } | 125 | } |
| @@ -158,6 +162,7 @@ static void tl_to_cores(struct tl_info *info) | |||
| 158 | break; | 162 | break; |
| 159 | case 1: | 163 | case 1: |
| 160 | core = core->next; | 164 | core = core->next; |
| 165 | core->id = tle->container.id; | ||
| 161 | break; | 166 | break; |
| 162 | case 0: | 167 | case 0: |
| 163 | add_cpus_to_core(&tle->cpu, core); | 168 | add_cpus_to_core(&tle->cpu, core); |
diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c index 6e7ad63854c0..5d8f0f3d0250 100644 --- a/arch/s390/kernel/traps.c +++ b/arch/s390/kernel/traps.c | |||
| @@ -46,13 +46,7 @@ | |||
| 46 | 46 | ||
| 47 | pgm_check_handler_t *pgm_check_table[128]; | 47 | pgm_check_handler_t *pgm_check_table[128]; |
| 48 | 48 | ||
| 49 | #ifdef CONFIG_SYSCTL | 49 | int show_unhandled_signals; |
| 50 | #ifdef CONFIG_PROCESS_DEBUG | ||
| 51 | int sysctl_userprocess_debug = 1; | ||
| 52 | #else | ||
| 53 | int sysctl_userprocess_debug = 0; | ||
| 54 | #endif | ||
| 55 | #endif | ||
| 56 | 50 | ||
| 57 | extern pgm_check_handler_t do_protection_exception; | 51 | extern pgm_check_handler_t do_protection_exception; |
| 58 | extern pgm_check_handler_t do_dat_exception; | 52 | extern pgm_check_handler_t do_dat_exception; |
| @@ -315,18 +309,19 @@ void die(const char * str, struct pt_regs * regs, long err) | |||
| 315 | do_exit(SIGSEGV); | 309 | do_exit(SIGSEGV); |
| 316 | } | 310 | } |
| 317 | 311 | ||
| 318 | static void inline | 312 | static void inline report_user_fault(struct pt_regs *regs, long int_code, |
| 319 | report_user_fault(long interruption_code, struct pt_regs *regs) | 313 | int signr) |
| 320 | { | 314 | { |
| 321 | #if defined(CONFIG_SYSCTL) | 315 | if ((task_pid_nr(current) > 1) && !show_unhandled_signals) |
| 322 | if (!sysctl_userprocess_debug) | ||
| 323 | return; | 316 | return; |
| 324 | #endif | 317 | if (!unhandled_signal(current, signr)) |
| 325 | #if defined(CONFIG_SYSCTL) || defined(CONFIG_PROCESS_DEBUG) | 318 | return; |
| 326 | printk("User process fault: interruption code 0x%lX\n", | 319 | if (!printk_ratelimit()) |
| 327 | interruption_code); | 320 | return; |
| 321 | printk("User process fault: interruption code 0x%lX ", int_code); | ||
| 322 | print_vma_addr("in ", regs->psw.addr & PSW_ADDR_INSN); | ||
| 323 | printk("\n"); | ||
| 328 | show_regs(regs); | 324 | show_regs(regs); |
| 329 | #endif | ||
| 330 | } | 325 | } |
| 331 | 326 | ||
| 332 | int is_valid_bugaddr(unsigned long addr) | 327 | int is_valid_bugaddr(unsigned long addr) |
| @@ -354,7 +349,7 @@ static void __kprobes inline do_trap(long interruption_code, int signr, | |||
| 354 | 349 | ||
| 355 | tsk->thread.trap_no = interruption_code & 0xffff; | 350 | tsk->thread.trap_no = interruption_code & 0xffff; |
| 356 | force_sig_info(signr, info, tsk); | 351 | force_sig_info(signr, info, tsk); |
| 357 | report_user_fault(interruption_code, regs); | 352 | report_user_fault(regs, interruption_code, signr); |
| 358 | } else { | 353 | } else { |
| 359 | const struct exception_table_entry *fixup; | 354 | const struct exception_table_entry *fixup; |
| 360 | fixup = search_exception_tables(regs->psw.addr & PSW_ADDR_INSN); | 355 | fixup = search_exception_tables(regs->psw.addr & PSW_ADDR_INSN); |
| @@ -390,8 +385,8 @@ static void default_trap_handler(struct pt_regs * regs, long interruption_code) | |||
| 390 | { | 385 | { |
| 391 | if (regs->psw.mask & PSW_MASK_PSTATE) { | 386 | if (regs->psw.mask & PSW_MASK_PSTATE) { |
| 392 | local_irq_enable(); | 387 | local_irq_enable(); |
| 388 | report_user_fault(regs, interruption_code, SIGSEGV); | ||
| 393 | do_exit(SIGSEGV); | 389 | do_exit(SIGSEGV); |
| 394 | report_user_fault(interruption_code, regs); | ||
| 395 | } else | 390 | } else |
| 396 | die("Unknown program exception", regs, interruption_code); | 391 | die("Unknown program exception", regs, interruption_code); |
| 397 | } | 392 | } |
diff --git a/arch/s390/kernel/vdso.c b/arch/s390/kernel/vdso.c index 6bc9c197aa91..6b83870507d5 100644 --- a/arch/s390/kernel/vdso.c +++ b/arch/s390/kernel/vdso.c | |||
| @@ -102,11 +102,7 @@ static void vdso_init_per_cpu_data(int cpu, struct vdso_per_cpu_data *vpcd) | |||
| 102 | /* | 102 | /* |
| 103 | * Allocate/free per cpu vdso data. | 103 | * Allocate/free per cpu vdso data. |
| 104 | */ | 104 | */ |
| 105 | #ifdef CONFIG_64BIT | ||
| 106 | #define SEGMENT_ORDER 2 | 105 | #define SEGMENT_ORDER 2 |
| 107 | #else | ||
| 108 | #define SEGMENT_ORDER 1 | ||
| 109 | #endif | ||
| 110 | 106 | ||
| 111 | int vdso_alloc_per_cpu(int cpu, struct _lowcore *lowcore) | 107 | int vdso_alloc_per_cpu(int cpu, struct _lowcore *lowcore) |
| 112 | { | 108 | { |
diff --git a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c index b59a812a010e..3479f1b0d4e0 100644 --- a/arch/s390/kernel/vtime.c +++ b/arch/s390/kernel/vtime.c | |||
| @@ -121,32 +121,35 @@ void account_system_vtime(struct task_struct *tsk) | |||
| 121 | } | 121 | } |
| 122 | EXPORT_SYMBOL_GPL(account_system_vtime); | 122 | EXPORT_SYMBOL_GPL(account_system_vtime); |
| 123 | 123 | ||
| 124 | void vtime_start_cpu(void) | 124 | void vtime_start_cpu(__u64 int_clock, __u64 enter_timer) |
| 125 | { | 125 | { |
| 126 | struct s390_idle_data *idle = &__get_cpu_var(s390_idle); | 126 | struct s390_idle_data *idle = &__get_cpu_var(s390_idle); |
| 127 | struct vtimer_queue *vq = &__get_cpu_var(virt_cpu_timer); | 127 | struct vtimer_queue *vq = &__get_cpu_var(virt_cpu_timer); |
| 128 | __u64 idle_time, expires; | 128 | __u64 idle_time, expires; |
| 129 | 129 | ||
| 130 | if (idle->idle_enter == 0ULL) | ||
| 131 | return; | ||
| 132 | |||
| 130 | /* Account time spent with enabled wait psw loaded as idle time. */ | 133 | /* Account time spent with enabled wait psw loaded as idle time. */ |
| 131 | idle_time = S390_lowcore.int_clock - idle->idle_enter; | 134 | idle_time = int_clock - idle->idle_enter; |
| 132 | account_idle_time(idle_time); | 135 | account_idle_time(idle_time); |
| 133 | S390_lowcore.steal_timer += | 136 | S390_lowcore.steal_timer += |
| 134 | idle->idle_enter - S390_lowcore.last_update_clock; | 137 | idle->idle_enter - S390_lowcore.last_update_clock; |
| 135 | S390_lowcore.last_update_clock = S390_lowcore.int_clock; | 138 | S390_lowcore.last_update_clock = int_clock; |
| 136 | 139 | ||
| 137 | /* Account system time spent going idle. */ | 140 | /* Account system time spent going idle. */ |
| 138 | S390_lowcore.system_timer += S390_lowcore.last_update_timer - vq->idle; | 141 | S390_lowcore.system_timer += S390_lowcore.last_update_timer - vq->idle; |
| 139 | S390_lowcore.last_update_timer = S390_lowcore.async_enter_timer; | 142 | S390_lowcore.last_update_timer = enter_timer; |
| 140 | 143 | ||
| 141 | /* Restart vtime CPU timer */ | 144 | /* Restart vtime CPU timer */ |
| 142 | if (vq->do_spt) { | 145 | if (vq->do_spt) { |
| 143 | /* Program old expire value but first save progress. */ | 146 | /* Program old expire value but first save progress. */ |
| 144 | expires = vq->idle - S390_lowcore.async_enter_timer; | 147 | expires = vq->idle - enter_timer; |
| 145 | expires += get_vtimer(); | 148 | expires += get_vtimer(); |
| 146 | set_vtimer(expires); | 149 | set_vtimer(expires); |
| 147 | } else { | 150 | } else { |
| 148 | /* Don't account the CPU timer delta while the cpu was idle. */ | 151 | /* Don't account the CPU timer delta while the cpu was idle. */ |
| 149 | vq->elapsed -= vq->idle - S390_lowcore.async_enter_timer; | 152 | vq->elapsed -= vq->idle - enter_timer; |
| 150 | } | 153 | } |
| 151 | 154 | ||
| 152 | idle->sequence++; | 155 | idle->sequence++; |
diff --git a/arch/s390/kvm/Kconfig b/arch/s390/kvm/Kconfig index a7251580891c..2f4b687cc7fa 100644 --- a/arch/s390/kvm/Kconfig +++ b/arch/s390/kvm/Kconfig | |||
| @@ -33,6 +33,17 @@ config KVM | |||
| 33 | 33 | ||
| 34 | If unsure, say N. | 34 | If unsure, say N. |
| 35 | 35 | ||
| 36 | config KVM_AWARE_CMF | ||
| 37 | depends on KVM | ||
| 38 | bool "KVM aware sampling" | ||
| 39 | ---help--- | ||
| 40 | This option enhances the sampling data from the CPU Measurement | ||
| 41 | Facility with additional information, that allows to distinguish | ||
| 42 | guest(s) and host when using the kernel based virtual machine | ||
| 43 | functionality. | ||
| 44 | |||
| 45 | If unsure, say N. | ||
| 46 | |||
| 36 | # OK, it's a little counter-intuitive to do this, but it puts it neatly under | 47 | # OK, it's a little counter-intuitive to do this, but it puts it neatly under |
| 37 | # the virtualization menu. | 48 | # the virtualization menu. |
| 38 | source drivers/vhost/Kconfig | 49 | source drivers/vhost/Kconfig |
diff --git a/arch/s390/kvm/sie64a.S b/arch/s390/kvm/sie64a.S index 934fd6a885f6..31646bd0e469 100644 --- a/arch/s390/kvm/sie64a.S +++ b/arch/s390/kvm/sie64a.S | |||
| @@ -1,20 +1,60 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * sie64a.S - low level sie call | 2 | * sie64a.S - low level sie call |
| 3 | * | 3 | * |
| 4 | * Copyright IBM Corp. 2008 | 4 | * Copyright IBM Corp. 2008,2010 |
| 5 | * | 5 | * |
| 6 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
| 7 | * it under the terms of the GNU General Public License (version 2 only) | 7 | * it under the terms of the GNU General Public License (version 2 only) |
| 8 | * as published by the Free Software Foundation. | 8 | * as published by the Free Software Foundation. |
| 9 | * | 9 | * |
| 10 | * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com> | 10 | * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com> |
| 11 | * Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com> | ||
| 11 | */ | 12 | */ |
| 12 | 13 | ||
| 13 | #include <linux/errno.h> | 14 | #include <linux/errno.h> |
| 14 | #include <asm/asm-offsets.h> | 15 | #include <asm/asm-offsets.h> |
| 16 | #include <asm/setup.h> | ||
| 17 | #include <asm/asm-offsets.h> | ||
| 18 | #include <asm/ptrace.h> | ||
| 19 | #include <asm/thread_info.h> | ||
| 20 | |||
| 21 | _TIF_EXIT_SIE = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_MCCK_PENDING) | ||
| 22 | |||
| 23 | /* | ||
| 24 | * offsets into stackframe | ||
| 25 | * SP_ = offsets into stack sie64 is called with | ||
| 26 | * SPI_ = offsets into irq stack | ||
| 27 | */ | ||
| 28 | SP_GREGS = __SF_EMPTY | ||
| 29 | SP_HOOK = __SF_EMPTY+8 | ||
| 30 | SP_GPP = __SF_EMPTY+16 | ||
| 31 | SPI_PSW = STACK_FRAME_OVERHEAD + __PT_PSW | ||
| 32 | |||
| 15 | 33 | ||
| 16 | SP_R5 = 5 * 8 # offset into stackframe | 34 | .macro SPP newpp |
| 17 | SP_R6 = 6 * 8 | 35 | #ifdef CONFIG_KVM_AWARE_CMF |
| 36 | tm __LC_MACHINE_FLAGS+6,0x20 # MACHINE_FLAG_SPP | ||
| 37 | jz 0f | ||
| 38 | .insn s,0xb2800000,\newpp | ||
| 39 | 0: | ||
| 40 | #endif | ||
| 41 | .endm | ||
| 42 | |||
| 43 | sie_irq_handler: | ||
| 44 | SPP __LC_CMF_HPP # set host id | ||
| 45 | larl %r2,sie_inst | ||
| 46 | clg %r2,SPI_PSW+8(0,%r15) # intercepted sie | ||
| 47 | jne 1f | ||
| 48 | xc __LC_SIE_HOOK(8),__LC_SIE_HOOK | ||
| 49 | lg %r2,__LC_THREAD_INFO # pointer thread_info struct | ||
| 50 | tm __TI_flags+7(%r2),_TIF_EXIT_SIE | ||
| 51 | jz 0f | ||
| 52 | larl %r2,sie_exit # work pending, leave sie | ||
| 53 | stg %r2,__LC_RETURN_PSW+8 | ||
| 54 | br %r14 | ||
| 55 | 0: larl %r2,sie_reenter # re-enter with guest id | ||
| 56 | stg %r2,__LC_RETURN_PSW+8 | ||
| 57 | 1: br %r14 | ||
| 18 | 58 | ||
| 19 | /* | 59 | /* |
| 20 | * sie64a calling convention: | 60 | * sie64a calling convention: |
| @@ -23,23 +63,34 @@ SP_R6 = 6 * 8 | |||
| 23 | */ | 63 | */ |
| 24 | .globl sie64a | 64 | .globl sie64a |
| 25 | sie64a: | 65 | sie64a: |
| 26 | lgr %r5,%r3 | 66 | stg %r3,SP_GREGS(%r15) # save guest register save area |
| 27 | stmg %r5,%r14,SP_R5(%r15) # save register on entry | 67 | stmg %r6,%r14,__SF_GPRS(%r15) # save registers on entry |
| 28 | lgr %r14,%r2 # pointer to sie control block | 68 | lgr %r14,%r2 # pointer to sie control block |
| 29 | lmg %r0,%r13,0(%r3) # load guest gprs 0-13 | 69 | larl %r5,sie_irq_handler |
| 70 | stg %r2,SP_GPP(%r15) | ||
| 71 | stg %r5,SP_HOOK(%r15) # save hook target | ||
| 72 | lmg %r0,%r13,0(%r3) # load guest gprs 0-13 | ||
| 73 | sie_reenter: | ||
| 74 | mvc __LC_SIE_HOOK(8),SP_HOOK(%r15) | ||
| 75 | SPP SP_GPP(%r15) # set guest id | ||
| 30 | sie_inst: | 76 | sie_inst: |
| 31 | sie 0(%r14) | 77 | sie 0(%r14) |
| 32 | lg %r14,SP_R5(%r15) | 78 | xc __LC_SIE_HOOK(8),__LC_SIE_HOOK |
| 33 | stmg %r0,%r13,0(%r14) # save guest gprs 0-13 | 79 | SPP __LC_CMF_HPP # set host id |
| 80 | sie_exit: | ||
| 81 | lg %r14,SP_GREGS(%r15) | ||
| 82 | stmg %r0,%r13,0(%r14) # save guest gprs 0-13 | ||
| 34 | lghi %r2,0 | 83 | lghi %r2,0 |
| 35 | lmg %r6,%r14,SP_R6(%r15) | 84 | lmg %r6,%r14,__SF_GPRS(%r15) |
| 36 | br %r14 | 85 | br %r14 |
| 37 | 86 | ||
| 38 | sie_err: | 87 | sie_err: |
| 39 | lg %r14,SP_R5(%r15) | 88 | xc __LC_SIE_HOOK(8),__LC_SIE_HOOK |
| 40 | stmg %r0,%r13,0(%r14) # save guest gprs 0-13 | 89 | SPP __LC_CMF_HPP # set host id |
| 90 | lg %r14,SP_GREGS(%r15) | ||
| 91 | stmg %r0,%r13,0(%r14) # save guest gprs 0-13 | ||
| 41 | lghi %r2,-EFAULT | 92 | lghi %r2,-EFAULT |
| 42 | lmg %r6,%r14,SP_R6(%r15) | 93 | lmg %r6,%r14,__SF_GPRS(%r15) |
| 43 | br %r14 | 94 | br %r14 |
| 44 | 95 | ||
| 45 | .section __ex_table,"a" | 96 | .section __ex_table,"a" |
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index 3040d7c78fe0..2505b2ea0ef1 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c | |||
| @@ -48,10 +48,6 @@ | |||
| 48 | #define __PF_RES_FIELD 0x8000000000000000ULL | 48 | #define __PF_RES_FIELD 0x8000000000000000ULL |
| 49 | #endif /* CONFIG_64BIT */ | 49 | #endif /* CONFIG_64BIT */ |
| 50 | 50 | ||
| 51 | #ifdef CONFIG_SYSCTL | ||
| 52 | extern int sysctl_userprocess_debug; | ||
| 53 | #endif | ||
| 54 | |||
| 55 | #define VM_FAULT_BADCONTEXT 0x010000 | 51 | #define VM_FAULT_BADCONTEXT 0x010000 |
| 56 | #define VM_FAULT_BADMAP 0x020000 | 52 | #define VM_FAULT_BADMAP 0x020000 |
| 57 | #define VM_FAULT_BADACCESS 0x040000 | 53 | #define VM_FAULT_BADACCESS 0x040000 |
| @@ -120,6 +116,22 @@ static inline int user_space_fault(unsigned long trans_exc_code) | |||
| 120 | return trans_exc_code != 3; | 116 | return trans_exc_code != 3; |
| 121 | } | 117 | } |
| 122 | 118 | ||
| 119 | static inline void report_user_fault(struct pt_regs *regs, long int_code, | ||
| 120 | int signr, unsigned long address) | ||
| 121 | { | ||
| 122 | if ((task_pid_nr(current) > 1) && !show_unhandled_signals) | ||
| 123 | return; | ||
| 124 | if (!unhandled_signal(current, signr)) | ||
| 125 | return; | ||
| 126 | if (!printk_ratelimit()) | ||
| 127 | return; | ||
| 128 | printk("User process fault: interruption code 0x%lX ", int_code); | ||
| 129 | print_vma_addr(KERN_CONT "in ", regs->psw.addr & PSW_ADDR_INSN); | ||
| 130 | printk("\n"); | ||
| 131 | printk("failing address: %lX\n", address); | ||
| 132 | show_regs(regs); | ||
| 133 | } | ||
| 134 | |||
| 123 | /* | 135 | /* |
| 124 | * Send SIGSEGV to task. This is an external routine | 136 | * Send SIGSEGV to task. This is an external routine |
| 125 | * to keep the stack usage of do_page_fault small. | 137 | * to keep the stack usage of do_page_fault small. |
| @@ -133,17 +145,7 @@ static noinline void do_sigsegv(struct pt_regs *regs, long int_code, | |||
| 133 | address = trans_exc_code & __FAIL_ADDR_MASK; | 145 | address = trans_exc_code & __FAIL_ADDR_MASK; |
| 134 | current->thread.prot_addr = address; | 146 | current->thread.prot_addr = address; |
| 135 | current->thread.trap_no = int_code; | 147 | current->thread.trap_no = int_code; |
| 136 | #if defined(CONFIG_SYSCTL) || defined(CONFIG_PROCESS_DEBUG) | 148 | report_user_fault(regs, int_code, SIGSEGV, address); |
| 137 | #if defined(CONFIG_SYSCTL) | ||
| 138 | if (sysctl_userprocess_debug) | ||
| 139 | #endif | ||
| 140 | { | ||
| 141 | printk("User process fault: interruption code 0x%lX\n", | ||
| 142 | int_code); | ||
| 143 | printk("failing address: %lX\n", address); | ||
| 144 | show_regs(regs); | ||
| 145 | } | ||
| 146 | #endif | ||
| 147 | si.si_signo = SIGSEGV; | 149 | si.si_signo = SIGSEGV; |
| 148 | si.si_code = si_code; | 150 | si.si_code = si_code; |
| 149 | si.si_addr = (void __user *) address; | 151 | si.si_addr = (void __user *) address; |
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index fa2339cb1681..0e86247d791e 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c | |||
| @@ -65,6 +65,7 @@ static void dasd_device_tasklet(struct dasd_device *); | |||
| 65 | static void dasd_block_tasklet(struct dasd_block *); | 65 | static void dasd_block_tasklet(struct dasd_block *); |
| 66 | static void do_kick_device(struct work_struct *); | 66 | static void do_kick_device(struct work_struct *); |
| 67 | static void do_restore_device(struct work_struct *); | 67 | static void do_restore_device(struct work_struct *); |
| 68 | static void do_reload_device(struct work_struct *); | ||
| 68 | static void dasd_return_cqr_cb(struct dasd_ccw_req *, void *); | 69 | static void dasd_return_cqr_cb(struct dasd_ccw_req *, void *); |
| 69 | static void dasd_device_timeout(unsigned long); | 70 | static void dasd_device_timeout(unsigned long); |
| 70 | static void dasd_block_timeout(unsigned long); | 71 | static void dasd_block_timeout(unsigned long); |
| @@ -115,6 +116,7 @@ struct dasd_device *dasd_alloc_device(void) | |||
| 115 | device->timer.data = (unsigned long) device; | 116 | device->timer.data = (unsigned long) device; |
| 116 | INIT_WORK(&device->kick_work, do_kick_device); | 117 | INIT_WORK(&device->kick_work, do_kick_device); |
| 117 | INIT_WORK(&device->restore_device, do_restore_device); | 118 | INIT_WORK(&device->restore_device, do_restore_device); |
| 119 | INIT_WORK(&device->reload_device, do_reload_device); | ||
| 118 | device->state = DASD_STATE_NEW; | 120 | device->state = DASD_STATE_NEW; |
| 119 | device->target = DASD_STATE_NEW; | 121 | device->target = DASD_STATE_NEW; |
| 120 | mutex_init(&device->state_mutex); | 122 | mutex_init(&device->state_mutex); |
| @@ -521,6 +523,26 @@ void dasd_kick_device(struct dasd_device *device) | |||
| 521 | } | 523 | } |
| 522 | 524 | ||
| 523 | /* | 525 | /* |
| 526 | * dasd_reload_device will schedule a call do do_reload_device to the kernel | ||
| 527 | * event daemon. | ||
| 528 | */ | ||
| 529 | static void do_reload_device(struct work_struct *work) | ||
| 530 | { | ||
| 531 | struct dasd_device *device = container_of(work, struct dasd_device, | ||
| 532 | reload_device); | ||
| 533 | device->discipline->reload(device); | ||
| 534 | dasd_put_device(device); | ||
| 535 | } | ||
| 536 | |||
| 537 | void dasd_reload_device(struct dasd_device *device) | ||
| 538 | { | ||
| 539 | dasd_get_device(device); | ||
| 540 | /* queue call to dasd_reload_device to the kernel event daemon. */ | ||
| 541 | schedule_work(&device->reload_device); | ||
| 542 | } | ||
| 543 | EXPORT_SYMBOL(dasd_reload_device); | ||
| 544 | |||
| 545 | /* | ||
| 524 | * dasd_restore_device will schedule a call do do_restore_device to the kernel | 546 | * dasd_restore_device will schedule a call do do_restore_device to the kernel |
| 525 | * event daemon. | 547 | * event daemon. |
| 526 | */ | 548 | */ |
diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c index 6632649dd6aa..85bfd8794856 100644 --- a/drivers/s390/block/dasd_3990_erp.c +++ b/drivers/s390/block/dasd_3990_erp.c | |||
| @@ -1418,9 +1418,29 @@ static struct dasd_ccw_req *dasd_3990_erp_inspect_alias( | |||
| 1418 | struct dasd_ccw_req *erp) | 1418 | struct dasd_ccw_req *erp) |
| 1419 | { | 1419 | { |
| 1420 | struct dasd_ccw_req *cqr = erp->refers; | 1420 | struct dasd_ccw_req *cqr = erp->refers; |
| 1421 | char *sense; | ||
| 1421 | 1422 | ||
| 1422 | if (cqr->block && | 1423 | if (cqr->block && |
| 1423 | (cqr->block->base != cqr->startdev)) { | 1424 | (cqr->block->base != cqr->startdev)) { |
| 1425 | |||
| 1426 | sense = dasd_get_sense(&erp->refers->irb); | ||
| 1427 | /* | ||
| 1428 | * dynamic pav may have changed base alias mapping | ||
| 1429 | */ | ||
| 1430 | if (!test_bit(DASD_FLAG_OFFLINE, &cqr->startdev->flags) && sense | ||
| 1431 | && (sense[0] == 0x10) && (sense[7] == 0x0F) | ||
| 1432 | && (sense[8] == 0x67)) { | ||
| 1433 | /* | ||
| 1434 | * remove device from alias handling to prevent new | ||
| 1435 | * requests from being scheduled on the | ||
| 1436 | * wrong alias device | ||
| 1437 | */ | ||
| 1438 | dasd_alias_remove_device(cqr->startdev); | ||
| 1439 | |||
| 1440 | /* schedule worker to reload device */ | ||
| 1441 | dasd_reload_device(cqr->startdev); | ||
| 1442 | } | ||
| 1443 | |||
| 1424 | if (cqr->startdev->features & DASD_FEATURE_ERPLOG) { | 1444 | if (cqr->startdev->features & DASD_FEATURE_ERPLOG) { |
| 1425 | DBF_DEV_EVENT(DBF_ERR, cqr->startdev, | 1445 | DBF_DEV_EVENT(DBF_ERR, cqr->startdev, |
| 1426 | "ERP on alias device for request %p," | 1446 | "ERP on alias device for request %p," |
diff --git a/drivers/s390/block/dasd_alias.c b/drivers/s390/block/dasd_alias.c index 8c4814258e93..4155805dcdff 100644 --- a/drivers/s390/block/dasd_alias.c +++ b/drivers/s390/block/dasd_alias.c | |||
| @@ -190,20 +190,21 @@ int dasd_alias_make_device_known_to_lcu(struct dasd_device *device) | |||
| 190 | struct alias_server *server, *newserver; | 190 | struct alias_server *server, *newserver; |
| 191 | struct alias_lcu *lcu, *newlcu; | 191 | struct alias_lcu *lcu, *newlcu; |
| 192 | int is_lcu_known; | 192 | int is_lcu_known; |
| 193 | struct dasd_uid *uid; | 193 | struct dasd_uid uid; |
| 194 | 194 | ||
| 195 | private = (struct dasd_eckd_private *) device->private; | 195 | private = (struct dasd_eckd_private *) device->private; |
| 196 | uid = &private->uid; | 196 | |
| 197 | device->discipline->get_uid(device, &uid); | ||
| 197 | spin_lock_irqsave(&aliastree.lock, flags); | 198 | spin_lock_irqsave(&aliastree.lock, flags); |
| 198 | is_lcu_known = 1; | 199 | is_lcu_known = 1; |
| 199 | server = _find_server(uid); | 200 | server = _find_server(&uid); |
| 200 | if (!server) { | 201 | if (!server) { |
| 201 | spin_unlock_irqrestore(&aliastree.lock, flags); | 202 | spin_unlock_irqrestore(&aliastree.lock, flags); |
| 202 | newserver = _allocate_server(uid); | 203 | newserver = _allocate_server(&uid); |
| 203 | if (IS_ERR(newserver)) | 204 | if (IS_ERR(newserver)) |
| 204 | return PTR_ERR(newserver); | 205 | return PTR_ERR(newserver); |
| 205 | spin_lock_irqsave(&aliastree.lock, flags); | 206 | spin_lock_irqsave(&aliastree.lock, flags); |
| 206 | server = _find_server(uid); | 207 | server = _find_server(&uid); |
| 207 | if (!server) { | 208 | if (!server) { |
| 208 | list_add(&newserver->server, &aliastree.serverlist); | 209 | list_add(&newserver->server, &aliastree.serverlist); |
| 209 | server = newserver; | 210 | server = newserver; |
| @@ -214,14 +215,14 @@ int dasd_alias_make_device_known_to_lcu(struct dasd_device *device) | |||
| 214 | } | 215 | } |
| 215 | } | 216 | } |
| 216 | 217 | ||
| 217 | lcu = _find_lcu(server, uid); | 218 | lcu = _find_lcu(server, &uid); |
| 218 | if (!lcu) { | 219 | if (!lcu) { |
| 219 | spin_unlock_irqrestore(&aliastree.lock, flags); | 220 | spin_unlock_irqrestore(&aliastree.lock, flags); |
| 220 | newlcu = _allocate_lcu(uid); | 221 | newlcu = _allocate_lcu(&uid); |
| 221 | if (IS_ERR(newlcu)) | 222 | if (IS_ERR(newlcu)) |
| 222 | return PTR_ERR(newlcu); | 223 | return PTR_ERR(newlcu); |
| 223 | spin_lock_irqsave(&aliastree.lock, flags); | 224 | spin_lock_irqsave(&aliastree.lock, flags); |
| 224 | lcu = _find_lcu(server, uid); | 225 | lcu = _find_lcu(server, &uid); |
| 225 | if (!lcu) { | 226 | if (!lcu) { |
| 226 | list_add(&newlcu->lcu, &server->lculist); | 227 | list_add(&newlcu->lcu, &server->lculist); |
| 227 | lcu = newlcu; | 228 | lcu = newlcu; |
| @@ -256,20 +257,20 @@ void dasd_alias_lcu_setup_complete(struct dasd_device *device) | |||
| 256 | unsigned long flags; | 257 | unsigned long flags; |
| 257 | struct alias_server *server; | 258 | struct alias_server *server; |
| 258 | struct alias_lcu *lcu; | 259 | struct alias_lcu *lcu; |
| 259 | struct dasd_uid *uid; | 260 | struct dasd_uid uid; |
| 260 | 261 | ||
| 261 | private = (struct dasd_eckd_private *) device->private; | 262 | private = (struct dasd_eckd_private *) device->private; |
| 262 | uid = &private->uid; | 263 | device->discipline->get_uid(device, &uid); |
| 263 | lcu = NULL; | 264 | lcu = NULL; |
| 264 | spin_lock_irqsave(&aliastree.lock, flags); | 265 | spin_lock_irqsave(&aliastree.lock, flags); |
| 265 | server = _find_server(uid); | 266 | server = _find_server(&uid); |
| 266 | if (server) | 267 | if (server) |
| 267 | lcu = _find_lcu(server, uid); | 268 | lcu = _find_lcu(server, &uid); |
| 268 | spin_unlock_irqrestore(&aliastree.lock, flags); | 269 | spin_unlock_irqrestore(&aliastree.lock, flags); |
| 269 | if (!lcu) { | 270 | if (!lcu) { |
| 270 | DBF_EVENT_DEVID(DBF_ERR, device->cdev, | 271 | DBF_EVENT_DEVID(DBF_ERR, device->cdev, |
| 271 | "could not find lcu for %04x %02x", | 272 | "could not find lcu for %04x %02x", |
| 272 | uid->ssid, uid->real_unit_addr); | 273 | uid.ssid, uid.real_unit_addr); |
| 273 | WARN_ON(1); | 274 | WARN_ON(1); |
| 274 | return; | 275 | return; |
| 275 | } | 276 | } |
| @@ -282,20 +283,20 @@ void dasd_alias_wait_for_lcu_setup(struct dasd_device *device) | |||
| 282 | unsigned long flags; | 283 | unsigned long flags; |
| 283 | struct alias_server *server; | 284 | struct alias_server *server; |
| 284 | struct alias_lcu *lcu; | 285 | struct alias_lcu *lcu; |
| 285 | struct dasd_uid *uid; | 286 | struct dasd_uid uid; |
| 286 | 287 | ||
| 287 | private = (struct dasd_eckd_private *) device->private; | 288 | private = (struct dasd_eckd_private *) device->private; |
| 288 | uid = &private->uid; | 289 | device->discipline->get_uid(device, &uid); |
| 289 | lcu = NULL; | 290 | lcu = NULL; |
| 290 | spin_lock_irqsave(&aliastree.lock, flags); | 291 | spin_lock_irqsave(&aliastree.lock, flags); |
| 291 | server = _find_server(uid); | 292 | server = _find_server(&uid); |
| 292 | if (server) | 293 | if (server) |
| 293 | lcu = _find_lcu(server, uid); | 294 | lcu = _find_lcu(server, &uid); |
| 294 | spin_unlock_irqrestore(&aliastree.lock, flags); | 295 | spin_unlock_irqrestore(&aliastree.lock, flags); |
| 295 | if (!lcu) { | 296 | if (!lcu) { |
| 296 | DBF_EVENT_DEVID(DBF_ERR, device->cdev, | 297 | DBF_EVENT_DEVID(DBF_ERR, device->cdev, |
| 297 | "could not find lcu for %04x %02x", | 298 | "could not find lcu for %04x %02x", |
| 298 | uid->ssid, uid->real_unit_addr); | 299 | uid.ssid, uid.real_unit_addr); |
| 299 | WARN_ON(1); | 300 | WARN_ON(1); |
| 300 | return; | 301 | return; |
| 301 | } | 302 | } |
| @@ -314,9 +315,11 @@ void dasd_alias_disconnect_device_from_lcu(struct dasd_device *device) | |||
| 314 | struct alias_lcu *lcu; | 315 | struct alias_lcu *lcu; |
| 315 | struct alias_server *server; | 316 | struct alias_server *server; |
| 316 | int was_pending; | 317 | int was_pending; |
| 318 | struct dasd_uid uid; | ||
| 317 | 319 | ||
| 318 | private = (struct dasd_eckd_private *) device->private; | 320 | private = (struct dasd_eckd_private *) device->private; |
| 319 | lcu = private->lcu; | 321 | lcu = private->lcu; |
| 322 | device->discipline->get_uid(device, &uid); | ||
| 320 | spin_lock_irqsave(&lcu->lock, flags); | 323 | spin_lock_irqsave(&lcu->lock, flags); |
| 321 | list_del_init(&device->alias_list); | 324 | list_del_init(&device->alias_list); |
| 322 | /* make sure that the workers don't use this device */ | 325 | /* make sure that the workers don't use this device */ |
| @@ -353,7 +356,7 @@ void dasd_alias_disconnect_device_from_lcu(struct dasd_device *device) | |||
| 353 | _schedule_lcu_update(lcu, NULL); | 356 | _schedule_lcu_update(lcu, NULL); |
| 354 | spin_unlock(&lcu->lock); | 357 | spin_unlock(&lcu->lock); |
| 355 | } | 358 | } |
| 356 | server = _find_server(&private->uid); | 359 | server = _find_server(&uid); |
| 357 | if (server && list_empty(&server->lculist)) { | 360 | if (server && list_empty(&server->lculist)) { |
| 358 | list_del(&server->server); | 361 | list_del(&server->server); |
| 359 | _free_server(server); | 362 | _free_server(server); |
| @@ -366,19 +369,30 @@ void dasd_alias_disconnect_device_from_lcu(struct dasd_device *device) | |||
| 366 | * in the lcu is up to date and will update the device uid before | 369 | * in the lcu is up to date and will update the device uid before |
| 367 | * adding it to a pav group. | 370 | * adding it to a pav group. |
| 368 | */ | 371 | */ |
| 372 | |||
| 369 | static int _add_device_to_lcu(struct alias_lcu *lcu, | 373 | static int _add_device_to_lcu(struct alias_lcu *lcu, |
| 370 | struct dasd_device *device) | 374 | struct dasd_device *device, |
| 375 | struct dasd_device *pos) | ||
| 371 | { | 376 | { |
| 372 | 377 | ||
| 373 | struct dasd_eckd_private *private; | 378 | struct dasd_eckd_private *private; |
| 374 | struct alias_pav_group *group; | 379 | struct alias_pav_group *group; |
| 375 | struct dasd_uid *uid; | 380 | struct dasd_uid uid; |
| 381 | unsigned long flags; | ||
| 376 | 382 | ||
| 377 | private = (struct dasd_eckd_private *) device->private; | 383 | private = (struct dasd_eckd_private *) device->private; |
| 378 | uid = &private->uid; | 384 | |
| 379 | uid->type = lcu->uac->unit[uid->real_unit_addr].ua_type; | 385 | /* only lock if not already locked */ |
| 380 | uid->base_unit_addr = lcu->uac->unit[uid->real_unit_addr].base_ua; | 386 | if (device != pos) |
| 381 | dasd_set_uid(device->cdev, &private->uid); | 387 | spin_lock_irqsave_nested(get_ccwdev_lock(device->cdev), flags, |
| 388 | CDEV_NESTED_SECOND); | ||
| 389 | private->uid.type = lcu->uac->unit[private->uid.real_unit_addr].ua_type; | ||
| 390 | private->uid.base_unit_addr = | ||
| 391 | lcu->uac->unit[private->uid.real_unit_addr].base_ua; | ||
| 392 | uid = private->uid; | ||
| 393 | |||
| 394 | if (device != pos) | ||
| 395 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); | ||
| 382 | 396 | ||
| 383 | /* if we have no PAV anyway, we don't need to bother with PAV groups */ | 397 | /* if we have no PAV anyway, we don't need to bother with PAV groups */ |
| 384 | if (lcu->pav == NO_PAV) { | 398 | if (lcu->pav == NO_PAV) { |
| @@ -386,25 +400,25 @@ static int _add_device_to_lcu(struct alias_lcu *lcu, | |||
| 386 | return 0; | 400 | return 0; |
| 387 | } | 401 | } |
| 388 | 402 | ||
| 389 | group = _find_group(lcu, uid); | 403 | group = _find_group(lcu, &uid); |
| 390 | if (!group) { | 404 | if (!group) { |
| 391 | group = kzalloc(sizeof(*group), GFP_ATOMIC); | 405 | group = kzalloc(sizeof(*group), GFP_ATOMIC); |
| 392 | if (!group) | 406 | if (!group) |
| 393 | return -ENOMEM; | 407 | return -ENOMEM; |
| 394 | memcpy(group->uid.vendor, uid->vendor, sizeof(uid->vendor)); | 408 | memcpy(group->uid.vendor, uid.vendor, sizeof(uid.vendor)); |
| 395 | memcpy(group->uid.serial, uid->serial, sizeof(uid->serial)); | 409 | memcpy(group->uid.serial, uid.serial, sizeof(uid.serial)); |
| 396 | group->uid.ssid = uid->ssid; | 410 | group->uid.ssid = uid.ssid; |
| 397 | if (uid->type == UA_BASE_DEVICE) | 411 | if (uid.type == UA_BASE_DEVICE) |
| 398 | group->uid.base_unit_addr = uid->real_unit_addr; | 412 | group->uid.base_unit_addr = uid.real_unit_addr; |
| 399 | else | 413 | else |
| 400 | group->uid.base_unit_addr = uid->base_unit_addr; | 414 | group->uid.base_unit_addr = uid.base_unit_addr; |
| 401 | memcpy(group->uid.vduit, uid->vduit, sizeof(uid->vduit)); | 415 | memcpy(group->uid.vduit, uid.vduit, sizeof(uid.vduit)); |
| 402 | INIT_LIST_HEAD(&group->group); | 416 | INIT_LIST_HEAD(&group->group); |
| 403 | INIT_LIST_HEAD(&group->baselist); | 417 | INIT_LIST_HEAD(&group->baselist); |
| 404 | INIT_LIST_HEAD(&group->aliaslist); | 418 | INIT_LIST_HEAD(&group->aliaslist); |
| 405 | list_add(&group->group, &lcu->grouplist); | 419 | list_add(&group->group, &lcu->grouplist); |
| 406 | } | 420 | } |
| 407 | if (uid->type == UA_BASE_DEVICE) | 421 | if (uid.type == UA_BASE_DEVICE) |
| 408 | list_move(&device->alias_list, &group->baselist); | 422 | list_move(&device->alias_list, &group->baselist); |
| 409 | else | 423 | else |
| 410 | list_move(&device->alias_list, &group->aliaslist); | 424 | list_move(&device->alias_list, &group->aliaslist); |
| @@ -525,7 +539,10 @@ static int _lcu_update(struct dasd_device *refdev, struct alias_lcu *lcu) | |||
| 525 | if (rc) | 539 | if (rc) |
| 526 | return rc; | 540 | return rc; |
| 527 | 541 | ||
| 528 | spin_lock_irqsave(&lcu->lock, flags); | 542 | /* need to take cdev lock before lcu lock */ |
| 543 | spin_lock_irqsave_nested(get_ccwdev_lock(refdev->cdev), flags, | ||
| 544 | CDEV_NESTED_FIRST); | ||
| 545 | spin_lock(&lcu->lock); | ||
| 529 | lcu->pav = NO_PAV; | 546 | lcu->pav = NO_PAV; |
| 530 | for (i = 0; i < MAX_DEVICES_PER_LCU; ++i) { | 547 | for (i = 0; i < MAX_DEVICES_PER_LCU; ++i) { |
| 531 | switch (lcu->uac->unit[i].ua_type) { | 548 | switch (lcu->uac->unit[i].ua_type) { |
| @@ -542,9 +559,10 @@ static int _lcu_update(struct dasd_device *refdev, struct alias_lcu *lcu) | |||
| 542 | 559 | ||
| 543 | list_for_each_entry_safe(device, tempdev, &lcu->active_devices, | 560 | list_for_each_entry_safe(device, tempdev, &lcu->active_devices, |
| 544 | alias_list) { | 561 | alias_list) { |
| 545 | _add_device_to_lcu(lcu, device); | 562 | _add_device_to_lcu(lcu, device, refdev); |
| 546 | } | 563 | } |
| 547 | spin_unlock_irqrestore(&lcu->lock, flags); | 564 | spin_unlock(&lcu->lock); |
| 565 | spin_unlock_irqrestore(get_ccwdev_lock(refdev->cdev), flags); | ||
| 548 | return 0; | 566 | return 0; |
| 549 | } | 567 | } |
| 550 | 568 | ||
| @@ -628,9 +646,12 @@ int dasd_alias_add_device(struct dasd_device *device) | |||
| 628 | private = (struct dasd_eckd_private *) device->private; | 646 | private = (struct dasd_eckd_private *) device->private; |
| 629 | lcu = private->lcu; | 647 | lcu = private->lcu; |
| 630 | rc = 0; | 648 | rc = 0; |
| 631 | spin_lock_irqsave(&lcu->lock, flags); | 649 | |
| 650 | /* need to take cdev lock before lcu lock */ | ||
| 651 | spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); | ||
| 652 | spin_lock(&lcu->lock); | ||
| 632 | if (!(lcu->flags & UPDATE_PENDING)) { | 653 | if (!(lcu->flags & UPDATE_PENDING)) { |
| 633 | rc = _add_device_to_lcu(lcu, device); | 654 | rc = _add_device_to_lcu(lcu, device, device); |
| 634 | if (rc) | 655 | if (rc) |
| 635 | lcu->flags |= UPDATE_PENDING; | 656 | lcu->flags |= UPDATE_PENDING; |
| 636 | } | 657 | } |
| @@ -638,10 +659,19 @@ int dasd_alias_add_device(struct dasd_device *device) | |||
| 638 | list_move(&device->alias_list, &lcu->active_devices); | 659 | list_move(&device->alias_list, &lcu->active_devices); |
| 639 | _schedule_lcu_update(lcu, device); | 660 | _schedule_lcu_update(lcu, device); |
| 640 | } | 661 | } |
| 641 | spin_unlock_irqrestore(&lcu->lock, flags); | 662 | spin_unlock(&lcu->lock); |
| 663 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); | ||
| 642 | return rc; | 664 | return rc; |
| 643 | } | 665 | } |
| 644 | 666 | ||
| 667 | int dasd_alias_update_add_device(struct dasd_device *device) | ||
| 668 | { | ||
| 669 | struct dasd_eckd_private *private; | ||
| 670 | private = (struct dasd_eckd_private *) device->private; | ||
| 671 | private->lcu->flags |= UPDATE_PENDING; | ||
| 672 | return dasd_alias_add_device(device); | ||
| 673 | } | ||
| 674 | |||
| 645 | int dasd_alias_remove_device(struct dasd_device *device) | 675 | int dasd_alias_remove_device(struct dasd_device *device) |
| 646 | { | 676 | { |
| 647 | struct dasd_eckd_private *private; | 677 | struct dasd_eckd_private *private; |
| @@ -740,19 +770,30 @@ static void _restart_all_base_devices_on_lcu(struct alias_lcu *lcu) | |||
| 740 | struct alias_pav_group *pavgroup; | 770 | struct alias_pav_group *pavgroup; |
| 741 | struct dasd_device *device; | 771 | struct dasd_device *device; |
| 742 | struct dasd_eckd_private *private; | 772 | struct dasd_eckd_private *private; |
| 773 | unsigned long flags; | ||
| 743 | 774 | ||
| 744 | /* active and inactive list can contain alias as well as base devices */ | 775 | /* active and inactive list can contain alias as well as base devices */ |
| 745 | list_for_each_entry(device, &lcu->active_devices, alias_list) { | 776 | list_for_each_entry(device, &lcu->active_devices, alias_list) { |
| 746 | private = (struct dasd_eckd_private *) device->private; | 777 | private = (struct dasd_eckd_private *) device->private; |
| 747 | if (private->uid.type != UA_BASE_DEVICE) | 778 | spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); |
| 779 | if (private->uid.type != UA_BASE_DEVICE) { | ||
| 780 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), | ||
| 781 | flags); | ||
| 748 | continue; | 782 | continue; |
| 783 | } | ||
| 784 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); | ||
| 749 | dasd_schedule_block_bh(device->block); | 785 | dasd_schedule_block_bh(device->block); |
| 750 | dasd_schedule_device_bh(device); | 786 | dasd_schedule_device_bh(device); |
| 751 | } | 787 | } |
| 752 | list_for_each_entry(device, &lcu->inactive_devices, alias_list) { | 788 | list_for_each_entry(device, &lcu->inactive_devices, alias_list) { |
| 753 | private = (struct dasd_eckd_private *) device->private; | 789 | private = (struct dasd_eckd_private *) device->private; |
| 754 | if (private->uid.type != UA_BASE_DEVICE) | 790 | spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); |
| 791 | if (private->uid.type != UA_BASE_DEVICE) { | ||
| 792 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), | ||
| 793 | flags); | ||
| 755 | continue; | 794 | continue; |
| 795 | } | ||
| 796 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); | ||
| 756 | dasd_schedule_block_bh(device->block); | 797 | dasd_schedule_block_bh(device->block); |
| 757 | dasd_schedule_device_bh(device); | 798 | dasd_schedule_device_bh(device); |
| 758 | } | 799 | } |
diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index eff9c812c5c2..34d51dd4c539 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c | |||
| @@ -49,7 +49,6 @@ struct dasd_devmap { | |||
| 49 | unsigned int devindex; | 49 | unsigned int devindex; |
| 50 | unsigned short features; | 50 | unsigned short features; |
| 51 | struct dasd_device *device; | 51 | struct dasd_device *device; |
| 52 | struct dasd_uid uid; | ||
| 53 | }; | 52 | }; |
| 54 | 53 | ||
| 55 | /* | 54 | /* |
| @@ -936,42 +935,46 @@ dasd_device_status_show(struct device *dev, struct device_attribute *attr, | |||
| 936 | 935 | ||
| 937 | static DEVICE_ATTR(status, 0444, dasd_device_status_show, NULL); | 936 | static DEVICE_ATTR(status, 0444, dasd_device_status_show, NULL); |
| 938 | 937 | ||
| 939 | static ssize_t | 938 | static ssize_t dasd_alias_show(struct device *dev, |
| 940 | dasd_alias_show(struct device *dev, struct device_attribute *attr, char *buf) | 939 | struct device_attribute *attr, char *buf) |
| 941 | { | 940 | { |
| 942 | struct dasd_devmap *devmap; | 941 | struct dasd_device *device; |
| 943 | int alias; | 942 | struct dasd_uid uid; |
| 944 | 943 | ||
| 945 | devmap = dasd_find_busid(dev_name(dev)); | 944 | device = dasd_device_from_cdev(to_ccwdev(dev)); |
| 946 | spin_lock(&dasd_devmap_lock); | 945 | if (IS_ERR(device)) |
| 947 | if (IS_ERR(devmap) || strlen(devmap->uid.vendor) == 0) { | ||
| 948 | spin_unlock(&dasd_devmap_lock); | ||
| 949 | return sprintf(buf, "0\n"); | 946 | return sprintf(buf, "0\n"); |
| 947 | |||
| 948 | if (device->discipline && device->discipline->get_uid && | ||
| 949 | !device->discipline->get_uid(device, &uid)) { | ||
| 950 | if (uid.type == UA_BASE_PAV_ALIAS || | ||
| 951 | uid.type == UA_HYPER_PAV_ALIAS) | ||
| 952 | return sprintf(buf, "1\n"); | ||
| 950 | } | 953 | } |
| 951 | if (devmap->uid.type == UA_BASE_PAV_ALIAS || | 954 | dasd_put_device(device); |
| 952 | devmap->uid.type == UA_HYPER_PAV_ALIAS) | 955 | |
| 953 | alias = 1; | 956 | return sprintf(buf, "0\n"); |
| 954 | else | ||
| 955 | alias = 0; | ||
| 956 | spin_unlock(&dasd_devmap_lock); | ||
| 957 | return sprintf(buf, alias ? "1\n" : "0\n"); | ||
| 958 | } | 957 | } |
| 959 | 958 | ||
| 960 | static DEVICE_ATTR(alias, 0444, dasd_alias_show, NULL); | 959 | static DEVICE_ATTR(alias, 0444, dasd_alias_show, NULL); |
| 961 | 960 | ||
| 962 | static ssize_t | 961 | static ssize_t dasd_vendor_show(struct device *dev, |
| 963 | dasd_vendor_show(struct device *dev, struct device_attribute *attr, char *buf) | 962 | struct device_attribute *attr, char *buf) |
| 964 | { | 963 | { |
| 965 | struct dasd_devmap *devmap; | 964 | struct dasd_device *device; |
| 965 | struct dasd_uid uid; | ||
| 966 | char *vendor; | 966 | char *vendor; |
| 967 | 967 | ||
| 968 | devmap = dasd_find_busid(dev_name(dev)); | 968 | device = dasd_device_from_cdev(to_ccwdev(dev)); |
| 969 | spin_lock(&dasd_devmap_lock); | 969 | vendor = ""; |
| 970 | if (!IS_ERR(devmap) && strlen(devmap->uid.vendor) > 0) | 970 | if (IS_ERR(device)) |
| 971 | vendor = devmap->uid.vendor; | 971 | return snprintf(buf, PAGE_SIZE, "%s\n", vendor); |
| 972 | else | 972 | |
| 973 | vendor = ""; | 973 | if (device->discipline && device->discipline->get_uid && |
| 974 | spin_unlock(&dasd_devmap_lock); | 974 | !device->discipline->get_uid(device, &uid)) |
| 975 | vendor = uid.vendor; | ||
| 976 | |||
| 977 | dasd_put_device(device); | ||
| 975 | 978 | ||
| 976 | return snprintf(buf, PAGE_SIZE, "%s\n", vendor); | 979 | return snprintf(buf, PAGE_SIZE, "%s\n", vendor); |
| 977 | } | 980 | } |
| @@ -985,48 +988,51 @@ static DEVICE_ATTR(vendor, 0444, dasd_vendor_show, NULL); | |||
| 985 | static ssize_t | 988 | static ssize_t |
| 986 | dasd_uid_show(struct device *dev, struct device_attribute *attr, char *buf) | 989 | dasd_uid_show(struct device *dev, struct device_attribute *attr, char *buf) |
| 987 | { | 990 | { |
| 988 | struct dasd_devmap *devmap; | 991 | struct dasd_device *device; |
| 992 | struct dasd_uid uid; | ||
| 989 | char uid_string[UID_STRLEN]; | 993 | char uid_string[UID_STRLEN]; |
| 990 | char ua_string[3]; | 994 | char ua_string[3]; |
| 991 | struct dasd_uid *uid; | ||
| 992 | 995 | ||
| 993 | devmap = dasd_find_busid(dev_name(dev)); | 996 | device = dasd_device_from_cdev(to_ccwdev(dev)); |
| 994 | spin_lock(&dasd_devmap_lock); | 997 | uid_string[0] = 0; |
| 995 | if (IS_ERR(devmap) || strlen(devmap->uid.vendor) == 0) { | 998 | if (IS_ERR(device)) |
| 996 | spin_unlock(&dasd_devmap_lock); | 999 | return snprintf(buf, PAGE_SIZE, "%s\n", uid_string); |
| 997 | return sprintf(buf, "\n"); | 1000 | |
| 998 | } | 1001 | if (device->discipline && device->discipline->get_uid && |
| 999 | uid = &devmap->uid; | 1002 | !device->discipline->get_uid(device, &uid)) { |
| 1000 | switch (uid->type) { | 1003 | switch (uid.type) { |
| 1001 | case UA_BASE_DEVICE: | 1004 | case UA_BASE_DEVICE: |
| 1002 | sprintf(ua_string, "%02x", uid->real_unit_addr); | 1005 | snprintf(ua_string, sizeof(ua_string), "%02x", |
| 1003 | break; | 1006 | uid.real_unit_addr); |
| 1004 | case UA_BASE_PAV_ALIAS: | 1007 | break; |
| 1005 | sprintf(ua_string, "%02x", uid->base_unit_addr); | 1008 | case UA_BASE_PAV_ALIAS: |
| 1006 | break; | 1009 | snprintf(ua_string, sizeof(ua_string), "%02x", |
| 1007 | case UA_HYPER_PAV_ALIAS: | 1010 | uid.base_unit_addr); |
| 1008 | sprintf(ua_string, "xx"); | 1011 | break; |
| 1009 | break; | 1012 | case UA_HYPER_PAV_ALIAS: |
| 1010 | default: | 1013 | snprintf(ua_string, sizeof(ua_string), "xx"); |
| 1011 | /* should not happen, treat like base device */ | 1014 | break; |
| 1012 | sprintf(ua_string, "%02x", uid->real_unit_addr); | 1015 | default: |
| 1013 | break; | 1016 | /* should not happen, treat like base device */ |
| 1017 | snprintf(ua_string, sizeof(ua_string), "%02x", | ||
| 1018 | uid.real_unit_addr); | ||
| 1019 | break; | ||
| 1020 | } | ||
| 1021 | |||
| 1022 | if (strlen(uid.vduit) > 0) | ||
| 1023 | snprintf(uid_string, sizeof(uid_string), | ||
| 1024 | "%s.%s.%04x.%s.%s", | ||
| 1025 | uid.vendor, uid.serial, uid.ssid, ua_string, | ||
| 1026 | uid.vduit); | ||
| 1027 | else | ||
| 1028 | snprintf(uid_string, sizeof(uid_string), | ||
| 1029 | "%s.%s.%04x.%s", | ||
| 1030 | uid.vendor, uid.serial, uid.ssid, ua_string); | ||
| 1014 | } | 1031 | } |
| 1015 | if (strlen(uid->vduit) > 0) | 1032 | dasd_put_device(device); |
| 1016 | snprintf(uid_string, sizeof(uid_string), | 1033 | |
| 1017 | "%s.%s.%04x.%s.%s", | ||
| 1018 | uid->vendor, uid->serial, | ||
| 1019 | uid->ssid, ua_string, | ||
| 1020 | uid->vduit); | ||
| 1021 | else | ||
| 1022 | snprintf(uid_string, sizeof(uid_string), | ||
| 1023 | "%s.%s.%04x.%s", | ||
| 1024 | uid->vendor, uid->serial, | ||
| 1025 | uid->ssid, ua_string); | ||
| 1026 | spin_unlock(&dasd_devmap_lock); | ||
| 1027 | return snprintf(buf, PAGE_SIZE, "%s\n", uid_string); | 1034 | return snprintf(buf, PAGE_SIZE, "%s\n", uid_string); |
| 1028 | } | 1035 | } |
| 1029 | |||
| 1030 | static DEVICE_ATTR(uid, 0444, dasd_uid_show, NULL); | 1036 | static DEVICE_ATTR(uid, 0444, dasd_uid_show, NULL); |
| 1031 | 1037 | ||
| 1032 | /* | 1038 | /* |
| @@ -1094,50 +1100,6 @@ static struct attribute_group dasd_attr_group = { | |||
| 1094 | }; | 1100 | }; |
| 1095 | 1101 | ||
| 1096 | /* | 1102 | /* |
| 1097 | * Return copy of the device unique identifier. | ||
| 1098 | */ | ||
| 1099 | int | ||
| 1100 | dasd_get_uid(struct ccw_device *cdev, struct dasd_uid *uid) | ||
| 1101 | { | ||
| 1102 | struct dasd_devmap *devmap; | ||
| 1103 | |||
| 1104 | devmap = dasd_find_busid(dev_name(&cdev->dev)); | ||
| 1105 | if (IS_ERR(devmap)) | ||
| 1106 | return PTR_ERR(devmap); | ||
| 1107 | spin_lock(&dasd_devmap_lock); | ||
| 1108 | *uid = devmap->uid; | ||
| 1109 | spin_unlock(&dasd_devmap_lock); | ||
| 1110 | return 0; | ||
| 1111 | } | ||
| 1112 | EXPORT_SYMBOL_GPL(dasd_get_uid); | ||
| 1113 | |||
| 1114 | /* | ||
| 1115 | * Register the given device unique identifier into devmap struct. | ||
| 1116 | * In addition check if the related storage server subsystem ID is already | ||
| 1117 | * contained in the dasd_server_ssid_list. If subsystem ID is not contained, | ||
| 1118 | * create new entry. | ||
| 1119 | * Return 0 if server was already in serverlist, | ||
| 1120 | * 1 if the server was added successful | ||
| 1121 | * <0 in case of error. | ||
| 1122 | */ | ||
| 1123 | int | ||
| 1124 | dasd_set_uid(struct ccw_device *cdev, struct dasd_uid *uid) | ||
| 1125 | { | ||
| 1126 | struct dasd_devmap *devmap; | ||
| 1127 | |||
| 1128 | devmap = dasd_find_busid(dev_name(&cdev->dev)); | ||
| 1129 | if (IS_ERR(devmap)) | ||
| 1130 | return PTR_ERR(devmap); | ||
| 1131 | |||
| 1132 | spin_lock(&dasd_devmap_lock); | ||
| 1133 | devmap->uid = *uid; | ||
| 1134 | spin_unlock(&dasd_devmap_lock); | ||
| 1135 | |||
| 1136 | return 0; | ||
| 1137 | } | ||
| 1138 | EXPORT_SYMBOL_GPL(dasd_set_uid); | ||
| 1139 | |||
| 1140 | /* | ||
| 1141 | * Return value of the specified feature. | 1103 | * Return value of the specified feature. |
| 1142 | */ | 1104 | */ |
| 1143 | int | 1105 | int |
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 0cb233116855..5b1cd8d6e971 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c | |||
| @@ -692,18 +692,20 @@ dasd_eckd_cdl_reclen(int recid) | |||
| 692 | /* | 692 | /* |
| 693 | * Generate device unique id that specifies the physical device. | 693 | * Generate device unique id that specifies the physical device. |
| 694 | */ | 694 | */ |
| 695 | static int dasd_eckd_generate_uid(struct dasd_device *device, | 695 | static int dasd_eckd_generate_uid(struct dasd_device *device) |
| 696 | struct dasd_uid *uid) | ||
| 697 | { | 696 | { |
| 698 | struct dasd_eckd_private *private; | 697 | struct dasd_eckd_private *private; |
| 698 | struct dasd_uid *uid; | ||
| 699 | int count; | 699 | int count; |
| 700 | unsigned long flags; | ||
| 700 | 701 | ||
| 701 | private = (struct dasd_eckd_private *) device->private; | 702 | private = (struct dasd_eckd_private *) device->private; |
| 702 | if (!private) | 703 | if (!private) |
| 703 | return -ENODEV; | 704 | return -ENODEV; |
| 704 | if (!private->ned || !private->gneq) | 705 | if (!private->ned || !private->gneq) |
| 705 | return -ENODEV; | 706 | return -ENODEV; |
| 706 | 707 | uid = &private->uid; | |
| 708 | spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); | ||
| 707 | memset(uid, 0, sizeof(struct dasd_uid)); | 709 | memset(uid, 0, sizeof(struct dasd_uid)); |
| 708 | memcpy(uid->vendor, private->ned->HDA_manufacturer, | 710 | memcpy(uid->vendor, private->ned->HDA_manufacturer, |
| 709 | sizeof(uid->vendor) - 1); | 711 | sizeof(uid->vendor) - 1); |
| @@ -726,9 +728,25 @@ static int dasd_eckd_generate_uid(struct dasd_device *device, | |||
| 726 | private->vdsneq->uit[count]); | 728 | private->vdsneq->uit[count]); |
| 727 | } | 729 | } |
| 728 | } | 730 | } |
| 731 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); | ||
| 729 | return 0; | 732 | return 0; |
| 730 | } | 733 | } |
| 731 | 734 | ||
| 735 | static int dasd_eckd_get_uid(struct dasd_device *device, struct dasd_uid *uid) | ||
| 736 | { | ||
| 737 | struct dasd_eckd_private *private; | ||
| 738 | unsigned long flags; | ||
| 739 | |||
| 740 | if (device->private) { | ||
| 741 | private = (struct dasd_eckd_private *)device->private; | ||
| 742 | spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); | ||
| 743 | *uid = private->uid; | ||
| 744 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); | ||
| 745 | return 0; | ||
| 746 | } | ||
| 747 | return -EINVAL; | ||
| 748 | } | ||
| 749 | |||
| 732 | static struct dasd_ccw_req *dasd_eckd_build_rcd_lpm(struct dasd_device *device, | 750 | static struct dasd_ccw_req *dasd_eckd_build_rcd_lpm(struct dasd_device *device, |
| 733 | void *rcd_buffer, | 751 | void *rcd_buffer, |
| 734 | struct ciw *ciw, __u8 lpm) | 752 | struct ciw *ciw, __u8 lpm) |
| @@ -1088,6 +1106,7 @@ dasd_eckd_check_characteristics(struct dasd_device *device) | |||
| 1088 | { | 1106 | { |
| 1089 | struct dasd_eckd_private *private; | 1107 | struct dasd_eckd_private *private; |
| 1090 | struct dasd_block *block; | 1108 | struct dasd_block *block; |
| 1109 | struct dasd_uid temp_uid; | ||
| 1091 | int is_known, rc; | 1110 | int is_known, rc; |
| 1092 | int readonly; | 1111 | int readonly; |
| 1093 | 1112 | ||
| @@ -1124,13 +1143,13 @@ dasd_eckd_check_characteristics(struct dasd_device *device) | |||
| 1124 | if (rc) | 1143 | if (rc) |
| 1125 | goto out_err1; | 1144 | goto out_err1; |
| 1126 | 1145 | ||
| 1127 | /* Generate device unique id and register in devmap */ | 1146 | /* Generate device unique id */ |
| 1128 | rc = dasd_eckd_generate_uid(device, &private->uid); | 1147 | rc = dasd_eckd_generate_uid(device); |
| 1129 | if (rc) | 1148 | if (rc) |
| 1130 | goto out_err1; | 1149 | goto out_err1; |
| 1131 | dasd_set_uid(device->cdev, &private->uid); | ||
| 1132 | 1150 | ||
| 1133 | if (private->uid.type == UA_BASE_DEVICE) { | 1151 | dasd_eckd_get_uid(device, &temp_uid); |
| 1152 | if (temp_uid.type == UA_BASE_DEVICE) { | ||
| 1134 | block = dasd_alloc_block(); | 1153 | block = dasd_alloc_block(); |
| 1135 | if (IS_ERR(block)) { | 1154 | if (IS_ERR(block)) { |
| 1136 | DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "%s", | 1155 | DBF_EVENT_DEVID(DBF_WARNING, device->cdev, "%s", |
| @@ -1451,6 +1470,7 @@ static int dasd_eckd_ready_to_online(struct dasd_device *device) | |||
| 1451 | 1470 | ||
| 1452 | static int dasd_eckd_online_to_ready(struct dasd_device *device) | 1471 | static int dasd_eckd_online_to_ready(struct dasd_device *device) |
| 1453 | { | 1472 | { |
| 1473 | cancel_work_sync(&device->reload_device); | ||
| 1454 | return dasd_alias_remove_device(device); | 1474 | return dasd_alias_remove_device(device); |
| 1455 | }; | 1475 | }; |
| 1456 | 1476 | ||
| @@ -1709,10 +1729,27 @@ static void dasd_eckd_handle_unsolicited_interrupt(struct dasd_device *device, | |||
| 1709 | { | 1729 | { |
| 1710 | char mask; | 1730 | char mask; |
| 1711 | char *sense = NULL; | 1731 | char *sense = NULL; |
| 1732 | struct dasd_eckd_private *private; | ||
| 1712 | 1733 | ||
| 1734 | private = (struct dasd_eckd_private *) device->private; | ||
| 1713 | /* first of all check for state change pending interrupt */ | 1735 | /* first of all check for state change pending interrupt */ |
| 1714 | mask = DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP; | 1736 | mask = DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP; |
| 1715 | if ((scsw_dstat(&irb->scsw) & mask) == mask) { | 1737 | if ((scsw_dstat(&irb->scsw) & mask) == mask) { |
| 1738 | /* for alias only and not in offline processing*/ | ||
| 1739 | if (!device->block && private->lcu && | ||
| 1740 | !test_bit(DASD_FLAG_OFFLINE, &device->flags)) { | ||
| 1741 | /* | ||
| 1742 | * the state change could be caused by an alias | ||
| 1743 | * reassignment remove device from alias handling | ||
| 1744 | * to prevent new requests from being scheduled on | ||
| 1745 | * the wrong alias device | ||
| 1746 | */ | ||
| 1747 | dasd_alias_remove_device(device); | ||
| 1748 | |||
| 1749 | /* schedule worker to reload device */ | ||
| 1750 | dasd_reload_device(device); | ||
| 1751 | } | ||
| 1752 | |||
| 1716 | dasd_generic_handle_state_change(device); | 1753 | dasd_generic_handle_state_change(device); |
| 1717 | return; | 1754 | return; |
| 1718 | } | 1755 | } |
| @@ -3259,7 +3296,7 @@ static void dasd_eckd_dump_sense(struct dasd_device *device, | |||
| 3259 | dasd_eckd_dump_sense_ccw(device, req, irb); | 3296 | dasd_eckd_dump_sense_ccw(device, req, irb); |
| 3260 | } | 3297 | } |
| 3261 | 3298 | ||
| 3262 | int dasd_eckd_pm_freeze(struct dasd_device *device) | 3299 | static int dasd_eckd_pm_freeze(struct dasd_device *device) |
| 3263 | { | 3300 | { |
| 3264 | /* | 3301 | /* |
| 3265 | * the device should be disconnected from our LCU structure | 3302 | * the device should be disconnected from our LCU structure |
| @@ -3272,7 +3309,7 @@ int dasd_eckd_pm_freeze(struct dasd_device *device) | |||
| 3272 | return 0; | 3309 | return 0; |
| 3273 | } | 3310 | } |
| 3274 | 3311 | ||
| 3275 | int dasd_eckd_restore_device(struct dasd_device *device) | 3312 | static int dasd_eckd_restore_device(struct dasd_device *device) |
| 3276 | { | 3313 | { |
| 3277 | struct dasd_eckd_private *private; | 3314 | struct dasd_eckd_private *private; |
| 3278 | struct dasd_eckd_characteristics temp_rdc_data; | 3315 | struct dasd_eckd_characteristics temp_rdc_data; |
| @@ -3287,15 +3324,16 @@ int dasd_eckd_restore_device(struct dasd_device *device) | |||
| 3287 | if (rc) | 3324 | if (rc) |
| 3288 | goto out_err; | 3325 | goto out_err; |
| 3289 | 3326 | ||
| 3290 | /* Generate device unique id and register in devmap */ | 3327 | dasd_eckd_get_uid(device, &temp_uid); |
| 3291 | rc = dasd_eckd_generate_uid(device, &private->uid); | 3328 | /* Generate device unique id */ |
| 3292 | dasd_get_uid(device->cdev, &temp_uid); | 3329 | rc = dasd_eckd_generate_uid(device); |
| 3330 | spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); | ||
| 3293 | if (memcmp(&private->uid, &temp_uid, sizeof(struct dasd_uid)) != 0) | 3331 | if (memcmp(&private->uid, &temp_uid, sizeof(struct dasd_uid)) != 0) |
| 3294 | dev_err(&device->cdev->dev, "The UID of the DASD has " | 3332 | dev_err(&device->cdev->dev, "The UID of the DASD has " |
| 3295 | "changed\n"); | 3333 | "changed\n"); |
| 3334 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); | ||
| 3296 | if (rc) | 3335 | if (rc) |
| 3297 | goto out_err; | 3336 | goto out_err; |
| 3298 | dasd_set_uid(device->cdev, &private->uid); | ||
| 3299 | 3337 | ||
| 3300 | /* register lcu with alias handling, enable PAV if this is a new lcu */ | 3338 | /* register lcu with alias handling, enable PAV if this is a new lcu */ |
| 3301 | is_known = dasd_alias_make_device_known_to_lcu(device); | 3339 | is_known = dasd_alias_make_device_known_to_lcu(device); |
| @@ -3336,6 +3374,56 @@ out_err: | |||
| 3336 | return -1; | 3374 | return -1; |
| 3337 | } | 3375 | } |
| 3338 | 3376 | ||
| 3377 | static int dasd_eckd_reload_device(struct dasd_device *device) | ||
| 3378 | { | ||
| 3379 | struct dasd_eckd_private *private; | ||
| 3380 | int rc, old_base; | ||
| 3381 | char print_uid[60]; | ||
| 3382 | struct dasd_uid uid; | ||
| 3383 | unsigned long flags; | ||
| 3384 | |||
| 3385 | private = (struct dasd_eckd_private *) device->private; | ||
| 3386 | |||
| 3387 | spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); | ||
| 3388 | old_base = private->uid.base_unit_addr; | ||
| 3389 | spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); | ||
| 3390 | |||
| 3391 | /* Read Configuration Data */ | ||
| 3392 | rc = dasd_eckd_read_conf(device); | ||
| 3393 | if (rc) | ||
| 3394 | goto out_err; | ||
| 3395 | |||
| 3396 | rc = dasd_eckd_generate_uid(device); | ||
| 3397 | if (rc) | ||
| 3398 | goto out_err; | ||
| 3399 | /* | ||
| 3400 | * update unit address configuration and | ||
| 3401 | * add device to alias management | ||
| 3402 | */ | ||
| 3403 | dasd_alias_update_add_device(device); | ||
| 3404 | |||
| 3405 | dasd_eckd_get_uid(device, &uid); | ||
| 3406 | |||
| 3407 | if (old_base != uid.base_unit_addr) { | ||
| 3408 | if (strlen(uid.vduit) > 0) | ||
| 3409 | snprintf(print_uid, sizeof(print_uid), | ||
| 3410 | "%s.%s.%04x.%02x.%s", uid.vendor, uid.serial, | ||
| 3411 | uid.ssid, uid.base_unit_addr, uid.vduit); | ||
| 3412 | else | ||
| 3413 | snprintf(print_uid, sizeof(print_uid), | ||
| 3414 | "%s.%s.%04x.%02x", uid.vendor, uid.serial, | ||
| 3415 | uid.ssid, uid.base_unit_addr); | ||
| 3416 | |||
| 3417 | dev_info(&device->cdev->dev, | ||
| 3418 | "An Alias device was reassigned to a new base device " | ||
| 3419 | "with UID: %s\n", print_uid); | ||
| 3420 | } | ||
| 3421 | return 0; | ||
| 3422 | |||
| 3423 | out_err: | ||
| 3424 | return -1; | ||
| 3425 | } | ||
| 3426 | |||
| 3339 | static struct ccw_driver dasd_eckd_driver = { | 3427 | static struct ccw_driver dasd_eckd_driver = { |
| 3340 | .name = "dasd-eckd", | 3428 | .name = "dasd-eckd", |
| 3341 | .owner = THIS_MODULE, | 3429 | .owner = THIS_MODULE, |
| @@ -3389,6 +3477,8 @@ static struct dasd_discipline dasd_eckd_discipline = { | |||
| 3389 | .ioctl = dasd_eckd_ioctl, | 3477 | .ioctl = dasd_eckd_ioctl, |
| 3390 | .freeze = dasd_eckd_pm_freeze, | 3478 | .freeze = dasd_eckd_pm_freeze, |
| 3391 | .restore = dasd_eckd_restore_device, | 3479 | .restore = dasd_eckd_restore_device, |
| 3480 | .reload = dasd_eckd_reload_device, | ||
| 3481 | .get_uid = dasd_eckd_get_uid, | ||
| 3392 | }; | 3482 | }; |
| 3393 | 3483 | ||
| 3394 | static int __init | 3484 | static int __init |
diff --git a/drivers/s390/block/dasd_eckd.h b/drivers/s390/block/dasd_eckd.h index 864d53c04201..dd6385a5af14 100644 --- a/drivers/s390/block/dasd_eckd.h +++ b/drivers/s390/block/dasd_eckd.h | |||
| @@ -426,7 +426,6 @@ struct alias_pav_group { | |||
| 426 | struct dasd_device *next; | 426 | struct dasd_device *next; |
| 427 | }; | 427 | }; |
| 428 | 428 | ||
| 429 | |||
| 430 | struct dasd_eckd_private { | 429 | struct dasd_eckd_private { |
| 431 | struct dasd_eckd_characteristics rdc_data; | 430 | struct dasd_eckd_characteristics rdc_data; |
| 432 | u8 *conf_data; | 431 | u8 *conf_data; |
| @@ -463,4 +462,5 @@ void dasd_alias_handle_summary_unit_check(struct dasd_device *, struct irb *); | |||
| 463 | void dasd_eckd_reset_ccw_to_base_io(struct dasd_ccw_req *); | 462 | void dasd_eckd_reset_ccw_to_base_io(struct dasd_ccw_req *); |
| 464 | void dasd_alias_lcu_setup_complete(struct dasd_device *); | 463 | void dasd_alias_lcu_setup_complete(struct dasd_device *); |
| 465 | void dasd_alias_wait_for_lcu_setup(struct dasd_device *); | 464 | void dasd_alias_wait_for_lcu_setup(struct dasd_device *); |
| 465 | int dasd_alias_update_add_device(struct dasd_device *); | ||
| 466 | #endif /* DASD_ECKD_H */ | 466 | #endif /* DASD_ECKD_H */ |
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index a91d4a97d4f2..32fac186ba3f 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h | |||
| @@ -81,6 +81,10 @@ struct dasd_block; | |||
| 81 | #define DASD_SIM_MSG_TO_OP 0x03 | 81 | #define DASD_SIM_MSG_TO_OP 0x03 |
| 82 | #define DASD_SIM_LOG 0x0C | 82 | #define DASD_SIM_LOG 0x0C |
| 83 | 83 | ||
| 84 | /* lock class for nested cdev lock */ | ||
| 85 | #define CDEV_NESTED_FIRST 1 | ||
| 86 | #define CDEV_NESTED_SECOND 2 | ||
| 87 | |||
| 84 | /* | 88 | /* |
| 85 | * SECTION: MACROs for klogd and s390 debug feature (dbf) | 89 | * SECTION: MACROs for klogd and s390 debug feature (dbf) |
| 86 | */ | 90 | */ |
| @@ -229,6 +233,24 @@ struct dasd_ccw_req { | |||
| 229 | typedef struct dasd_ccw_req *(*dasd_erp_fn_t) (struct dasd_ccw_req *); | 233 | typedef struct dasd_ccw_req *(*dasd_erp_fn_t) (struct dasd_ccw_req *); |
| 230 | 234 | ||
| 231 | /* | 235 | /* |
| 236 | * Unique identifier for dasd device. | ||
| 237 | */ | ||
| 238 | #define UA_NOT_CONFIGURED 0x00 | ||
| 239 | #define UA_BASE_DEVICE 0x01 | ||
| 240 | #define UA_BASE_PAV_ALIAS 0x02 | ||
| 241 | #define UA_HYPER_PAV_ALIAS 0x03 | ||
| 242 | |||
| 243 | struct dasd_uid { | ||
| 244 | __u8 type; | ||
| 245 | char vendor[4]; | ||
| 246 | char serial[15]; | ||
| 247 | __u16 ssid; | ||
| 248 | __u8 real_unit_addr; | ||
| 249 | __u8 base_unit_addr; | ||
| 250 | char vduit[33]; | ||
| 251 | }; | ||
| 252 | |||
| 253 | /* | ||
| 232 | * the struct dasd_discipline is | 254 | * the struct dasd_discipline is |
| 233 | * sth like a table of virtual functions, if you think of dasd_eckd | 255 | * sth like a table of virtual functions, if you think of dasd_eckd |
| 234 | * inheriting dasd... | 256 | * inheriting dasd... |
| @@ -312,28 +334,15 @@ struct dasd_discipline { | |||
| 312 | /* suspend/resume functions */ | 334 | /* suspend/resume functions */ |
| 313 | int (*freeze) (struct dasd_device *); | 335 | int (*freeze) (struct dasd_device *); |
| 314 | int (*restore) (struct dasd_device *); | 336 | int (*restore) (struct dasd_device *); |
| 315 | }; | ||
| 316 | 337 | ||
| 317 | extern struct dasd_discipline *dasd_diag_discipline_pointer; | 338 | /* reload device after state change */ |
| 318 | 339 | int (*reload) (struct dasd_device *); | |
| 319 | /* | ||
| 320 | * Unique identifier for dasd device. | ||
| 321 | */ | ||
| 322 | #define UA_NOT_CONFIGURED 0x00 | ||
| 323 | #define UA_BASE_DEVICE 0x01 | ||
| 324 | #define UA_BASE_PAV_ALIAS 0x02 | ||
| 325 | #define UA_HYPER_PAV_ALIAS 0x03 | ||
| 326 | 340 | ||
| 327 | struct dasd_uid { | 341 | int (*get_uid) (struct dasd_device *, struct dasd_uid *); |
| 328 | __u8 type; | ||
| 329 | char vendor[4]; | ||
| 330 | char serial[15]; | ||
| 331 | __u16 ssid; | ||
| 332 | __u8 real_unit_addr; | ||
| 333 | __u8 base_unit_addr; | ||
| 334 | char vduit[33]; | ||
| 335 | }; | 342 | }; |
| 336 | 343 | ||
| 344 | extern struct dasd_discipline *dasd_diag_discipline_pointer; | ||
| 345 | |||
| 337 | /* | 346 | /* |
| 338 | * Notification numbers for extended error reporting notifications: | 347 | * Notification numbers for extended error reporting notifications: |
| 339 | * The DASD_EER_DISABLE notification is sent before a dasd_device (and it's | 348 | * The DASD_EER_DISABLE notification is sent before a dasd_device (and it's |
| @@ -386,6 +395,7 @@ struct dasd_device { | |||
| 386 | struct tasklet_struct tasklet; | 395 | struct tasklet_struct tasklet; |
| 387 | struct work_struct kick_work; | 396 | struct work_struct kick_work; |
| 388 | struct work_struct restore_device; | 397 | struct work_struct restore_device; |
| 398 | struct work_struct reload_device; | ||
| 389 | struct timer_list timer; | 399 | struct timer_list timer; |
| 390 | 400 | ||
| 391 | debug_info_t *debug_area; | 401 | debug_info_t *debug_area; |
| @@ -582,6 +592,7 @@ void dasd_enable_device(struct dasd_device *); | |||
| 582 | void dasd_set_target_state(struct dasd_device *, int); | 592 | void dasd_set_target_state(struct dasd_device *, int); |
| 583 | void dasd_kick_device(struct dasd_device *); | 593 | void dasd_kick_device(struct dasd_device *); |
| 584 | void dasd_restore_device(struct dasd_device *); | 594 | void dasd_restore_device(struct dasd_device *); |
| 595 | void dasd_reload_device(struct dasd_device *); | ||
| 585 | 596 | ||
| 586 | void dasd_add_request_head(struct dasd_ccw_req *); | 597 | void dasd_add_request_head(struct dasd_ccw_req *); |
| 587 | void dasd_add_request_tail(struct dasd_ccw_req *); | 598 | void dasd_add_request_tail(struct dasd_ccw_req *); |
| @@ -629,8 +640,6 @@ void dasd_devmap_exit(void); | |||
| 629 | struct dasd_device *dasd_create_device(struct ccw_device *); | 640 | struct dasd_device *dasd_create_device(struct ccw_device *); |
| 630 | void dasd_delete_device(struct dasd_device *); | 641 | void dasd_delete_device(struct dasd_device *); |
| 631 | 642 | ||
| 632 | int dasd_get_uid(struct ccw_device *, struct dasd_uid *); | ||
| 633 | int dasd_set_uid(struct ccw_device *, struct dasd_uid *); | ||
| 634 | int dasd_get_feature(struct ccw_device *, int); | 643 | int dasd_get_feature(struct ccw_device *, int); |
| 635 | int dasd_set_feature(struct ccw_device *, int, int); | 644 | int dasd_set_feature(struct ccw_device *, int, int); |
| 636 | 645 | ||
diff --git a/drivers/s390/char/Kconfig b/drivers/s390/char/Kconfig index 4e34d3686c23..40834f18754c 100644 --- a/drivers/s390/char/Kconfig +++ b/drivers/s390/char/Kconfig | |||
| @@ -148,13 +148,12 @@ config VMLOGRDR | |||
| 148 | This driver depends on the IUCV support driver. | 148 | This driver depends on the IUCV support driver. |
| 149 | 149 | ||
| 150 | config VMCP | 150 | config VMCP |
| 151 | tristate "Support for the z/VM CP interface (VM only)" | 151 | bool "Support for the z/VM CP interface" |
| 152 | depends on S390 | 152 | depends on S390 |
| 153 | help | 153 | help |
| 154 | Select this option if you want to be able to interact with the control | 154 | Select this option if you want to be able to interact with the control |
| 155 | program on z/VM | 155 | program on z/VM |
| 156 | 156 | ||
| 157 | |||
| 158 | config MONREADER | 157 | config MONREADER |
| 159 | tristate "API for reading z/VM monitor service records" | 158 | tristate "API for reading z/VM monitor service records" |
| 160 | depends on IUCV | 159 | depends on IUCV |
diff --git a/drivers/s390/char/fs3270.c b/drivers/s390/char/fs3270.c index 0eabcca3c92d..857dfcb7b359 100644 --- a/drivers/s390/char/fs3270.c +++ b/drivers/s390/char/fs3270.c | |||
| @@ -484,6 +484,7 @@ fs3270_open(struct inode *inode, struct file *filp) | |||
| 484 | raw3270_del_view(&fp->view); | 484 | raw3270_del_view(&fp->view); |
| 485 | goto out; | 485 | goto out; |
| 486 | } | 486 | } |
| 487 | nonseekable_open(inode, filp); | ||
| 487 | filp->private_data = fp; | 488 | filp->private_data = fp; |
| 488 | out: | 489 | out: |
| 489 | mutex_unlock(&fs3270_mutex); | 490 | mutex_unlock(&fs3270_mutex); |
diff --git a/drivers/s390/char/keyboard.c b/drivers/s390/char/keyboard.c index cb6bffe7141a..18d9a497863b 100644 --- a/drivers/s390/char/keyboard.c +++ b/drivers/s390/char/keyboard.c | |||
| @@ -49,7 +49,7 @@ static unsigned char ret_diacr[NR_DEAD] = { | |||
| 49 | struct kbd_data * | 49 | struct kbd_data * |
| 50 | kbd_alloc(void) { | 50 | kbd_alloc(void) { |
| 51 | struct kbd_data *kbd; | 51 | struct kbd_data *kbd; |
| 52 | int i, len; | 52 | int i; |
| 53 | 53 | ||
| 54 | kbd = kzalloc(sizeof(struct kbd_data), GFP_KERNEL); | 54 | kbd = kzalloc(sizeof(struct kbd_data), GFP_KERNEL); |
| 55 | if (!kbd) | 55 | if (!kbd) |
| @@ -59,12 +59,11 @@ kbd_alloc(void) { | |||
| 59 | goto out_kbd; | 59 | goto out_kbd; |
| 60 | for (i = 0; i < ARRAY_SIZE(key_maps); i++) { | 60 | for (i = 0; i < ARRAY_SIZE(key_maps); i++) { |
| 61 | if (key_maps[i]) { | 61 | if (key_maps[i]) { |
| 62 | kbd->key_maps[i] = | 62 | kbd->key_maps[i] = kmemdup(key_maps[i], |
| 63 | kmalloc(sizeof(u_short)*NR_KEYS, GFP_KERNEL); | 63 | sizeof(u_short) * NR_KEYS, |
| 64 | GFP_KERNEL); | ||
| 64 | if (!kbd->key_maps[i]) | 65 | if (!kbd->key_maps[i]) |
| 65 | goto out_maps; | 66 | goto out_maps; |
| 66 | memcpy(kbd->key_maps[i], key_maps[i], | ||
| 67 | sizeof(u_short)*NR_KEYS); | ||
| 68 | } | 67 | } |
| 69 | } | 68 | } |
| 70 | kbd->func_table = kzalloc(sizeof(func_table), GFP_KERNEL); | 69 | kbd->func_table = kzalloc(sizeof(func_table), GFP_KERNEL); |
| @@ -72,23 +71,21 @@ kbd_alloc(void) { | |||
| 72 | goto out_maps; | 71 | goto out_maps; |
| 73 | for (i = 0; i < ARRAY_SIZE(func_table); i++) { | 72 | for (i = 0; i < ARRAY_SIZE(func_table); i++) { |
| 74 | if (func_table[i]) { | 73 | if (func_table[i]) { |
| 75 | len = strlen(func_table[i]) + 1; | 74 | kbd->func_table[i] = kstrdup(func_table[i], |
| 76 | kbd->func_table[i] = kmalloc(len, GFP_KERNEL); | 75 | GFP_KERNEL); |
| 77 | if (!kbd->func_table[i]) | 76 | if (!kbd->func_table[i]) |
| 78 | goto out_func; | 77 | goto out_func; |
| 79 | memcpy(kbd->func_table[i], func_table[i], len); | ||
| 80 | } | 78 | } |
| 81 | } | 79 | } |
| 82 | kbd->fn_handler = | 80 | kbd->fn_handler = |
| 83 | kzalloc(sizeof(fn_handler_fn *) * NR_FN_HANDLER, GFP_KERNEL); | 81 | kzalloc(sizeof(fn_handler_fn *) * NR_FN_HANDLER, GFP_KERNEL); |
| 84 | if (!kbd->fn_handler) | 82 | if (!kbd->fn_handler) |
| 85 | goto out_func; | 83 | goto out_func; |
| 86 | kbd->accent_table = | 84 | kbd->accent_table = kmemdup(accent_table, |
| 87 | kmalloc(sizeof(struct kbdiacruc)*MAX_DIACR, GFP_KERNEL); | 85 | sizeof(struct kbdiacruc) * MAX_DIACR, |
| 86 | GFP_KERNEL); | ||
| 88 | if (!kbd->accent_table) | 87 | if (!kbd->accent_table) |
| 89 | goto out_fn_handler; | 88 | goto out_fn_handler; |
| 90 | memcpy(kbd->accent_table, accent_table, | ||
| 91 | sizeof(struct kbdiacruc)*MAX_DIACR); | ||
| 92 | kbd->accent_table_size = accent_table_size; | 89 | kbd->accent_table_size = accent_table_size; |
| 93 | return kbd; | 90 | return kbd; |
| 94 | 91 | ||
diff --git a/drivers/s390/char/vmcp.c b/drivers/s390/char/vmcp.c index 5bb59d36a6d4..04e532eec032 100644 --- a/drivers/s390/char/vmcp.c +++ b/drivers/s390/char/vmcp.c | |||
| @@ -1,24 +1,20 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright IBM Corp. 2004,2007 | 2 | * Copyright IBM Corp. 2004,2010 |
| 3 | * Interface implementation for communication with the z/VM control program | 3 | * Interface implementation for communication with the z/VM control program |
| 4 | * Author(s): Christian Borntraeger <borntraeger@de.ibm.com> | ||
| 5 | * | 4 | * |
| 5 | * Author(s): Christian Borntraeger <borntraeger@de.ibm.com> | ||
| 6 | * | 6 | * |
| 7 | * z/VMs CP offers the possibility to issue commands via the diagnose code 8 | 7 | * z/VMs CP offers the possibility to issue commands via the diagnose code 8 |
| 8 | * this driver implements a character device that issues these commands and | 8 | * this driver implements a character device that issues these commands and |
| 9 | * returns the answer of CP. | 9 | * returns the answer of CP. |
| 10 | 10 | * | |
| 11 | * The idea of this driver is based on cpint from Neale Ferguson and #CP in CMS | 11 | * The idea of this driver is based on cpint from Neale Ferguson and #CP in CMS |
| 12 | */ | 12 | */ |
| 13 | 13 | ||
| 14 | #define KMSG_COMPONENT "vmcp" | ||
| 15 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt | ||
| 16 | |||
| 17 | #include <linux/fs.h> | 14 | #include <linux/fs.h> |
| 18 | #include <linux/init.h> | 15 | #include <linux/init.h> |
| 19 | #include <linux/kernel.h> | 16 | #include <linux/kernel.h> |
| 20 | #include <linux/miscdevice.h> | 17 | #include <linux/miscdevice.h> |
| 21 | #include <linux/module.h> | ||
| 22 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
| 23 | #include <asm/compat.h> | 19 | #include <asm/compat.h> |
| 24 | #include <asm/cpcmd.h> | 20 | #include <asm/cpcmd.h> |
| @@ -26,10 +22,6 @@ | |||
| 26 | #include <asm/uaccess.h> | 22 | #include <asm/uaccess.h> |
| 27 | #include "vmcp.h" | 23 | #include "vmcp.h" |
| 28 | 24 | ||
| 29 | MODULE_LICENSE("GPL"); | ||
| 30 | MODULE_AUTHOR("Christian Borntraeger <borntraeger@de.ibm.com>"); | ||
| 31 | MODULE_DESCRIPTION("z/VM CP interface"); | ||
| 32 | |||
| 33 | static debug_info_t *vmcp_debug; | 25 | static debug_info_t *vmcp_debug; |
| 34 | 26 | ||
| 35 | static int vmcp_open(struct inode *inode, struct file *file) | 27 | static int vmcp_open(struct inode *inode, struct file *file) |
| @@ -197,11 +189,8 @@ static int __init vmcp_init(void) | |||
| 197 | { | 189 | { |
| 198 | int ret; | 190 | int ret; |
| 199 | 191 | ||
| 200 | if (!MACHINE_IS_VM) { | 192 | if (!MACHINE_IS_VM) |
| 201 | pr_warning("The z/VM CP interface device driver cannot be " | 193 | return 0; |
| 202 | "loaded without z/VM\n"); | ||
| 203 | return -ENODEV; | ||
| 204 | } | ||
| 205 | 194 | ||
| 206 | vmcp_debug = debug_register("vmcp", 1, 1, 240); | 195 | vmcp_debug = debug_register("vmcp", 1, 1, 240); |
| 207 | if (!vmcp_debug) | 196 | if (!vmcp_debug) |
| @@ -214,19 +203,8 @@ static int __init vmcp_init(void) | |||
| 214 | } | 203 | } |
| 215 | 204 | ||
| 216 | ret = misc_register(&vmcp_dev); | 205 | ret = misc_register(&vmcp_dev); |
| 217 | if (ret) { | 206 | if (ret) |
| 218 | debug_unregister(vmcp_debug); | 207 | debug_unregister(vmcp_debug); |
| 219 | return ret; | 208 | return ret; |
| 220 | } | ||
| 221 | |||
| 222 | return 0; | ||
| 223 | } | ||
| 224 | |||
| 225 | static void __exit vmcp_exit(void) | ||
| 226 | { | ||
| 227 | misc_deregister(&vmcp_dev); | ||
| 228 | debug_unregister(vmcp_debug); | ||
| 229 | } | 209 | } |
| 230 | 210 | device_initcall(vmcp_init); | |
| 231 | module_init(vmcp_init); | ||
| 232 | module_exit(vmcp_exit); | ||
diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c index 7217966f7d31..f5ea3384a4b9 100644 --- a/drivers/s390/char/zcore.c +++ b/drivers/s390/char/zcore.c | |||
| @@ -445,7 +445,7 @@ static int zcore_memmap_open(struct inode *inode, struct file *filp) | |||
| 445 | } | 445 | } |
| 446 | kfree(chunk_array); | 446 | kfree(chunk_array); |
| 447 | filp->private_data = buf; | 447 | filp->private_data = buf; |
| 448 | return 0; | 448 | return nonseekable_open(inode, filp); |
| 449 | } | 449 | } |
| 450 | 450 | ||
| 451 | static int zcore_memmap_release(struct inode *inode, struct file *filp) | 451 | static int zcore_memmap_release(struct inode *inode, struct file *filp) |
| @@ -473,7 +473,7 @@ static ssize_t zcore_reipl_write(struct file *filp, const char __user *buf, | |||
| 473 | 473 | ||
| 474 | static int zcore_reipl_open(struct inode *inode, struct file *filp) | 474 | static int zcore_reipl_open(struct inode *inode, struct file *filp) |
| 475 | { | 475 | { |
| 476 | return 0; | 476 | return nonseekable_open(inode, filp); |
| 477 | } | 477 | } |
| 478 | 478 | ||
| 479 | static int zcore_reipl_release(struct inode *inode, struct file *filp) | 479 | static int zcore_reipl_release(struct inode *inode, struct file *filp) |
diff --git a/drivers/s390/cio/chsc_sch.c b/drivers/s390/cio/chsc_sch.c index 3b6f4adc5094..a83877c664a6 100644 --- a/drivers/s390/cio/chsc_sch.c +++ b/drivers/s390/cio/chsc_sch.c | |||
| @@ -803,6 +803,7 @@ static long chsc_ioctl(struct file *filp, unsigned int cmd, | |||
| 803 | 803 | ||
| 804 | static const struct file_operations chsc_fops = { | 804 | static const struct file_operations chsc_fops = { |
| 805 | .owner = THIS_MODULE, | 805 | .owner = THIS_MODULE, |
| 806 | .open = nonseekable_open, | ||
| 806 | .unlocked_ioctl = chsc_ioctl, | 807 | .unlocked_ioctl = chsc_ioctl, |
| 807 | .compat_ioctl = chsc_ioctl, | 808 | .compat_ioctl = chsc_ioctl, |
| 808 | }; | 809 | }; |
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 5feea1a371e1..f4e6cf3aceb8 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c | |||
| @@ -616,7 +616,8 @@ void __irq_entry do_IRQ(struct pt_regs *regs) | |||
| 616 | struct pt_regs *old_regs; | 616 | struct pt_regs *old_regs; |
| 617 | 617 | ||
| 618 | old_regs = set_irq_regs(regs); | 618 | old_regs = set_irq_regs(regs); |
| 619 | s390_idle_check(); | 619 | s390_idle_check(regs, S390_lowcore.int_clock, |
| 620 | S390_lowcore.async_enter_timer); | ||
| 620 | irq_enter(); | 621 | irq_enter(); |
| 621 | __get_cpu_var(s390_idle).nohz_delay = 1; | 622 | __get_cpu_var(s390_idle).nohz_delay = 1; |
| 622 | if (S390_lowcore.int_clock >= S390_lowcore.clock_comparator) | 623 | if (S390_lowcore.int_clock >= S390_lowcore.clock_comparator) |
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 511649115bd7..ac94ac751459 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c | |||
| @@ -648,6 +648,8 @@ static void css_process_crw(struct crw *crw0, struct crw *crw1, int overflow) | |||
| 648 | static void __init | 648 | static void __init |
| 649 | css_generate_pgid(struct channel_subsystem *css, u32 tod_high) | 649 | css_generate_pgid(struct channel_subsystem *css, u32 tod_high) |
| 650 | { | 650 | { |
| 651 | struct cpuid cpu_id; | ||
| 652 | |||
| 651 | if (css_general_characteristics.mcss) { | 653 | if (css_general_characteristics.mcss) { |
| 652 | css->global_pgid.pgid_high.ext_cssid.version = 0x80; | 654 | css->global_pgid.pgid_high.ext_cssid.version = 0x80; |
| 653 | css->global_pgid.pgid_high.ext_cssid.cssid = css->cssid; | 655 | css->global_pgid.pgid_high.ext_cssid.cssid = css->cssid; |
| @@ -658,8 +660,9 @@ css_generate_pgid(struct channel_subsystem *css, u32 tod_high) | |||
| 658 | css->global_pgid.pgid_high.cpu_addr = 0; | 660 | css->global_pgid.pgid_high.cpu_addr = 0; |
| 659 | #endif | 661 | #endif |
| 660 | } | 662 | } |
| 661 | css->global_pgid.cpu_id = S390_lowcore.cpu_id.ident; | 663 | get_cpu_id(&cpu_id); |
| 662 | css->global_pgid.cpu_model = S390_lowcore.cpu_id.machine; | 664 | css->global_pgid.cpu_id = cpu_id.ident; |
| 665 | css->global_pgid.cpu_model = cpu_id.machine; | ||
| 663 | css->global_pgid.tod_high = tod_high; | 666 | css->global_pgid.tod_high = tod_high; |
| 664 | 667 | ||
| 665 | } | 668 | } |
| @@ -1062,6 +1065,7 @@ static ssize_t cio_settle_write(struct file *file, const char __user *buf, | |||
| 1062 | } | 1065 | } |
| 1063 | 1066 | ||
| 1064 | static const struct file_operations cio_settle_proc_fops = { | 1067 | static const struct file_operations cio_settle_proc_fops = { |
| 1068 | .open = nonseekable_open, | ||
| 1065 | .write = cio_settle_write, | 1069 | .write = cio_settle_write, |
| 1066 | }; | 1070 | }; |
| 1067 | 1071 | ||
diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h index 48aa0647432b..f0037eefd44e 100644 --- a/drivers/s390/cio/qdio.h +++ b/drivers/s390/cio/qdio.h | |||
| @@ -13,8 +13,8 @@ | |||
| 13 | #include <asm/debug.h> | 13 | #include <asm/debug.h> |
| 14 | #include "chsc.h" | 14 | #include "chsc.h" |
| 15 | 15 | ||
| 16 | #define QDIO_BUSY_BIT_PATIENCE 100 /* 100 microseconds */ | 16 | #define QDIO_BUSY_BIT_PATIENCE (100 << 12) /* 100 microseconds */ |
| 17 | #define QDIO_INPUT_THRESHOLD 500 /* 500 microseconds */ | 17 | #define QDIO_INPUT_THRESHOLD (500 << 12) /* 500 microseconds */ |
| 18 | 18 | ||
| 19 | /* | 19 | /* |
| 20 | * if an asynchronous HiperSockets queue runs full, the 10 seconds timer wait | 20 | * if an asynchronous HiperSockets queue runs full, the 10 seconds timer wait |
| @@ -296,10 +296,8 @@ struct qdio_q { | |||
| 296 | struct qdio_irq *irq_ptr; | 296 | struct qdio_irq *irq_ptr; |
| 297 | struct sl *sl; | 297 | struct sl *sl; |
| 298 | /* | 298 | /* |
| 299 | * Warning: Leave this member at the end so it won't be cleared in | 299 | * A page is allocated under this pointer and used for slib and sl. |
| 300 | * qdio_fill_qs. A page is allocated under this pointer and used for | 300 | * slib is 2048 bytes big and sl points to offset PAGE_SIZE / 2. |
| 301 | * slib and sl. slib is 2048 bytes big and sl points to offset | ||
| 302 | * PAGE_SIZE / 2. | ||
| 303 | */ | 301 | */ |
| 304 | struct slib *slib; | 302 | struct slib *slib; |
| 305 | } __attribute__ ((aligned(256))); | 303 | } __attribute__ ((aligned(256))); |
| @@ -372,11 +370,6 @@ static inline int multicast_outbound(struct qdio_q *q) | |||
| 372 | (q->nr == q->irq_ptr->nr_output_qs - 1); | 370 | (q->nr == q->irq_ptr->nr_output_qs - 1); |
| 373 | } | 371 | } |
| 374 | 372 | ||
| 375 | static inline unsigned long long get_usecs(void) | ||
| 376 | { | ||
| 377 | return monotonic_clock() >> 12; | ||
| 378 | } | ||
| 379 | |||
| 380 | #define pci_out_supported(q) \ | 373 | #define pci_out_supported(q) \ |
| 381 | (q->irq_ptr->qib.ac & QIB_AC_OUTBOUND_PCI_SUPPORTED) | 374 | (q->irq_ptr->qib.ac & QIB_AC_OUTBOUND_PCI_SUPPORTED) |
| 382 | #define is_qebsm(q) (q->irq_ptr->sch_token != 0) | 375 | #define is_qebsm(q) (q->irq_ptr->sch_token != 0) |
diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 88be7b9ea6e1..00520f9a7a8e 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c | |||
| @@ -336,10 +336,10 @@ again: | |||
| 336 | WARN_ON(queue_type(q) != QDIO_IQDIO_QFMT || cc != 2); | 336 | WARN_ON(queue_type(q) != QDIO_IQDIO_QFMT || cc != 2); |
| 337 | 337 | ||
| 338 | if (!start_time) { | 338 | if (!start_time) { |
| 339 | start_time = get_usecs(); | 339 | start_time = get_clock(); |
| 340 | goto again; | 340 | goto again; |
| 341 | } | 341 | } |
| 342 | if ((get_usecs() - start_time) < QDIO_BUSY_BIT_PATIENCE) | 342 | if ((get_clock() - start_time) < QDIO_BUSY_BIT_PATIENCE) |
| 343 | goto again; | 343 | goto again; |
| 344 | } | 344 | } |
| 345 | return cc; | 345 | return cc; |
| @@ -536,7 +536,7 @@ static int qdio_inbound_q_moved(struct qdio_q *q) | |||
| 536 | if ((bufnr != q->last_move) || q->qdio_error) { | 536 | if ((bufnr != q->last_move) || q->qdio_error) { |
| 537 | q->last_move = bufnr; | 537 | q->last_move = bufnr; |
| 538 | if (!is_thinint_irq(q->irq_ptr) && MACHINE_IS_LPAR) | 538 | if (!is_thinint_irq(q->irq_ptr) && MACHINE_IS_LPAR) |
| 539 | q->u.in.timestamp = get_usecs(); | 539 | q->u.in.timestamp = get_clock(); |
| 540 | return 1; | 540 | return 1; |
| 541 | } else | 541 | } else |
| 542 | return 0; | 542 | return 0; |
| @@ -567,7 +567,7 @@ static inline int qdio_inbound_q_done(struct qdio_q *q) | |||
| 567 | * At this point we know, that inbound first_to_check | 567 | * At this point we know, that inbound first_to_check |
| 568 | * has (probably) not moved (see qdio_inbound_processing). | 568 | * has (probably) not moved (see qdio_inbound_processing). |
| 569 | */ | 569 | */ |
| 570 | if (get_usecs() > q->u.in.timestamp + QDIO_INPUT_THRESHOLD) { | 570 | if (get_clock() > q->u.in.timestamp + QDIO_INPUT_THRESHOLD) { |
| 571 | DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "in done:%02x", | 571 | DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "in done:%02x", |
| 572 | q->first_to_check); | 572 | q->first_to_check); |
| 573 | return 1; | 573 | return 1; |
| @@ -606,7 +606,7 @@ static void qdio_kick_handler(struct qdio_q *q) | |||
| 606 | static void __qdio_inbound_processing(struct qdio_q *q) | 606 | static void __qdio_inbound_processing(struct qdio_q *q) |
| 607 | { | 607 | { |
| 608 | qperf_inc(q, tasklet_inbound); | 608 | qperf_inc(q, tasklet_inbound); |
| 609 | again: | 609 | |
| 610 | if (!qdio_inbound_q_moved(q)) | 610 | if (!qdio_inbound_q_moved(q)) |
| 611 | return; | 611 | return; |
| 612 | 612 | ||
| @@ -615,7 +615,10 @@ again: | |||
| 615 | if (!qdio_inbound_q_done(q)) { | 615 | if (!qdio_inbound_q_done(q)) { |
| 616 | /* means poll time is not yet over */ | 616 | /* means poll time is not yet over */ |
| 617 | qperf_inc(q, tasklet_inbound_resched); | 617 | qperf_inc(q, tasklet_inbound_resched); |
| 618 | goto again; | 618 | if (likely(q->irq_ptr->state != QDIO_IRQ_STATE_STOPPED)) { |
| 619 | tasklet_schedule(&q->tasklet); | ||
| 620 | return; | ||
| 621 | } | ||
| 619 | } | 622 | } |
| 620 | 623 | ||
| 621 | qdio_stop_polling(q); | 624 | qdio_stop_polling(q); |
| @@ -625,7 +628,8 @@ again: | |||
| 625 | */ | 628 | */ |
| 626 | if (!qdio_inbound_q_done(q)) { | 629 | if (!qdio_inbound_q_done(q)) { |
| 627 | qperf_inc(q, tasklet_inbound_resched2); | 630 | qperf_inc(q, tasklet_inbound_resched2); |
| 628 | goto again; | 631 | if (likely(q->irq_ptr->state != QDIO_IRQ_STATE_STOPPED)) |
| 632 | tasklet_schedule(&q->tasklet); | ||
| 629 | } | 633 | } |
| 630 | } | 634 | } |
| 631 | 635 | ||
| @@ -955,6 +959,9 @@ void qdio_int_handler(struct ccw_device *cdev, unsigned long intparm, | |||
| 955 | return; | 959 | return; |
| 956 | } | 960 | } |
| 957 | 961 | ||
| 962 | if (irq_ptr->perf_stat_enabled) | ||
| 963 | irq_ptr->perf_stat.qdio_int++; | ||
| 964 | |||
| 958 | if (IS_ERR(irb)) { | 965 | if (IS_ERR(irb)) { |
| 959 | switch (PTR_ERR(irb)) { | 966 | switch (PTR_ERR(irb)) { |
| 960 | case -EIO: | 967 | case -EIO: |
| @@ -1016,30 +1023,6 @@ int qdio_get_ssqd_desc(struct ccw_device *cdev, | |||
| 1016 | } | 1023 | } |
| 1017 | EXPORT_SYMBOL_GPL(qdio_get_ssqd_desc); | 1024 | EXPORT_SYMBOL_GPL(qdio_get_ssqd_desc); |
| 1018 | 1025 | ||
| 1019 | /** | ||
| 1020 | * qdio_cleanup - shutdown queues and free data structures | ||
| 1021 | * @cdev: associated ccw device | ||
| 1022 | * @how: use halt or clear to shutdown | ||
| 1023 | * | ||
| 1024 | * This function calls qdio_shutdown() for @cdev with method @how. | ||
| 1025 | * and qdio_free(). The qdio_free() return value is ignored since | ||
| 1026 | * !irq_ptr is already checked. | ||
| 1027 | */ | ||
| 1028 | int qdio_cleanup(struct ccw_device *cdev, int how) | ||
| 1029 | { | ||
| 1030 | struct qdio_irq *irq_ptr = cdev->private->qdio_data; | ||
| 1031 | int rc; | ||
| 1032 | |||
| 1033 | if (!irq_ptr) | ||
| 1034 | return -ENODEV; | ||
| 1035 | |||
| 1036 | rc = qdio_shutdown(cdev, how); | ||
| 1037 | |||
| 1038 | qdio_free(cdev); | ||
| 1039 | return rc; | ||
| 1040 | } | ||
| 1041 | EXPORT_SYMBOL_GPL(qdio_cleanup); | ||
| 1042 | |||
| 1043 | static void qdio_shutdown_queues(struct ccw_device *cdev) | 1026 | static void qdio_shutdown_queues(struct ccw_device *cdev) |
| 1044 | { | 1027 | { |
| 1045 | struct qdio_irq *irq_ptr = cdev->private->qdio_data; | 1028 | struct qdio_irq *irq_ptr = cdev->private->qdio_data; |
| @@ -1157,28 +1140,6 @@ int qdio_free(struct ccw_device *cdev) | |||
| 1157 | EXPORT_SYMBOL_GPL(qdio_free); | 1140 | EXPORT_SYMBOL_GPL(qdio_free); |
| 1158 | 1141 | ||
| 1159 | /** | 1142 | /** |
| 1160 | * qdio_initialize - allocate and establish queues for a qdio subchannel | ||
| 1161 | * @init_data: initialization data | ||
| 1162 | * | ||
| 1163 | * This function first allocates queues via qdio_allocate() and on success | ||
| 1164 | * establishes them via qdio_establish(). | ||
| 1165 | */ | ||
| 1166 | int qdio_initialize(struct qdio_initialize *init_data) | ||
| 1167 | { | ||
| 1168 | int rc; | ||
| 1169 | |||
| 1170 | rc = qdio_allocate(init_data); | ||
| 1171 | if (rc) | ||
| 1172 | return rc; | ||
| 1173 | |||
| 1174 | rc = qdio_establish(init_data); | ||
| 1175 | if (rc) | ||
| 1176 | qdio_free(init_data->cdev); | ||
| 1177 | return rc; | ||
| 1178 | } | ||
| 1179 | EXPORT_SYMBOL_GPL(qdio_initialize); | ||
| 1180 | |||
| 1181 | /** | ||
| 1182 | * qdio_allocate - allocate qdio queues and associated data | 1143 | * qdio_allocate - allocate qdio queues and associated data |
| 1183 | * @init_data: initialization data | 1144 | * @init_data: initialization data |
| 1184 | */ | 1145 | */ |
diff --git a/drivers/s390/cio/qdio_setup.c b/drivers/s390/cio/qdio_setup.c index 7f4a75465140..6326b67c45d2 100644 --- a/drivers/s390/cio/qdio_setup.c +++ b/drivers/s390/cio/qdio_setup.c | |||
| @@ -106,10 +106,12 @@ int qdio_allocate_qs(struct qdio_irq *irq_ptr, int nr_input_qs, int nr_output_qs | |||
| 106 | static void setup_queues_misc(struct qdio_q *q, struct qdio_irq *irq_ptr, | 106 | static void setup_queues_misc(struct qdio_q *q, struct qdio_irq *irq_ptr, |
| 107 | qdio_handler_t *handler, int i) | 107 | qdio_handler_t *handler, int i) |
| 108 | { | 108 | { |
| 109 | /* must be cleared by every qdio_establish */ | 109 | struct slib *slib = q->slib; |
| 110 | memset(q, 0, ((char *)&q->slib) - ((char *)q)); | ||
| 111 | memset(q->slib, 0, PAGE_SIZE); | ||
| 112 | 110 | ||
| 111 | /* queue must be cleared for qdio_establish */ | ||
| 112 | memset(q, 0, sizeof(*q)); | ||
| 113 | memset(slib, 0, PAGE_SIZE); | ||
| 114 | q->slib = slib; | ||
| 113 | q->irq_ptr = irq_ptr; | 115 | q->irq_ptr = irq_ptr; |
| 114 | q->mask = 1 << (31 - i); | 116 | q->mask = 1 << (31 - i); |
| 115 | q->nr = i; | 117 | q->nr = i; |
diff --git a/drivers/s390/cio/qdio_thinint.c b/drivers/s390/cio/qdio_thinint.c index ce5f8910ff83..8daf1b99f153 100644 --- a/drivers/s390/cio/qdio_thinint.c +++ b/drivers/s390/cio/qdio_thinint.c | |||
| @@ -95,7 +95,7 @@ void tiqdio_add_input_queues(struct qdio_irq *irq_ptr) | |||
| 95 | for_each_input_queue(irq_ptr, q, i) | 95 | for_each_input_queue(irq_ptr, q, i) |
| 96 | list_add_rcu(&q->entry, &tiq_list); | 96 | list_add_rcu(&q->entry, &tiq_list); |
| 97 | mutex_unlock(&tiq_list_lock); | 97 | mutex_unlock(&tiq_list_lock); |
| 98 | xchg(irq_ptr->dsci, 1); | 98 | xchg(irq_ptr->dsci, 1 << 7); |
| 99 | } | 99 | } |
| 100 | 100 | ||
| 101 | void tiqdio_remove_input_queues(struct qdio_irq *irq_ptr) | 101 | void tiqdio_remove_input_queues(struct qdio_irq *irq_ptr) |
| @@ -173,7 +173,7 @@ static void tiqdio_thinint_handler(void *ind, void *drv_data) | |||
| 173 | 173 | ||
| 174 | /* prevent racing */ | 174 | /* prevent racing */ |
| 175 | if (*tiqdio_alsi) | 175 | if (*tiqdio_alsi) |
| 176 | xchg(&q_indicators[TIQDIO_SHARED_IND].ind, 1); | 176 | xchg(&q_indicators[TIQDIO_SHARED_IND].ind, 1 << 7); |
| 177 | } | 177 | } |
| 178 | } | 178 | } |
| 179 | 179 | ||
diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c index 304caf549973..41e0aaefafd5 100644 --- a/drivers/s390/crypto/zcrypt_api.c +++ b/drivers/s390/crypto/zcrypt_api.c | |||
| @@ -302,7 +302,7 @@ static ssize_t zcrypt_write(struct file *filp, const char __user *buf, | |||
| 302 | static int zcrypt_open(struct inode *inode, struct file *filp) | 302 | static int zcrypt_open(struct inode *inode, struct file *filp) |
| 303 | { | 303 | { |
| 304 | atomic_inc(&zcrypt_open_count); | 304 | atomic_inc(&zcrypt_open_count); |
| 305 | return 0; | 305 | return nonseekable_open(inode, filp); |
| 306 | } | 306 | } |
| 307 | 307 | ||
| 308 | /** | 308 | /** |
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 3ba738b2e271..28f71349fdec 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c | |||
| @@ -1292,13 +1292,14 @@ int qeth_qdio_clear_card(struct qeth_card *card, int use_halt) | |||
| 1292 | QETH_QDIO_CLEANING)) { | 1292 | QETH_QDIO_CLEANING)) { |
| 1293 | case QETH_QDIO_ESTABLISHED: | 1293 | case QETH_QDIO_ESTABLISHED: |
| 1294 | if (card->info.type == QETH_CARD_TYPE_IQD) | 1294 | if (card->info.type == QETH_CARD_TYPE_IQD) |
| 1295 | rc = qdio_cleanup(CARD_DDEV(card), | 1295 | rc = qdio_shutdown(CARD_DDEV(card), |
| 1296 | QDIO_FLAG_CLEANUP_USING_HALT); | 1296 | QDIO_FLAG_CLEANUP_USING_HALT); |
| 1297 | else | 1297 | else |
| 1298 | rc = qdio_cleanup(CARD_DDEV(card), | 1298 | rc = qdio_shutdown(CARD_DDEV(card), |
| 1299 | QDIO_FLAG_CLEANUP_USING_CLEAR); | 1299 | QDIO_FLAG_CLEANUP_USING_CLEAR); |
| 1300 | if (rc) | 1300 | if (rc) |
| 1301 | QETH_DBF_TEXT_(TRACE, 3, "1err%d", rc); | 1301 | QETH_DBF_TEXT_(TRACE, 3, "1err%d", rc); |
| 1302 | qdio_free(CARD_DDEV(card)); | ||
| 1302 | atomic_set(&card->qdio.state, QETH_QDIO_ALLOCATED); | 1303 | atomic_set(&card->qdio.state, QETH_QDIO_ALLOCATED); |
| 1303 | break; | 1304 | break; |
| 1304 | case QETH_QDIO_CLEANING: | 1305 | case QETH_QDIO_CLEANING: |
| @@ -3810,10 +3811,18 @@ static int qeth_qdio_establish(struct qeth_card *card) | |||
| 3810 | 3811 | ||
| 3811 | if (atomic_cmpxchg(&card->qdio.state, QETH_QDIO_ALLOCATED, | 3812 | if (atomic_cmpxchg(&card->qdio.state, QETH_QDIO_ALLOCATED, |
| 3812 | QETH_QDIO_ESTABLISHED) == QETH_QDIO_ALLOCATED) { | 3813 | QETH_QDIO_ESTABLISHED) == QETH_QDIO_ALLOCATED) { |
| 3813 | rc = qdio_initialize(&init_data); | 3814 | rc = qdio_allocate(&init_data); |
| 3814 | if (rc) | 3815 | if (rc) { |
| 3816 | atomic_set(&card->qdio.state, QETH_QDIO_ALLOCATED); | ||
| 3817 | goto out; | ||
| 3818 | } | ||
| 3819 | rc = qdio_establish(&init_data); | ||
| 3820 | if (rc) { | ||
| 3815 | atomic_set(&card->qdio.state, QETH_QDIO_ALLOCATED); | 3821 | atomic_set(&card->qdio.state, QETH_QDIO_ALLOCATED); |
| 3822 | qdio_free(CARD_DDEV(card)); | ||
| 3823 | } | ||
| 3816 | } | 3824 | } |
| 3825 | out: | ||
| 3817 | kfree(out_sbal_ptrs); | 3826 | kfree(out_sbal_ptrs); |
| 3818 | kfree(in_sbal_ptrs); | 3827 | kfree(in_sbal_ptrs); |
| 3819 | kfree(qib_param_field); | 3828 | kfree(qib_param_field); |
diff --git a/drivers/s390/scsi/zfcp_cfdc.c b/drivers/s390/scsi/zfcp_cfdc.c index 25d9e0ae9c57..1a2db0a35737 100644 --- a/drivers/s390/scsi/zfcp_cfdc.c +++ b/drivers/s390/scsi/zfcp_cfdc.c | |||
| @@ -254,6 +254,7 @@ static long zfcp_cfdc_dev_ioctl(struct file *file, unsigned int command, | |||
| 254 | } | 254 | } |
| 255 | 255 | ||
| 256 | static const struct file_operations zfcp_cfdc_fops = { | 256 | static const struct file_operations zfcp_cfdc_fops = { |
| 257 | .open = nonseekable_open, | ||
| 257 | .unlocked_ioctl = zfcp_cfdc_dev_ioctl, | 258 | .unlocked_ioctl = zfcp_cfdc_dev_ioctl, |
| 258 | #ifdef CONFIG_COMPAT | 259 | #ifdef CONFIG_COMPAT |
| 259 | .compat_ioctl = zfcp_cfdc_dev_ioctl | 260 | .compat_ioctl = zfcp_cfdc_dev_ioctl |
diff --git a/include/linux/elf.h b/include/linux/elf.h index 597858418051..4d608014753a 100644 --- a/include/linux/elf.h +++ b/include/linux/elf.h | |||
| @@ -394,6 +394,7 @@ typedef struct elf64_shdr { | |||
| 394 | #define NT_S390_TODPREG 0x303 /* s390 TOD programmable register */ | 394 | #define NT_S390_TODPREG 0x303 /* s390 TOD programmable register */ |
| 395 | #define NT_S390_CTRS 0x304 /* s390 control registers */ | 395 | #define NT_S390_CTRS 0x304 /* s390 control registers */ |
| 396 | #define NT_S390_PREFIX 0x305 /* s390 prefix register */ | 396 | #define NT_S390_PREFIX 0x305 /* s390 prefix register */ |
| 397 | #define NT_S390_LAST_BREAK 0x306 /* s390 breaking event address */ | ||
| 397 | 398 | ||
| 398 | 399 | ||
| 399 | /* Note header in a PT_NOTE section */ | 400 | /* Note header in a PT_NOTE section */ |
diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 8686b0f5fc12..90f536d84643 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c | |||
| @@ -621,7 +621,7 @@ static struct ctl_table kern_table[] = { | |||
| 621 | #endif | 621 | #endif |
| 622 | { | 622 | { |
| 623 | .procname = "userprocess_debug", | 623 | .procname = "userprocess_debug", |
| 624 | .data = &sysctl_userprocess_debug, | 624 | .data = &show_unhandled_signals, |
| 625 | .maxlen = sizeof(int), | 625 | .maxlen = sizeof(int), |
| 626 | .mode = 0644, | 626 | .mode = 0644, |
| 627 | .proc_handler = proc_dointvec, | 627 | .proc_handler = proc_dointvec, |
| @@ -1431,7 +1431,8 @@ static struct ctl_table fs_table[] = { | |||
| 1431 | }; | 1431 | }; |
| 1432 | 1432 | ||
| 1433 | static struct ctl_table debug_table[] = { | 1433 | static struct ctl_table debug_table[] = { |
| 1434 | #if defined(CONFIG_X86) || defined(CONFIG_PPC) || defined(CONFIG_SPARC) | 1434 | #if defined(CONFIG_X86) || defined(CONFIG_PPC) || defined(CONFIG_SPARC) || \ |
| 1435 | defined(CONFIG_S390) | ||
| 1435 | { | 1436 | { |
| 1436 | .procname = "exception-trace", | 1437 | .procname = "exception-trace", |
| 1437 | .data = &show_unhandled_signals, | 1438 | .data = &show_unhandled_signals, |
