diff options
| -rw-r--r-- | arch/s390/hypfs/inode.c | 33 | ||||
| -rw-r--r-- | arch/s390/kernel/Makefile | 2 | ||||
| -rw-r--r-- | arch/s390/kernel/diag.c | 102 | ||||
| -rw-r--r-- | arch/s390/kernel/dis.c | 2 | ||||
| -rw-r--r-- | arch/s390/kernel/kprobes.c | 2 | ||||
| -rw-r--r-- | arch/s390/kernel/s390_ksyms.c | 1 | ||||
| -rw-r--r-- | arch/s390/mm/cmm.c | 1 | ||||
| -rw-r--r-- | arch/s390/mm/init.c | 17 | ||||
| -rw-r--r-- | drivers/s390/block/dasd_diag.c | 1 | ||||
| -rw-r--r-- | drivers/s390/char/raw3270.c | 1 | ||||
| -rw-r--r-- | drivers/s390/char/vmur.c | 250 | ||||
| -rw-r--r-- | drivers/s390/char/vmur.h | 1 | ||||
| -rw-r--r-- | drivers/s390/cio/cmf.c | 10 | ||||
| -rw-r--r-- | drivers/s390/cio/device.c | 5 | ||||
| -rw-r--r-- | drivers/s390/cio/device_id.c | 48 | ||||
| -rw-r--r-- | drivers/s390/cio/qdio.c | 5 | ||||
| -rw-r--r-- | include/asm-s390/atomic.h | 26 | ||||
| -rw-r--r-- | include/asm-s390/cio.h | 15 | ||||
| -rw-r--r-- | include/asm-s390/diag.h | 39 | ||||
| -rw-r--r-- | include/asm-s390/pgalloc.h | 2 |
20 files changed, 371 insertions, 192 deletions
diff --git a/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c index ad4ca75c0f04..5245717295b8 100644 --- a/arch/s390/hypfs/inode.c +++ b/arch/s390/hypfs/inode.c | |||
| @@ -60,17 +60,28 @@ static void hypfs_add_dentry(struct dentry *dentry) | |||
| 60 | hypfs_last_dentry = dentry; | 60 | hypfs_last_dentry = dentry; |
| 61 | } | 61 | } |
| 62 | 62 | ||
| 63 | static inline int hypfs_positive(struct dentry *dentry) | ||
| 64 | { | ||
| 65 | return dentry->d_inode && !d_unhashed(dentry); | ||
| 66 | } | ||
| 67 | |||
| 63 | static void hypfs_remove(struct dentry *dentry) | 68 | static void hypfs_remove(struct dentry *dentry) |
| 64 | { | 69 | { |
| 65 | struct dentry *parent; | 70 | struct dentry *parent; |
| 66 | 71 | ||
| 67 | parent = dentry->d_parent; | 72 | parent = dentry->d_parent; |
| 68 | if (S_ISDIR(dentry->d_inode->i_mode)) | 73 | if (!parent || !parent->d_inode) |
| 69 | simple_rmdir(parent->d_inode, dentry); | 74 | return; |
| 70 | else | 75 | mutex_lock(&parent->d_inode->i_mutex); |
| 71 | simple_unlink(parent->d_inode, dentry); | 76 | if (hypfs_positive(dentry)) { |
| 77 | if (S_ISDIR(dentry->d_inode->i_mode)) | ||
| 78 | simple_rmdir(parent->d_inode, dentry); | ||
| 79 | else | ||
| 80 | simple_unlink(parent->d_inode, dentry); | ||
| 81 | } | ||
| 72 | d_delete(dentry); | 82 | d_delete(dentry); |
| 73 | dput(dentry); | 83 | dput(dentry); |
| 84 | mutex_unlock(&parent->d_inode->i_mutex); | ||
| 74 | } | 85 | } |
| 75 | 86 | ||
| 76 | static void hypfs_delete_tree(struct dentry *root) | 87 | static void hypfs_delete_tree(struct dentry *root) |
| @@ -315,6 +326,7 @@ static int hypfs_fill_super(struct super_block *sb, void *data, int silent) | |||
| 315 | } | 326 | } |
| 316 | hypfs_update_update(sb); | 327 | hypfs_update_update(sb); |
| 317 | sb->s_root = root_dentry; | 328 | sb->s_root = root_dentry; |
| 329 | printk(KERN_INFO "hypfs: Hypervisor filesystem mounted\n"); | ||
| 318 | return 0; | 330 | return 0; |
| 319 | 331 | ||
| 320 | err_tree: | 332 | err_tree: |
| @@ -356,13 +368,17 @@ static struct dentry *hypfs_create_file(struct super_block *sb, | |||
| 356 | qname.name = name; | 368 | qname.name = name; |
| 357 | qname.len = strlen(name); | 369 | qname.len = strlen(name); |
| 358 | qname.hash = full_name_hash(name, qname.len); | 370 | qname.hash = full_name_hash(name, qname.len); |
| 371 | mutex_lock(&parent->d_inode->i_mutex); | ||
| 359 | dentry = lookup_one_len(name, parent, strlen(name)); | 372 | dentry = lookup_one_len(name, parent, strlen(name)); |
| 360 | if (IS_ERR(dentry)) | 373 | if (IS_ERR(dentry)) { |
| 361 | return ERR_PTR(-ENOMEM); | 374 | dentry = ERR_PTR(-ENOMEM); |
| 375 | goto fail; | ||
| 376 | } | ||
| 362 | inode = hypfs_make_inode(sb, mode); | 377 | inode = hypfs_make_inode(sb, mode); |
| 363 | if (!inode) { | 378 | if (!inode) { |
| 364 | dput(dentry); | 379 | dput(dentry); |
| 365 | return ERR_PTR(-ENOMEM); | 380 | dentry = ERR_PTR(-ENOMEM); |
| 381 | goto fail; | ||
| 366 | } | 382 | } |
| 367 | if (mode & S_IFREG) { | 383 | if (mode & S_IFREG) { |
| 368 | inode->i_fop = &hypfs_file_ops; | 384 | inode->i_fop = &hypfs_file_ops; |
| @@ -379,6 +395,8 @@ static struct dentry *hypfs_create_file(struct super_block *sb, | |||
| 379 | inode->i_private = data; | 395 | inode->i_private = data; |
| 380 | d_instantiate(dentry, inode); | 396 | d_instantiate(dentry, inode); |
| 381 | dget(dentry); | 397 | dget(dentry); |
| 398 | fail: | ||
| 399 | mutex_unlock(&parent->d_inode->i_mutex); | ||
| 382 | return dentry; | 400 | return dentry; |
| 383 | } | 401 | } |
| 384 | 402 | ||
| @@ -391,7 +409,6 @@ struct dentry *hypfs_mkdir(struct super_block *sb, struct dentry *parent, | |||
| 391 | if (IS_ERR(dentry)) | 409 | if (IS_ERR(dentry)) |
| 392 | return dentry; | 410 | return dentry; |
| 393 | hypfs_add_dentry(dentry); | 411 | hypfs_add_dentry(dentry); |
| 394 | parent->d_inode->i_nlink++; | ||
| 395 | return dentry; | 412 | return dentry; |
| 396 | } | 413 | } |
| 397 | 414 | ||
diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index 3195d375bd51..56cb71007cd9 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile | |||
| @@ -6,7 +6,7 @@ EXTRA_AFLAGS := -traditional | |||
| 6 | 6 | ||
| 7 | obj-y := bitmap.o traps.o time.o process.o base.o early.o \ | 7 | obj-y := bitmap.o traps.o time.o process.o base.o early.o \ |
| 8 | setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \ | 8 | setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \ |
| 9 | semaphore.o s390_ext.o debug.o irq.o ipl.o dis.o | 9 | semaphore.o s390_ext.o debug.o irq.o ipl.o dis.o diag.o |
| 10 | 10 | ||
| 11 | obj-y += $(if $(CONFIG_64BIT),entry64.o,entry.o) | 11 | obj-y += $(if $(CONFIG_64BIT),entry64.o,entry.o) |
| 12 | obj-y += $(if $(CONFIG_64BIT),reipl64.o,reipl.o) | 12 | obj-y += $(if $(CONFIG_64BIT),reipl64.o,reipl.o) |
diff --git a/arch/s390/kernel/diag.c b/arch/s390/kernel/diag.c new file mode 100644 index 000000000000..c032d11da8a1 --- /dev/null +++ b/arch/s390/kernel/diag.c | |||
| @@ -0,0 +1,102 @@ | |||
| 1 | /* | ||
| 2 | * Implementation of s390 diagnose codes | ||
| 3 | * | ||
| 4 | * Copyright IBM Corp. 2007 | ||
| 5 | * Author(s): Michael Holzheu <holzheu@de.ibm.com> | ||
| 6 | */ | ||
| 7 | |||
| 8 | #include <linux/module.h> | ||
| 9 | #include <asm/diag.h> | ||
| 10 | |||
| 11 | /* | ||
| 12 | * Diagnose 10: Release pages | ||
| 13 | */ | ||
| 14 | void diag10(unsigned long addr) | ||
| 15 | { | ||
| 16 | if (addr >= 0x7ff00000) | ||
| 17 | return; | ||
| 18 | asm volatile( | ||
| 19 | #ifdef CONFIG_64BIT | ||
| 20 | " sam31\n" | ||
| 21 | " diag %0,%0,0x10\n" | ||
| 22 | "0: sam64\n" | ||
| 23 | #else | ||
| 24 | " diag %0,%0,0x10\n" | ||
| 25 | "0:\n" | ||
| 26 | #endif | ||
| 27 | EX_TABLE(0b, 0b) | ||
| 28 | : : "a" (addr)); | ||
| 29 | } | ||
| 30 | EXPORT_SYMBOL(diag10); | ||
| 31 | |||
| 32 | /* | ||
| 33 | * Diagnose 14: Input spool file manipulation | ||
| 34 | */ | ||
| 35 | int diag14(unsigned long rx, unsigned long ry1, unsigned long subcode) | ||
| 36 | { | ||
| 37 | register unsigned long _ry1 asm("2") = ry1; | ||
| 38 | register unsigned long _ry2 asm("3") = subcode; | ||
| 39 | int rc = 0; | ||
| 40 | |||
| 41 | asm volatile( | ||
| 42 | #ifdef CONFIG_64BIT | ||
| 43 | " sam31\n" | ||
| 44 | " diag %2,2,0x14\n" | ||
| 45 | " sam64\n" | ||
| 46 | #else | ||
| 47 | " diag %2,2,0x14\n" | ||
| 48 | #endif | ||
| 49 | " ipm %0\n" | ||
| 50 | " srl %0,28\n" | ||
| 51 | : "=d" (rc), "+d" (_ry2) | ||
| 52 | : "d" (rx), "d" (_ry1) | ||
| 53 | : "cc"); | ||
| 54 | |||
| 55 | return rc; | ||
| 56 | } | ||
| 57 | EXPORT_SYMBOL(diag14); | ||
| 58 | |||
| 59 | /* | ||
| 60 | * Diagnose 210: Get information about a virtual device | ||
| 61 | */ | ||
| 62 | int diag210(struct diag210 *addr) | ||
| 63 | { | ||
| 64 | /* | ||
| 65 | * diag 210 needs its data below the 2GB border, so we | ||
| 66 | * use a static data area to be sure | ||
| 67 | */ | ||
| 68 | static struct diag210 diag210_tmp; | ||
| 69 | static DEFINE_SPINLOCK(diag210_lock); | ||
| 70 | unsigned long flags; | ||
| 71 | int ccode; | ||
| 72 | |||
| 73 | spin_lock_irqsave(&diag210_lock, flags); | ||
| 74 | diag210_tmp = *addr; | ||
| 75 | |||
| 76 | #ifdef CONFIG_64BIT | ||
| 77 | asm volatile( | ||
| 78 | " lhi %0,-1\n" | ||
| 79 | " sam31\n" | ||
| 80 | " diag %1,0,0x210\n" | ||
| 81 | "0: ipm %0\n" | ||
| 82 | " srl %0,28\n" | ||
| 83 | "1: sam64\n" | ||
| 84 | EX_TABLE(0b, 1b) | ||
| 85 | : "=&d" (ccode) : "a" (&diag210_tmp) : "cc", "memory"); | ||
| 86 | #else | ||
| 87 | asm volatile( | ||
| 88 | " lhi %0,-1\n" | ||
| 89 | " diag %1,0,0x210\n" | ||
| 90 | "0: ipm %0\n" | ||
| 91 | " srl %0,28\n" | ||
| 92 | "1:\n" | ||
| 93 | EX_TABLE(0b, 1b) | ||
| 94 | : "=&d" (ccode) : "a" (&diag210_tmp) : "cc", "memory"); | ||
| 95 | #endif | ||
| 96 | |||
| 97 | *addr = diag210_tmp; | ||
| 98 | spin_unlock_irqrestore(&diag210_lock, flags); | ||
| 99 | |||
| 100 | return ccode; | ||
| 101 | } | ||
| 102 | EXPORT_SYMBOL(diag210); | ||
diff --git a/arch/s390/kernel/dis.c b/arch/s390/kernel/dis.c index d3057318f2bf..50d2235df732 100644 --- a/arch/s390/kernel/dis.c +++ b/arch/s390/kernel/dis.c | |||
| @@ -577,7 +577,7 @@ static struct insn opcode_b2[] = { | |||
| 577 | { "esta", 0x4a, INSTR_RRE_RR }, | 577 | { "esta", 0x4a, INSTR_RRE_RR }, |
| 578 | { "lura", 0x4b, INSTR_RRE_RR }, | 578 | { "lura", 0x4b, INSTR_RRE_RR }, |
| 579 | { "tar", 0x4c, INSTR_RRE_AR }, | 579 | { "tar", 0x4c, INSTR_RRE_AR }, |
| 580 | { "cpya", INSTR_RRE_AA }, | 580 | { "cpya", 0x4d, INSTR_RRE_AA }, |
| 581 | { "sar", 0x4e, INSTR_RRE_AR }, | 581 | { "sar", 0x4e, INSTR_RRE_AR }, |
| 582 | { "ear", 0x4f, INSTR_RRE_RA }, | 582 | { "ear", 0x4f, INSTR_RRE_RA }, |
| 583 | { "csp", 0x50, INSTR_RRE_RR }, | 583 | { "csp", 0x50, INSTR_RRE_RR }, |
diff --git a/arch/s390/kernel/kprobes.c b/arch/s390/kernel/kprobes.c index 358d2bbbc481..e40373d9fbce 100644 --- a/arch/s390/kernel/kprobes.c +++ b/arch/s390/kernel/kprobes.c | |||
| @@ -85,7 +85,7 @@ void __kprobes get_instruction_type(struct arch_specific_insn *ainsn) | |||
| 85 | ainsn->reg = (*ainsn->insn & 0xf0) >> 4; | 85 | ainsn->reg = (*ainsn->insn & 0xf0) >> 4; |
| 86 | 86 | ||
| 87 | /* save the instruction length (pop 5-5) in bytes */ | 87 | /* save the instruction length (pop 5-5) in bytes */ |
| 88 | switch (*(__u8 *) (ainsn->insn) >> 4) { | 88 | switch (*(__u8 *) (ainsn->insn) >> 6) { |
| 89 | case 0: | 89 | case 0: |
| 90 | ainsn->ilen = 2; | 90 | ainsn->ilen = 2; |
| 91 | break; | 91 | break; |
diff --git a/arch/s390/kernel/s390_ksyms.c b/arch/s390/kernel/s390_ksyms.c index 90b5ef529eb7..7234c737f825 100644 --- a/arch/s390/kernel/s390_ksyms.c +++ b/arch/s390/kernel/s390_ksyms.c | |||
| @@ -25,7 +25,6 @@ EXPORT_SYMBOL(_oi_bitmap); | |||
| 25 | EXPORT_SYMBOL(_ni_bitmap); | 25 | EXPORT_SYMBOL(_ni_bitmap); |
| 26 | EXPORT_SYMBOL(_zb_findmap); | 26 | EXPORT_SYMBOL(_zb_findmap); |
| 27 | EXPORT_SYMBOL(_sb_findmap); | 27 | EXPORT_SYMBOL(_sb_findmap); |
| 28 | EXPORT_SYMBOL(diag10); | ||
| 29 | 28 | ||
| 30 | /* | 29 | /* |
| 31 | * semaphore ops | 30 | * semaphore ops |
diff --git a/arch/s390/mm/cmm.c b/arch/s390/mm/cmm.c index c5b2f4f078bc..fabc50adc46a 100644 --- a/arch/s390/mm/cmm.c +++ b/arch/s390/mm/cmm.c | |||
| @@ -20,6 +20,7 @@ | |||
| 20 | 20 | ||
| 21 | #include <asm/pgalloc.h> | 21 | #include <asm/pgalloc.h> |
| 22 | #include <asm/uaccess.h> | 22 | #include <asm/uaccess.h> |
| 23 | #include <asm/diag.h> | ||
| 23 | 24 | ||
| 24 | static char *sender = "VMRMSVM"; | 25 | static char *sender = "VMRMSVM"; |
| 25 | module_param(sender, charp, 0400); | 26 | module_param(sender, charp, 0400); |
diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c index 9098531a2671..3a25bbf2eb0a 100644 --- a/arch/s390/mm/init.c +++ b/arch/s390/mm/init.c | |||
| @@ -42,23 +42,6 @@ DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); | |||
| 42 | pgd_t swapper_pg_dir[PTRS_PER_PGD] __attribute__((__aligned__(PAGE_SIZE))); | 42 | pgd_t swapper_pg_dir[PTRS_PER_PGD] __attribute__((__aligned__(PAGE_SIZE))); |
| 43 | char empty_zero_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE))); | 43 | char empty_zero_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE))); |
| 44 | 44 | ||
| 45 | void diag10(unsigned long addr) | ||
| 46 | { | ||
| 47 | if (addr >= 0x7ff00000) | ||
| 48 | return; | ||
| 49 | asm volatile( | ||
| 50 | #ifdef CONFIG_64BIT | ||
| 51 | " sam31\n" | ||
| 52 | " diag %0,%0,0x10\n" | ||
| 53 | "0: sam64\n" | ||
| 54 | #else | ||
| 55 | " diag %0,%0,0x10\n" | ||
| 56 | "0:\n" | ||
| 57 | #endif | ||
| 58 | EX_TABLE(0b,0b) | ||
| 59 | : : "a" (addr)); | ||
| 60 | } | ||
| 61 | |||
| 62 | void show_mem(void) | 45 | void show_mem(void) |
| 63 | { | 46 | { |
| 64 | int i, total = 0, reserved = 0; | 47 | int i, total = 0, reserved = 0; |
diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c index eccac1c3b71b..d32c60dbdd82 100644 --- a/drivers/s390/block/dasd_diag.c +++ b/drivers/s390/block/dasd_diag.c | |||
| @@ -24,6 +24,7 @@ | |||
| 24 | #include <asm/s390_ext.h> | 24 | #include <asm/s390_ext.h> |
| 25 | #include <asm/todclk.h> | 25 | #include <asm/todclk.h> |
| 26 | #include <asm/vtoc.h> | 26 | #include <asm/vtoc.h> |
| 27 | #include <asm/diag.h> | ||
| 27 | 28 | ||
| 28 | #include "dasd_int.h" | 29 | #include "dasd_int.h" |
| 29 | #include "dasd_diag.h" | 30 | #include "dasd_diag.h" |
diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c index 4f2f81b16cfa..2edd5fb6d3dc 100644 --- a/drivers/s390/char/raw3270.c +++ b/drivers/s390/char/raw3270.c | |||
| @@ -21,6 +21,7 @@ | |||
| 21 | #include <asm/ccwdev.h> | 21 | #include <asm/ccwdev.h> |
| 22 | #include <asm/cio.h> | 22 | #include <asm/cio.h> |
| 23 | #include <asm/ebcdic.h> | 23 | #include <asm/ebcdic.h> |
| 24 | #include <asm/diag.h> | ||
| 24 | 25 | ||
| 25 | #include "raw3270.h" | 26 | #include "raw3270.h" |
| 26 | 27 | ||
diff --git a/drivers/s390/char/vmur.c b/drivers/s390/char/vmur.c index 04b19bdc09da..d70a6e65bf14 100644 --- a/drivers/s390/char/vmur.c +++ b/drivers/s390/char/vmur.c | |||
| @@ -14,6 +14,7 @@ | |||
| 14 | #include <asm/cio.h> | 14 | #include <asm/cio.h> |
| 15 | #include <asm/ccwdev.h> | 15 | #include <asm/ccwdev.h> |
| 16 | #include <asm/debug.h> | 16 | #include <asm/debug.h> |
| 17 | #include <asm/diag.h> | ||
| 17 | 18 | ||
| 18 | #include "vmur.h" | 19 | #include "vmur.h" |
| 19 | 20 | ||
| @@ -68,8 +69,26 @@ static struct ccw_driver ur_driver = { | |||
| 68 | .set_offline = ur_set_offline, | 69 | .set_offline = ur_set_offline, |
| 69 | }; | 70 | }; |
| 70 | 71 | ||
| 72 | static DEFINE_MUTEX(vmur_mutex); | ||
| 73 | |||
| 71 | /* | 74 | /* |
| 72 | * Allocation, freeing, getting and putting of urdev structures | 75 | * Allocation, freeing, getting and putting of urdev structures |
| 76 | * | ||
| 77 | * Each ur device (urd) contains a reference to its corresponding ccw device | ||
| 78 | * (cdev) using the urd->cdev pointer. Each ccw device has a reference to the | ||
| 79 | * ur device using the cdev->dev.driver_data pointer. | ||
| 80 | * | ||
| 81 | * urd references: | ||
| 82 | * - ur_probe gets a urd reference, ur_remove drops the reference | ||
| 83 | * (cdev->dev.driver_data) | ||
| 84 | * - ur_open gets a urd reference, ur_relase drops the reference | ||
| 85 | * (urf->urd) | ||
| 86 | * | ||
| 87 | * cdev references: | ||
| 88 | * - urdev_alloc get a cdev reference (urd->cdev) | ||
| 89 | * - urdev_free drops the cdev reference (urd->cdev) | ||
| 90 | * | ||
| 91 | * Setting and clearing of cdev->dev.driver_data is protected by the ccwdev lock | ||
| 73 | */ | 92 | */ |
| 74 | static struct urdev *urdev_alloc(struct ccw_device *cdev) | 93 | static struct urdev *urdev_alloc(struct ccw_device *cdev) |
| 75 | { | 94 | { |
| @@ -78,42 +97,61 @@ static struct urdev *urdev_alloc(struct ccw_device *cdev) | |||
| 78 | urd = kzalloc(sizeof(struct urdev), GFP_KERNEL); | 97 | urd = kzalloc(sizeof(struct urdev), GFP_KERNEL); |
| 79 | if (!urd) | 98 | if (!urd) |
| 80 | return NULL; | 99 | return NULL; |
| 81 | urd->cdev = cdev; | ||
| 82 | urd->reclen = cdev->id.driver_info; | 100 | urd->reclen = cdev->id.driver_info; |
| 83 | ccw_device_get_id(cdev, &urd->dev_id); | 101 | ccw_device_get_id(cdev, &urd->dev_id); |
| 84 | mutex_init(&urd->io_mutex); | 102 | mutex_init(&urd->io_mutex); |
| 85 | mutex_init(&urd->open_mutex); | 103 | mutex_init(&urd->open_mutex); |
| 104 | atomic_set(&urd->ref_count, 1); | ||
| 105 | urd->cdev = cdev; | ||
| 106 | get_device(&cdev->dev); | ||
| 86 | return urd; | 107 | return urd; |
| 87 | } | 108 | } |
| 88 | 109 | ||
| 89 | static void urdev_free(struct urdev *urd) | 110 | static void urdev_free(struct urdev *urd) |
| 90 | { | 111 | { |
| 112 | TRACE("urdev_free: %p\n", urd); | ||
| 113 | if (urd->cdev) | ||
| 114 | put_device(&urd->cdev->dev); | ||
| 91 | kfree(urd); | 115 | kfree(urd); |
| 92 | } | 116 | } |
| 93 | 117 | ||
| 94 | /* | 118 | static void urdev_get(struct urdev *urd) |
| 95 | * This is how the character device driver gets a reference to a | 119 | { |
| 96 | * ur device. When this call returns successfully, a reference has | 120 | atomic_inc(&urd->ref_count); |
| 97 | * been taken (by get_device) on the underlying kobject. The recipient | 121 | } |
| 98 | * of this urdev pointer must eventually drop it with urdev_put(urd) | 122 | |
| 99 | * which does the corresponding put_device(). | 123 | static struct urdev *urdev_get_from_cdev(struct ccw_device *cdev) |
| 100 | */ | 124 | { |
| 125 | struct urdev *urd; | ||
| 126 | unsigned long flags; | ||
| 127 | |||
| 128 | spin_lock_irqsave(get_ccwdev_lock(cdev), flags); | ||
| 129 | urd = cdev->dev.driver_data; | ||
| 130 | if (urd) | ||
| 131 | urdev_get(urd); | ||
| 132 | spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags); | ||
| 133 | return urd; | ||
| 134 | } | ||
| 135 | |||
| 101 | static struct urdev *urdev_get_from_devno(u16 devno) | 136 | static struct urdev *urdev_get_from_devno(u16 devno) |
| 102 | { | 137 | { |
| 103 | char bus_id[16]; | 138 | char bus_id[16]; |
| 104 | struct ccw_device *cdev; | 139 | struct ccw_device *cdev; |
| 140 | struct urdev *urd; | ||
| 105 | 141 | ||
| 106 | sprintf(bus_id, "0.0.%04x", devno); | 142 | sprintf(bus_id, "0.0.%04x", devno); |
| 107 | cdev = get_ccwdev_by_busid(&ur_driver, bus_id); | 143 | cdev = get_ccwdev_by_busid(&ur_driver, bus_id); |
| 108 | if (!cdev) | 144 | if (!cdev) |
| 109 | return NULL; | 145 | return NULL; |
| 110 | 146 | urd = urdev_get_from_cdev(cdev); | |
| 111 | return cdev->dev.driver_data; | 147 | put_device(&cdev->dev); |
| 148 | return urd; | ||
| 112 | } | 149 | } |
| 113 | 150 | ||
| 114 | static void urdev_put(struct urdev *urd) | 151 | static void urdev_put(struct urdev *urd) |
| 115 | { | 152 | { |
| 116 | put_device(&urd->cdev->dev); | 153 | if (atomic_dec_and_test(&urd->ref_count)) |
| 154 | urdev_free(urd); | ||
| 117 | } | 155 | } |
| 118 | 156 | ||
| 119 | /* | 157 | /* |
| @@ -245,6 +283,7 @@ static void ur_int_handler(struct ccw_device *cdev, unsigned long intparm, | |||
| 245 | return; | 283 | return; |
| 246 | } | 284 | } |
| 247 | urd = cdev->dev.driver_data; | 285 | urd = cdev->dev.driver_data; |
| 286 | BUG_ON(!urd); | ||
| 248 | /* On special conditions irb is an error pointer */ | 287 | /* On special conditions irb is an error pointer */ |
| 249 | if (IS_ERR(irb)) | 288 | if (IS_ERR(irb)) |
| 250 | urd->io_request_rc = PTR_ERR(irb); | 289 | urd->io_request_rc = PTR_ERR(irb); |
| @@ -262,9 +301,15 @@ static void ur_int_handler(struct ccw_device *cdev, unsigned long intparm, | |||
| 262 | static ssize_t ur_attr_reclen_show(struct device *dev, | 301 | static ssize_t ur_attr_reclen_show(struct device *dev, |
| 263 | struct device_attribute *attr, char *buf) | 302 | struct device_attribute *attr, char *buf) |
| 264 | { | 303 | { |
| 265 | struct urdev *urd = dev->driver_data; | 304 | struct urdev *urd; |
| 305 | int rc; | ||
| 266 | 306 | ||
| 267 | return sprintf(buf, "%zu\n", urd->reclen); | 307 | urd = urdev_get_from_cdev(to_ccwdev(dev)); |
| 308 | if (!urd) | ||
| 309 | return -ENODEV; | ||
| 310 | rc = sprintf(buf, "%zu\n", urd->reclen); | ||
| 311 | urdev_put(urd); | ||
| 312 | return rc; | ||
| 268 | } | 313 | } |
| 269 | 314 | ||
| 270 | static DEVICE_ATTR(reclen, 0444, ur_attr_reclen_show, NULL); | 315 | static DEVICE_ATTR(reclen, 0444, ur_attr_reclen_show, NULL); |
| @@ -379,31 +424,6 @@ static ssize_t ur_write(struct file *file, const char __user *udata, | |||
| 379 | return do_write(urf->urd, udata, count, urf->dev_reclen, ppos); | 424 | return do_write(urf->urd, udata, count, urf->dev_reclen, ppos); |
| 380 | } | 425 | } |
| 381 | 426 | ||
| 382 | static int do_diag_14(unsigned long rx, unsigned long ry1, | ||
| 383 | unsigned long subcode) | ||
| 384 | { | ||
| 385 | register unsigned long _ry1 asm("2") = ry1; | ||
| 386 | register unsigned long _ry2 asm("3") = subcode; | ||
| 387 | int rc = 0; | ||
| 388 | |||
| 389 | asm volatile( | ||
| 390 | #ifdef CONFIG_64BIT | ||
| 391 | " sam31\n" | ||
| 392 | " diag %2,2,0x14\n" | ||
| 393 | " sam64\n" | ||
| 394 | #else | ||
| 395 | " diag %2,2,0x14\n" | ||
| 396 | #endif | ||
| 397 | " ipm %0\n" | ||
| 398 | " srl %0,28\n" | ||
| 399 | : "=d" (rc), "+d" (_ry2) | ||
| 400 | : "d" (rx), "d" (_ry1) | ||
| 401 | : "cc"); | ||
| 402 | |||
| 403 | TRACE("diag 14: subcode=0x%lx, cc=%i\n", subcode, rc); | ||
| 404 | return rc; | ||
| 405 | } | ||
| 406 | |||
| 407 | /* | 427 | /* |
| 408 | * diagnose code 0x14 subcode 0x0028 - position spool file to designated | 428 | * diagnose code 0x14 subcode 0x0028 - position spool file to designated |
| 409 | * record | 429 | * record |
| @@ -415,7 +435,7 @@ static int diag_position_to_record(int devno, int record) | |||
| 415 | { | 435 | { |
| 416 | int cc; | 436 | int cc; |
| 417 | 437 | ||
| 418 | cc = do_diag_14(record, devno, 0x28); | 438 | cc = diag14(record, devno, 0x28); |
| 419 | switch (cc) { | 439 | switch (cc) { |
| 420 | case 0: | 440 | case 0: |
| 421 | return 0; | 441 | return 0; |
| @@ -440,7 +460,7 @@ static int diag_read_file(int devno, char *buf) | |||
| 440 | { | 460 | { |
| 441 | int cc; | 461 | int cc; |
| 442 | 462 | ||
| 443 | cc = do_diag_14((unsigned long) buf, devno, 0x00); | 463 | cc = diag14((unsigned long) buf, devno, 0x00); |
| 444 | switch (cc) { | 464 | switch (cc) { |
| 445 | case 0: | 465 | case 0: |
| 446 | return 0; | 466 | return 0; |
| @@ -533,7 +553,7 @@ static int diag_read_next_file_info(struct file_control_block *buf, int spid) | |||
| 533 | { | 553 | { |
| 534 | int cc; | 554 | int cc; |
| 535 | 555 | ||
| 536 | cc = do_diag_14((unsigned long) buf, spid, 0xfff); | 556 | cc = diag14((unsigned long) buf, spid, 0xfff); |
| 537 | switch (cc) { | 557 | switch (cc) { |
| 538 | case 0: | 558 | case 0: |
| 539 | return 0; | 559 | return 0; |
| @@ -750,64 +770,63 @@ static struct file_operations ur_fops = { | |||
| 750 | 770 | ||
| 751 | /* | 771 | /* |
| 752 | * ccw_device infrastructure: | 772 | * ccw_device infrastructure: |
| 753 | * ur_probe gets its own ref to the device (i.e. get_device), | 773 | * ur_probe creates the struct urdev (with refcount = 1), the device |
| 754 | * creates the struct urdev, the device attributes, sets up | 774 | * attributes, sets up the interrupt handler and validates the virtual |
| 755 | * the interrupt handler and validates the virtual unit record device. | 775 | * unit record device. |
| 756 | * ur_remove removes the device attributes, frees the struct urdev | 776 | * ur_remove removes the device attributes and drops the reference to |
| 757 | * and drops (put_device) the ref to the device we got in ur_probe. | 777 | * struct urdev. |
| 778 | * | ||
| 779 | * ur_probe, ur_remove, ur_set_online and ur_set_offline are serialized | ||
| 780 | * by the vmur_mutex lock. | ||
| 781 | * | ||
| 782 | * urd->char_device is used as indication that the online function has | ||
| 783 | * been completed successfully. | ||
| 758 | */ | 784 | */ |
| 759 | static int ur_probe(struct ccw_device *cdev) | 785 | static int ur_probe(struct ccw_device *cdev) |
| 760 | { | 786 | { |
| 761 | struct urdev *urd; | 787 | struct urdev *urd; |
| 762 | int rc; | 788 | int rc; |
| 763 | 789 | ||
| 764 | TRACE("ur_probe: cdev=%p state=%d\n", cdev, *(int *) cdev->private); | 790 | TRACE("ur_probe: cdev=%p\n", cdev); |
| 765 | |||
| 766 | if (!get_device(&cdev->dev)) | ||
| 767 | return -ENODEV; | ||
| 768 | 791 | ||
| 792 | mutex_lock(&vmur_mutex); | ||
| 769 | urd = urdev_alloc(cdev); | 793 | urd = urdev_alloc(cdev); |
| 770 | if (!urd) { | 794 | if (!urd) { |
| 771 | rc = -ENOMEM; | 795 | rc = -ENOMEM; |
| 772 | goto fail; | 796 | goto fail_unlock; |
| 773 | } | 797 | } |
| 798 | |||
| 774 | rc = ur_create_attributes(&cdev->dev); | 799 | rc = ur_create_attributes(&cdev->dev); |
| 775 | if (rc) { | 800 | if (rc) { |
| 776 | rc = -ENOMEM; | 801 | rc = -ENOMEM; |
| 777 | goto fail; | 802 | goto fail_urdev_put; |
| 778 | } | 803 | } |
| 779 | cdev->dev.driver_data = urd; | ||
| 780 | cdev->handler = ur_int_handler; | 804 | cdev->handler = ur_int_handler; |
| 781 | 805 | ||
| 782 | /* validate virtual unit record device */ | 806 | /* validate virtual unit record device */ |
| 783 | urd->class = get_urd_class(urd); | 807 | urd->class = get_urd_class(urd); |
| 784 | if (urd->class < 0) { | 808 | if (urd->class < 0) { |
| 785 | rc = urd->class; | 809 | rc = urd->class; |
| 786 | goto fail; | 810 | goto fail_remove_attr; |
| 787 | } | 811 | } |
| 788 | if ((urd->class != DEV_CLASS_UR_I) && (urd->class != DEV_CLASS_UR_O)) { | 812 | if ((urd->class != DEV_CLASS_UR_I) && (urd->class != DEV_CLASS_UR_O)) { |
| 789 | rc = -ENOTSUPP; | 813 | rc = -ENOTSUPP; |
| 790 | goto fail; | 814 | goto fail_remove_attr; |
| 791 | } | 815 | } |
| 816 | spin_lock_irq(get_ccwdev_lock(cdev)); | ||
| 817 | cdev->dev.driver_data = urd; | ||
| 818 | spin_unlock_irq(get_ccwdev_lock(cdev)); | ||
| 792 | 819 | ||
| 820 | mutex_unlock(&vmur_mutex); | ||
| 793 | return 0; | 821 | return 0; |
| 794 | 822 | ||
| 795 | fail: | 823 | fail_remove_attr: |
| 796 | urdev_free(urd); | ||
| 797 | put_device(&cdev->dev); | ||
| 798 | return rc; | ||
| 799 | } | ||
| 800 | |||
| 801 | static void ur_remove(struct ccw_device *cdev) | ||
| 802 | { | ||
| 803 | struct urdev *urd = cdev->dev.driver_data; | ||
| 804 | |||
| 805 | TRACE("ur_remove\n"); | ||
| 806 | if (cdev->online) | ||
| 807 | ur_set_offline(cdev); | ||
| 808 | ur_remove_attributes(&cdev->dev); | 824 | ur_remove_attributes(&cdev->dev); |
| 809 | urdev_free(urd); | 825 | fail_urdev_put: |
| 810 | put_device(&cdev->dev); | 826 | urdev_put(urd); |
| 827 | fail_unlock: | ||
| 828 | mutex_unlock(&vmur_mutex); | ||
| 829 | return rc; | ||
| 811 | } | 830 | } |
| 812 | 831 | ||
| 813 | static int ur_set_online(struct ccw_device *cdev) | 832 | static int ur_set_online(struct ccw_device *cdev) |
| @@ -816,20 +835,29 @@ static int ur_set_online(struct ccw_device *cdev) | |||
| 816 | int minor, major, rc; | 835 | int minor, major, rc; |
| 817 | char node_id[16]; | 836 | char node_id[16]; |
| 818 | 837 | ||
| 819 | TRACE("ur_set_online: cdev=%p state=%d\n", cdev, | 838 | TRACE("ur_set_online: cdev=%p\n", cdev); |
| 820 | *(int *) cdev->private); | ||
| 821 | 839 | ||
| 822 | if (!try_module_get(ur_driver.owner)) | 840 | mutex_lock(&vmur_mutex); |
| 823 | return -EINVAL; | 841 | urd = urdev_get_from_cdev(cdev); |
| 842 | if (!urd) { | ||
| 843 | /* ur_remove already deleted our urd */ | ||
| 844 | rc = -ENODEV; | ||
| 845 | goto fail_unlock; | ||
| 846 | } | ||
| 847 | |||
| 848 | if (urd->char_device) { | ||
| 849 | /* Another ur_set_online was faster */ | ||
| 850 | rc = -EBUSY; | ||
| 851 | goto fail_urdev_put; | ||
| 852 | } | ||
| 824 | 853 | ||
| 825 | urd = (struct urdev *) cdev->dev.driver_data; | ||
| 826 | minor = urd->dev_id.devno; | 854 | minor = urd->dev_id.devno; |
| 827 | major = MAJOR(ur_first_dev_maj_min); | 855 | major = MAJOR(ur_first_dev_maj_min); |
| 828 | 856 | ||
| 829 | urd->char_device = cdev_alloc(); | 857 | urd->char_device = cdev_alloc(); |
| 830 | if (!urd->char_device) { | 858 | if (!urd->char_device) { |
| 831 | rc = -ENOMEM; | 859 | rc = -ENOMEM; |
| 832 | goto fail_module_put; | 860 | goto fail_urdev_put; |
| 833 | } | 861 | } |
| 834 | 862 | ||
| 835 | cdev_init(urd->char_device, &ur_fops); | 863 | cdev_init(urd->char_device, &ur_fops); |
| @@ -858,29 +886,79 @@ static int ur_set_online(struct ccw_device *cdev) | |||
| 858 | TRACE("ur_set_online: device_create rc=%d\n", rc); | 886 | TRACE("ur_set_online: device_create rc=%d\n", rc); |
| 859 | goto fail_free_cdev; | 887 | goto fail_free_cdev; |
| 860 | } | 888 | } |
| 861 | 889 | urdev_put(urd); | |
| 890 | mutex_unlock(&vmur_mutex); | ||
| 862 | return 0; | 891 | return 0; |
| 863 | 892 | ||
| 864 | fail_free_cdev: | 893 | fail_free_cdev: |
| 865 | cdev_del(urd->char_device); | 894 | cdev_del(urd->char_device); |
| 866 | fail_module_put: | 895 | urd->char_device = NULL; |
| 867 | module_put(ur_driver.owner); | 896 | fail_urdev_put: |
| 868 | 897 | urdev_put(urd); | |
| 898 | fail_unlock: | ||
| 899 | mutex_unlock(&vmur_mutex); | ||
| 869 | return rc; | 900 | return rc; |
| 870 | } | 901 | } |
| 871 | 902 | ||
| 872 | static int ur_set_offline(struct ccw_device *cdev) | 903 | static int ur_set_offline_force(struct ccw_device *cdev, int force) |
| 873 | { | 904 | { |
| 874 | struct urdev *urd; | 905 | struct urdev *urd; |
| 906 | int rc; | ||
| 875 | 907 | ||
| 876 | TRACE("ur_set_offline: cdev=%p cdev->private=%p state=%d\n", | 908 | TRACE("ur_set_offline: cdev=%p\n", cdev); |
| 877 | cdev, cdev->private, *(int *) cdev->private); | 909 | urd = urdev_get_from_cdev(cdev); |
| 878 | urd = (struct urdev *) cdev->dev.driver_data; | 910 | if (!urd) |
| 911 | /* ur_remove already deleted our urd */ | ||
| 912 | return -ENODEV; | ||
| 913 | if (!urd->char_device) { | ||
| 914 | /* Another ur_set_offline was faster */ | ||
| 915 | rc = -EBUSY; | ||
| 916 | goto fail_urdev_put; | ||
| 917 | } | ||
| 918 | if (!force && (atomic_read(&urd->ref_count) > 2)) { | ||
| 919 | /* There is still a user of urd (e.g. ur_open) */ | ||
| 920 | TRACE("ur_set_offline: BUSY\n"); | ||
| 921 | rc = -EBUSY; | ||
| 922 | goto fail_urdev_put; | ||
| 923 | } | ||
| 879 | device_destroy(vmur_class, urd->char_device->dev); | 924 | device_destroy(vmur_class, urd->char_device->dev); |
| 880 | cdev_del(urd->char_device); | 925 | cdev_del(urd->char_device); |
| 881 | module_put(ur_driver.owner); | 926 | urd->char_device = NULL; |
| 927 | rc = 0; | ||
| 882 | 928 | ||
| 883 | return 0; | 929 | fail_urdev_put: |
| 930 | urdev_put(urd); | ||
| 931 | return rc; | ||
| 932 | } | ||
| 933 | |||
| 934 | static int ur_set_offline(struct ccw_device *cdev) | ||
| 935 | { | ||
| 936 | int rc; | ||
| 937 | |||
| 938 | mutex_lock(&vmur_mutex); | ||
| 939 | rc = ur_set_offline_force(cdev, 0); | ||
| 940 | mutex_unlock(&vmur_mutex); | ||
| 941 | return rc; | ||
| 942 | } | ||
| 943 | |||
| 944 | static void ur_remove(struct ccw_device *cdev) | ||
| 945 | { | ||
| 946 | unsigned long flags; | ||
| 947 | |||
| 948 | TRACE("ur_remove\n"); | ||
| 949 | |||
| 950 | mutex_lock(&vmur_mutex); | ||
| 951 | |||
| 952 | if (cdev->online) | ||
| 953 | ur_set_offline_force(cdev, 1); | ||
| 954 | ur_remove_attributes(&cdev->dev); | ||
| 955 | |||
| 956 | spin_lock_irqsave(get_ccwdev_lock(cdev), flags); | ||
| 957 | urdev_put(cdev->dev.driver_data); | ||
| 958 | cdev->dev.driver_data = NULL; | ||
| 959 | spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags); | ||
| 960 | |||
| 961 | mutex_unlock(&vmur_mutex); | ||
| 884 | } | 962 | } |
| 885 | 963 | ||
| 886 | /* | 964 | /* |
diff --git a/drivers/s390/char/vmur.h b/drivers/s390/char/vmur.h index 2b3c564e0472..fa959644735a 100644 --- a/drivers/s390/char/vmur.h +++ b/drivers/s390/char/vmur.h | |||
| @@ -70,6 +70,7 @@ struct urdev { | |||
| 70 | size_t reclen; /* Record length for *write* CCWs */ | 70 | size_t reclen; /* Record length for *write* CCWs */ |
| 71 | int class; /* VM device class */ | 71 | int class; /* VM device class */ |
| 72 | int io_request_rc; /* return code from I/O request */ | 72 | int io_request_rc; /* return code from I/O request */ |
| 73 | atomic_t ref_count; /* reference counter */ | ||
| 73 | }; | 74 | }; |
| 74 | 75 | ||
| 75 | /* | 76 | /* |
diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c index 02fd00b55e1b..34a796913b06 100644 --- a/drivers/s390/cio/cmf.c +++ b/drivers/s390/cio/cmf.c | |||
| @@ -594,6 +594,9 @@ alloc_cmb (struct ccw_device *cdev) | |||
| 594 | free_pages((unsigned long)mem, get_order(size)); | 594 | free_pages((unsigned long)mem, get_order(size)); |
| 595 | } else if (!mem) { | 595 | } else if (!mem) { |
| 596 | /* no luck */ | 596 | /* no luck */ |
| 597 | printk(KERN_WARNING "cio: failed to allocate area " | ||
| 598 | "for measuring %d subchannels\n", | ||
| 599 | cmb_area.num_channels); | ||
| 597 | ret = -ENOMEM; | 600 | ret = -ENOMEM; |
| 598 | goto out; | 601 | goto out; |
| 599 | } else { | 602 | } else { |
| @@ -1279,13 +1282,6 @@ init_cmf(void) | |||
| 1279 | case CMF_BASIC: | 1282 | case CMF_BASIC: |
| 1280 | format_string = "basic"; | 1283 | format_string = "basic"; |
| 1281 | cmbops = &cmbops_basic; | 1284 | cmbops = &cmbops_basic; |
| 1282 | if (cmb_area.num_channels > 4096 || cmb_area.num_channels < 1) { | ||
| 1283 | printk(KERN_ERR "cio: Basic channel measurement " | ||
| 1284 | "facility can only use 1 to 4096 devices\n" | ||
| 1285 | KERN_ERR "when the cmf driver is built" | ||
| 1286 | " as a loadable module\n"); | ||
| 1287 | return 1; | ||
| 1288 | } | ||
| 1289 | break; | 1285 | break; |
| 1290 | case CMF_EXTENDED: | 1286 | case CMF_EXTENDED: |
| 1291 | format_string = "extended"; | 1287 | format_string = "extended"; |
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 297659fa0e26..e44d92eac8e9 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c | |||
| @@ -117,7 +117,10 @@ static int ccw_uevent(struct device *dev, char **envp, int num_envp, | |||
| 117 | snprint_alias(modalias_buf, sizeof(modalias_buf), id, ""); | 117 | snprint_alias(modalias_buf, sizeof(modalias_buf), id, ""); |
| 118 | ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len, | 118 | ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len, |
| 119 | "MODALIAS=%s", modalias_buf); | 119 | "MODALIAS=%s", modalias_buf); |
| 120 | return ret; | 120 | if (ret) |
| 121 | return ret; | ||
| 122 | envp[i] = NULL; | ||
| 123 | return 0; | ||
| 121 | } | 124 | } |
| 122 | 125 | ||
| 123 | struct bus_type ccw_bus_type; | 126 | struct bus_type ccw_bus_type; |
diff --git a/drivers/s390/cio/device_id.c b/drivers/s390/cio/device_id.c index 60b9347f7c92..f232832f2b22 100644 --- a/drivers/s390/cio/device_id.c +++ b/drivers/s390/cio/device_id.c | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | #include <asm/delay.h> | 17 | #include <asm/delay.h> |
| 18 | #include <asm/cio.h> | 18 | #include <asm/cio.h> |
| 19 | #include <asm/lowcore.h> | 19 | #include <asm/lowcore.h> |
| 20 | #include <asm/diag.h> | ||
| 20 | 21 | ||
| 21 | #include "cio.h" | 22 | #include "cio.h" |
| 22 | #include "cio_debug.h" | 23 | #include "cio_debug.h" |
| @@ -25,51 +26,6 @@ | |||
| 25 | #include "ioasm.h" | 26 | #include "ioasm.h" |
| 26 | 27 | ||
| 27 | /* | 28 | /* |
| 28 | * diag210 is used under VM to get information about a virtual device | ||
| 29 | */ | ||
| 30 | int | ||
| 31 | diag210(struct diag210 * addr) | ||
| 32 | { | ||
| 33 | /* | ||
| 34 | * diag 210 needs its data below the 2GB border, so we | ||
| 35 | * use a static data area to be sure | ||
| 36 | */ | ||
| 37 | static struct diag210 diag210_tmp; | ||
| 38 | static DEFINE_SPINLOCK(diag210_lock); | ||
| 39 | unsigned long flags; | ||
| 40 | int ccode; | ||
| 41 | |||
| 42 | spin_lock_irqsave(&diag210_lock, flags); | ||
| 43 | diag210_tmp = *addr; | ||
| 44 | |||
| 45 | #ifdef CONFIG_64BIT | ||
| 46 | asm volatile( | ||
| 47 | " lhi %0,-1\n" | ||
| 48 | " sam31\n" | ||
| 49 | " diag %1,0,0x210\n" | ||
| 50 | "0: ipm %0\n" | ||
| 51 | " srl %0,28\n" | ||
| 52 | "1: sam64\n" | ||
| 53 | EX_TABLE(0b,1b) | ||
| 54 | : "=&d" (ccode) : "a" (&diag210_tmp) : "cc", "memory"); | ||
| 55 | #else | ||
| 56 | asm volatile( | ||
| 57 | " lhi %0,-1\n" | ||
| 58 | " diag %1,0,0x210\n" | ||
| 59 | "0: ipm %0\n" | ||
| 60 | " srl %0,28\n" | ||
| 61 | "1:\n" | ||
| 62 | EX_TABLE(0b,1b) | ||
| 63 | : "=&d" (ccode) : "a" (&diag210_tmp) : "cc", "memory"); | ||
| 64 | #endif | ||
| 65 | |||
| 66 | *addr = diag210_tmp; | ||
| 67 | spin_unlock_irqrestore(&diag210_lock, flags); | ||
| 68 | |||
| 69 | return ccode; | ||
| 70 | } | ||
| 71 | |||
| 72 | /* | ||
| 73 | * Input : | 29 | * Input : |
| 74 | * devno - device number | 30 | * devno - device number |
| 75 | * ps - pointer to sense ID data area | 31 | * ps - pointer to sense ID data area |
| @@ -349,5 +305,3 @@ ccw_device_sense_id_irq(struct ccw_device *cdev, enum dev_event dev_event) | |||
| 349 | break; | 305 | break; |
| 350 | } | 306 | } |
| 351 | } | 307 | } |
| 352 | |||
| 353 | EXPORT_SYMBOL(diag210); | ||
diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c index 03347aed2b3e..d8d479876ec7 100644 --- a/drivers/s390/cio/qdio.c +++ b/drivers/s390/cio/qdio.c | |||
| @@ -195,6 +195,8 @@ qdio_do_eqbs(struct qdio_q *q, unsigned char *state, | |||
| 195 | again: | 195 | again: |
| 196 | ccq = do_eqbs(irq->sch_token, state, q_no, start, cnt); | 196 | ccq = do_eqbs(irq->sch_token, state, q_no, start, cnt); |
| 197 | rc = qdio_check_ccq(q, ccq); | 197 | rc = qdio_check_ccq(q, ccq); |
| 198 | if ((ccq == 96) && (tmp_cnt != *cnt)) | ||
| 199 | rc = 0; | ||
| 198 | if (rc == 1) { | 200 | if (rc == 1) { |
| 199 | QDIO_DBF_TEXT5(1,trace,"eqAGAIN"); | 201 | QDIO_DBF_TEXT5(1,trace,"eqAGAIN"); |
| 200 | goto again; | 202 | goto again; |
| @@ -740,7 +742,8 @@ qdio_get_outbound_buffer_frontier(struct qdio_q *q) | |||
| 740 | first_not_to_check=f+qdio_min(atomic_read(&q->number_of_buffers_used), | 742 | first_not_to_check=f+qdio_min(atomic_read(&q->number_of_buffers_used), |
| 741 | (QDIO_MAX_BUFFERS_PER_Q-1)); | 743 | (QDIO_MAX_BUFFERS_PER_Q-1)); |
| 742 | 744 | ||
| 743 | if ((!q->is_iqdio_q)&&(!q->hydra_gives_outbound_pcis)) | 745 | if (((!q->is_iqdio_q) && (!q->hydra_gives_outbound_pcis)) || |
| 746 | (q->queue_type == QDIO_IQDIO_QFMT_ASYNCH)) | ||
| 744 | SYNC_MEMORY; | 747 | SYNC_MEMORY; |
| 745 | 748 | ||
| 746 | check_next: | 749 | check_next: |
diff --git a/include/asm-s390/atomic.h b/include/asm-s390/atomic.h index ea486952f778..2d184655bc5d 100644 --- a/include/asm-s390/atomic.h +++ b/include/asm-s390/atomic.h | |||
| @@ -67,8 +67,17 @@ typedef struct { | |||
| 67 | 67 | ||
| 68 | #endif /* __GNUC__ */ | 68 | #endif /* __GNUC__ */ |
| 69 | 69 | ||
| 70 | #define atomic_read(v) ((v)->counter) | 70 | static inline int atomic_read(const atomic_t *v) |
| 71 | #define atomic_set(v,i) (((v)->counter) = (i)) | 71 | { |
| 72 | barrier(); | ||
| 73 | return v->counter; | ||
| 74 | } | ||
| 75 | |||
| 76 | static inline void atomic_set(atomic_t *v, int i) | ||
| 77 | { | ||
| 78 | v->counter = i; | ||
| 79 | barrier(); | ||
| 80 | } | ||
| 72 | 81 | ||
| 73 | static __inline__ int atomic_add_return(int i, atomic_t * v) | 82 | static __inline__ int atomic_add_return(int i, atomic_t * v) |
| 74 | { | 83 | { |
| @@ -182,8 +191,17 @@ typedef struct { | |||
| 182 | 191 | ||
| 183 | #endif /* __GNUC__ */ | 192 | #endif /* __GNUC__ */ |
| 184 | 193 | ||
| 185 | #define atomic64_read(v) ((v)->counter) | 194 | static inline long long atomic64_read(const atomic64_t *v) |
| 186 | #define atomic64_set(v,i) (((v)->counter) = (i)) | 195 | { |
| 196 | barrier(); | ||
| 197 | return v->counter; | ||
| 198 | } | ||
| 199 | |||
| 200 | static inline void atomic64_set(atomic64_t *v, long long i) | ||
| 201 | { | ||
| 202 | v->counter = i; | ||
| 203 | barrier(); | ||
| 204 | } | ||
| 187 | 205 | ||
| 188 | static __inline__ long long atomic64_add_return(long long i, atomic64_t * v) | 206 | static __inline__ long long atomic64_add_return(long long i, atomic64_t * v) |
| 189 | { | 207 | { |
diff --git a/include/asm-s390/cio.h b/include/asm-s390/cio.h index f738d2827582..1982fb344164 100644 --- a/include/asm-s390/cio.h +++ b/include/asm-s390/cio.h | |||
| @@ -258,19 +258,6 @@ struct ciw { | |||
| 258 | /* Sick revalidation of device. */ | 258 | /* Sick revalidation of device. */ |
| 259 | #define CIO_REVALIDATE 0x0008 | 259 | #define CIO_REVALIDATE 0x0008 |
| 260 | 260 | ||
| 261 | struct diag210 { | ||
| 262 | __u16 vrdcdvno : 16; /* device number (input) */ | ||
| 263 | __u16 vrdclen : 16; /* data block length (input) */ | ||
| 264 | __u32 vrdcvcla : 8; /* virtual device class (output) */ | ||
| 265 | __u32 vrdcvtyp : 8; /* virtual device type (output) */ | ||
| 266 | __u32 vrdcvsta : 8; /* virtual device status (output) */ | ||
| 267 | __u32 vrdcvfla : 8; /* virtual device flags (output) */ | ||
| 268 | __u32 vrdcrccl : 8; /* real device class (output) */ | ||
| 269 | __u32 vrdccrty : 8; /* real device type (output) */ | ||
| 270 | __u32 vrdccrmd : 8; /* real device model (output) */ | ||
| 271 | __u32 vrdccrft : 8; /* real device feature (output) */ | ||
| 272 | } __attribute__ ((packed,aligned(4))); | ||
| 273 | |||
| 274 | struct ccw_dev_id { | 261 | struct ccw_dev_id { |
| 275 | u8 ssid; | 262 | u8 ssid; |
| 276 | u16 devno; | 263 | u16 devno; |
| @@ -285,8 +272,6 @@ static inline int ccw_dev_id_is_equal(struct ccw_dev_id *dev_id1, | |||
| 285 | return 0; | 272 | return 0; |
| 286 | } | 273 | } |
| 287 | 274 | ||
| 288 | extern int diag210(struct diag210 *addr); | ||
| 289 | |||
| 290 | extern void wait_cons_dev(void); | 275 | extern void wait_cons_dev(void); |
| 291 | 276 | ||
| 292 | extern void css_schedule_reprobe(void); | 277 | extern void css_schedule_reprobe(void); |
diff --git a/include/asm-s390/diag.h b/include/asm-s390/diag.h new file mode 100644 index 000000000000..72b2e2f2d32d --- /dev/null +++ b/include/asm-s390/diag.h | |||
| @@ -0,0 +1,39 @@ | |||
| 1 | /* | ||
| 2 | * s390 diagnose functions | ||
| 3 | * | ||
| 4 | * Copyright IBM Corp. 2007 | ||
| 5 | * Author(s): Michael Holzheu <holzheu@de.ibm.com> | ||
| 6 | */ | ||
| 7 | |||
| 8 | #ifndef _ASM_S390_DIAG_H | ||
| 9 | #define _ASM_S390_DIAG_H | ||
| 10 | |||
| 11 | /* | ||
| 12 | * Diagnose 10: Release pages | ||
| 13 | */ | ||
| 14 | extern void diag10(unsigned long addr); | ||
| 15 | |||
| 16 | /* | ||
| 17 | * Diagnose 14: Input spool file manipulation | ||
| 18 | */ | ||
| 19 | extern int diag14(unsigned long rx, unsigned long ry1, unsigned long subcode); | ||
| 20 | |||
| 21 | /* | ||
| 22 | * Diagnose 210: Get information about a virtual device | ||
| 23 | */ | ||
| 24 | struct diag210 { | ||
| 25 | u16 vrdcdvno; /* device number (input) */ | ||
| 26 | u16 vrdclen; /* data block length (input) */ | ||
| 27 | u8 vrdcvcla; /* virtual device class (output) */ | ||
| 28 | u8 vrdcvtyp; /* virtual device type (output) */ | ||
| 29 | u8 vrdcvsta; /* virtual device status (output) */ | ||
| 30 | u8 vrdcvfla; /* virtual device flags (output) */ | ||
| 31 | u8 vrdcrccl; /* real device class (output) */ | ||
| 32 | u8 vrdccrty; /* real device type (output) */ | ||
| 33 | u8 vrdccrmd; /* real device model (output) */ | ||
| 34 | u8 vrdccrft; /* real device feature (output) */ | ||
| 35 | } __attribute__((packed, aligned(4))); | ||
| 36 | |||
| 37 | extern int diag210(struct diag210 *addr); | ||
| 38 | |||
| 39 | #endif /* _ASM_S390_DIAG_H */ | ||
diff --git a/include/asm-s390/pgalloc.h b/include/asm-s390/pgalloc.h index 56c8a6c80e2e..e45d3c9a4b7e 100644 --- a/include/asm-s390/pgalloc.h +++ b/include/asm-s390/pgalloc.h | |||
| @@ -19,8 +19,6 @@ | |||
| 19 | 19 | ||
| 20 | #define check_pgt_cache() do {} while (0) | 20 | #define check_pgt_cache() do {} while (0) |
| 21 | 21 | ||
| 22 | extern void diag10(unsigned long addr); | ||
| 23 | |||
| 24 | /* | 22 | /* |
| 25 | * Page allocation orders. | 23 | * Page allocation orders. |
| 26 | */ | 24 | */ |
