aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@woody.linux-foundation.org>2007-08-22 14:12:08 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-08-22 14:12:08 -0400
commit53ce2dc2718c57346c543dab254fc900c6fe6c65 (patch)
tree451fcbc89084b1d9b83c105294794f29bf6d59f3
parent8b14cb9953c6b569327e9372718cff09a98f9589 (diff)
parentc51b9621796c31810fb66509ea1faee4597d9c03 (diff)
Merge branch 'for-linus' of git://git390.osdl.marist.edu/pub/scm/linux-2.6
* 'for-linus' of git://git390.osdl.marist.edu/pub/scm/linux-2.6: [S390] Change atomic_read/set to inline functions with barrier semantics. [S390] kprobes: fix instruction length calculation [S390] hypfs: inode corruption due to missing locking [S390] disassembler: fix b2 opcodes like srst, bsg, and others [S390] vmur: fix reference counting for vmur device structure [S390] vmur: fix diag14 exceptions with addresses > 2GB. [S390] qdio: Refresh buffer states for IQDIO Asynchronous output queue [S390] qdio: fix EQBS handling on CCQ96 [S390] cio: change confusing message in cmf. [S390] cio: dont forget to set last slot to NULL in ccw_uevent().
-rw-r--r--arch/s390/hypfs/inode.c33
-rw-r--r--arch/s390/kernel/Makefile2
-rw-r--r--arch/s390/kernel/diag.c102
-rw-r--r--arch/s390/kernel/dis.c2
-rw-r--r--arch/s390/kernel/kprobes.c2
-rw-r--r--arch/s390/kernel/s390_ksyms.c1
-rw-r--r--arch/s390/mm/cmm.c1
-rw-r--r--arch/s390/mm/init.c17
-rw-r--r--drivers/s390/block/dasd_diag.c1
-rw-r--r--drivers/s390/char/raw3270.c1
-rw-r--r--drivers/s390/char/vmur.c250
-rw-r--r--drivers/s390/char/vmur.h1
-rw-r--r--drivers/s390/cio/cmf.c10
-rw-r--r--drivers/s390/cio/device.c5
-rw-r--r--drivers/s390/cio/device_id.c48
-rw-r--r--drivers/s390/cio/qdio.c5
-rw-r--r--include/asm-s390/atomic.h26
-rw-r--r--include/asm-s390/cio.h15
-rw-r--r--include/asm-s390/diag.h39
-rw-r--r--include/asm-s390/pgalloc.h2
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
63static inline int hypfs_positive(struct dentry *dentry)
64{
65 return dentry->d_inode && !d_unhashed(dentry);
66}
67
63static void hypfs_remove(struct dentry *dentry) 68static 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
76static void hypfs_delete_tree(struct dentry *root) 87static 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
320err_tree: 332err_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);
398fail:
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
7obj-y := bitmap.o traps.o time.o process.o base.o early.o \ 7obj-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
11obj-y += $(if $(CONFIG_64BIT),entry64.o,entry.o) 11obj-y += $(if $(CONFIG_64BIT),entry64.o,entry.o)
12obj-y += $(if $(CONFIG_64BIT),reipl64.o,reipl.o) 12obj-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 */
14void 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}
30EXPORT_SYMBOL(diag10);
31
32/*
33 * Diagnose 14: Input spool file manipulation
34 */
35int 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}
57EXPORT_SYMBOL(diag14);
58
59/*
60 * Diagnose 210: Get information about a virtual device
61 */
62int 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}
102EXPORT_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);
25EXPORT_SYMBOL(_ni_bitmap); 25EXPORT_SYMBOL(_ni_bitmap);
26EXPORT_SYMBOL(_zb_findmap); 26EXPORT_SYMBOL(_zb_findmap);
27EXPORT_SYMBOL(_sb_findmap); 27EXPORT_SYMBOL(_sb_findmap);
28EXPORT_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
24static char *sender = "VMRMSVM"; 25static char *sender = "VMRMSVM";
25module_param(sender, charp, 0400); 26module_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);
42pgd_t swapper_pg_dir[PTRS_PER_PGD] __attribute__((__aligned__(PAGE_SIZE))); 42pgd_t swapper_pg_dir[PTRS_PER_PGD] __attribute__((__aligned__(PAGE_SIZE)));
43char empty_zero_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE))); 43char empty_zero_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
44 44
45void 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
62void show_mem(void) 45void 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
72static 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 */
74static struct urdev *urdev_alloc(struct ccw_device *cdev) 93static 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
89static void urdev_free(struct urdev *urd) 110static 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/* 118static 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(). 123static 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
101static struct urdev *urdev_get_from_devno(u16 devno) 136static 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
114static void urdev_put(struct urdev *urd) 151static 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,
262static ssize_t ur_attr_reclen_show(struct device *dev, 301static 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
270static DEVICE_ATTR(reclen, 0444, ur_attr_reclen_show, NULL); 315static 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
382static 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 */
759static int ur_probe(struct ccw_device *cdev) 785static 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
795fail: 823fail_remove_attr:
796 urdev_free(urd);
797 put_device(&cdev->dev);
798 return rc;
799}
800
801static 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); 825fail_urdev_put:
810 put_device(&cdev->dev); 826 urdev_put(urd);
827fail_unlock:
828 mutex_unlock(&vmur_mutex);
829 return rc;
811} 830}
812 831
813static int ur_set_online(struct ccw_device *cdev) 832static 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
864fail_free_cdev: 893fail_free_cdev:
865 cdev_del(urd->char_device); 894 cdev_del(urd->char_device);
866fail_module_put: 895 urd->char_device = NULL;
867 module_put(ur_driver.owner); 896fail_urdev_put:
868 897 urdev_put(urd);
898fail_unlock:
899 mutex_unlock(&vmur_mutex);
869 return rc; 900 return rc;
870} 901}
871 902
872static int ur_set_offline(struct ccw_device *cdev) 903static 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; 929fail_urdev_put:
930 urdev_put(urd);
931 return rc;
932}
933
934static 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
944static 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
123struct bus_type ccw_bus_type; 126struct 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 */
30int
31diag210(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
353EXPORT_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,
195again: 195again:
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
746check_next: 749check_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) 70static 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
76static inline void atomic_set(atomic_t *v, int i)
77{
78 v->counter = i;
79 barrier();
80}
72 81
73static __inline__ int atomic_add_return(int i, atomic_t * v) 82static __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) 194static 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
200static inline void atomic64_set(atomic64_t *v, long long i)
201{
202 v->counter = i;
203 barrier();
204}
187 205
188static __inline__ long long atomic64_add_return(long long i, atomic64_t * v) 206static __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
261struct 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
274struct ccw_dev_id { 261struct 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
288extern int diag210(struct diag210 *addr);
289
290extern void wait_cons_dev(void); 275extern void wait_cons_dev(void);
291 276
292extern void css_schedule_reprobe(void); 277extern 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 */
14extern void diag10(unsigned long addr);
15
16/*
17 * Diagnose 14: Input spool file manipulation
18 */
19extern int diag14(unsigned long rx, unsigned long ry1, unsigned long subcode);
20
21/*
22 * Diagnose 210: Get information about a virtual device
23 */
24struct 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
37extern 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
22extern void diag10(unsigned long addr);
23
24/* 22/*
25 * Page allocation orders. 23 * Page allocation orders.
26 */ 24 */