diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/core/skbuff.c | 8 | ||||
-rw-r--r-- | net/core/sock.c | 2 | ||||
-rw-r--r-- | net/ipv4/inet_timewait_sock.c | 3 | ||||
-rw-r--r-- | net/iucv/af_iucv.c | 147 | ||||
-rw-r--r-- | net/iucv/iucv.c | 268 |
5 files changed, 423 insertions, 5 deletions
diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 1a94a3037370..5c93435b0347 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c | |||
@@ -39,6 +39,7 @@ | |||
39 | #include <linux/module.h> | 39 | #include <linux/module.h> |
40 | #include <linux/types.h> | 40 | #include <linux/types.h> |
41 | #include <linux/kernel.h> | 41 | #include <linux/kernel.h> |
42 | #include <linux/kmemcheck.h> | ||
42 | #include <linux/mm.h> | 43 | #include <linux/mm.h> |
43 | #include <linux/interrupt.h> | 44 | #include <linux/interrupt.h> |
44 | #include <linux/in.h> | 45 | #include <linux/in.h> |
@@ -201,6 +202,8 @@ struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask, | |||
201 | skb->data = data; | 202 | skb->data = data; |
202 | skb_reset_tail_pointer(skb); | 203 | skb_reset_tail_pointer(skb); |
203 | skb->end = skb->tail + size; | 204 | skb->end = skb->tail + size; |
205 | kmemcheck_annotate_bitfield(skb, flags1); | ||
206 | kmemcheck_annotate_bitfield(skb, flags2); | ||
204 | /* make sure we initialize shinfo sequentially */ | 207 | /* make sure we initialize shinfo sequentially */ |
205 | shinfo = skb_shinfo(skb); | 208 | shinfo = skb_shinfo(skb); |
206 | atomic_set(&shinfo->dataref, 1); | 209 | atomic_set(&shinfo->dataref, 1); |
@@ -217,6 +220,8 @@ struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask, | |||
217 | struct sk_buff *child = skb + 1; | 220 | struct sk_buff *child = skb + 1; |
218 | atomic_t *fclone_ref = (atomic_t *) (child + 1); | 221 | atomic_t *fclone_ref = (atomic_t *) (child + 1); |
219 | 222 | ||
223 | kmemcheck_annotate_bitfield(child, flags1); | ||
224 | kmemcheck_annotate_bitfield(child, flags2); | ||
220 | skb->fclone = SKB_FCLONE_ORIG; | 225 | skb->fclone = SKB_FCLONE_ORIG; |
221 | atomic_set(fclone_ref, 1); | 226 | atomic_set(fclone_ref, 1); |
222 | 227 | ||
@@ -635,6 +640,9 @@ struct sk_buff *skb_clone(struct sk_buff *skb, gfp_t gfp_mask) | |||
635 | n = kmem_cache_alloc(skbuff_head_cache, gfp_mask); | 640 | n = kmem_cache_alloc(skbuff_head_cache, gfp_mask); |
636 | if (!n) | 641 | if (!n) |
637 | return NULL; | 642 | return NULL; |
643 | |||
644 | kmemcheck_annotate_bitfield(n, flags1); | ||
645 | kmemcheck_annotate_bitfield(n, flags2); | ||
638 | n->fclone = SKB_FCLONE_UNAVAILABLE; | 646 | n->fclone = SKB_FCLONE_UNAVAILABLE; |
639 | } | 647 | } |
640 | 648 | ||
diff --git a/net/core/sock.c b/net/core/sock.c index 06e26b77ad9e..b0ba569bc973 100644 --- a/net/core/sock.c +++ b/net/core/sock.c | |||
@@ -945,6 +945,8 @@ static struct sock *sk_prot_alloc(struct proto *prot, gfp_t priority, | |||
945 | sk = kmalloc(prot->obj_size, priority); | 945 | sk = kmalloc(prot->obj_size, priority); |
946 | 946 | ||
947 | if (sk != NULL) { | 947 | if (sk != NULL) { |
948 | kmemcheck_annotate_bitfield(sk, flags); | ||
949 | |||
948 | if (security_sk_alloc(sk, family, priority)) | 950 | if (security_sk_alloc(sk, family, priority)) |
949 | goto out_free; | 951 | goto out_free; |
950 | 952 | ||
diff --git a/net/ipv4/inet_timewait_sock.c b/net/ipv4/inet_timewait_sock.c index 68a8d892c711..61283f928825 100644 --- a/net/ipv4/inet_timewait_sock.c +++ b/net/ipv4/inet_timewait_sock.c | |||
@@ -9,6 +9,7 @@ | |||
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/kernel.h> | 11 | #include <linux/kernel.h> |
12 | #include <linux/kmemcheck.h> | ||
12 | #include <net/inet_hashtables.h> | 13 | #include <net/inet_hashtables.h> |
13 | #include <net/inet_timewait_sock.h> | 14 | #include <net/inet_timewait_sock.h> |
14 | #include <net/ip.h> | 15 | #include <net/ip.h> |
@@ -120,6 +121,8 @@ struct inet_timewait_sock *inet_twsk_alloc(const struct sock *sk, const int stat | |||
120 | if (tw != NULL) { | 121 | if (tw != NULL) { |
121 | const struct inet_sock *inet = inet_sk(sk); | 122 | const struct inet_sock *inet = inet_sk(sk); |
122 | 123 | ||
124 | kmemcheck_annotate_bitfield(tw, flags); | ||
125 | |||
123 | /* Give us an identity. */ | 126 | /* Give us an identity. */ |
124 | tw->tw_daddr = inet->daddr; | 127 | tw->tw_daddr = inet->daddr; |
125 | tw->tw_rcv_saddr = inet->rcv_saddr; | 128 | tw->tw_rcv_saddr = inet->rcv_saddr; |
diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c index a9b3a6f9ea95..656cbd195825 100644 --- a/net/iucv/af_iucv.c +++ b/net/iucv/af_iucv.c | |||
@@ -1,11 +1,12 @@ | |||
1 | /* | 1 | /* |
2 | * linux/net/iucv/af_iucv.c | ||
3 | * | ||
4 | * IUCV protocol stack for Linux on zSeries | 2 | * IUCV protocol stack for Linux on zSeries |
5 | * | 3 | * |
6 | * Copyright 2006 IBM Corporation | 4 | * Copyright IBM Corp. 2006, 2009 |
7 | * | 5 | * |
8 | * Author(s): Jennifer Hunt <jenhunt@us.ibm.com> | 6 | * Author(s): Jennifer Hunt <jenhunt@us.ibm.com> |
7 | * Hendrik Brueckner <brueckner@linux.vnet.ibm.com> | ||
8 | * PM functions: | ||
9 | * Ursula Braun <ursula.braun@de.ibm.com> | ||
9 | */ | 10 | */ |
10 | 11 | ||
11 | #define KMSG_COMPONENT "af_iucv" | 12 | #define KMSG_COMPONENT "af_iucv" |
@@ -90,6 +91,122 @@ static inline void low_nmcpy(unsigned char *dst, char *src) | |||
90 | memcpy(&dst[8], src, 8); | 91 | memcpy(&dst[8], src, 8); |
91 | } | 92 | } |
92 | 93 | ||
94 | static int afiucv_pm_prepare(struct device *dev) | ||
95 | { | ||
96 | #ifdef CONFIG_PM_DEBUG | ||
97 | printk(KERN_WARNING "afiucv_pm_prepare\n"); | ||
98 | #endif | ||
99 | return 0; | ||
100 | } | ||
101 | |||
102 | static void afiucv_pm_complete(struct device *dev) | ||
103 | { | ||
104 | #ifdef CONFIG_PM_DEBUG | ||
105 | printk(KERN_WARNING "afiucv_pm_complete\n"); | ||
106 | #endif | ||
107 | return; | ||
108 | } | ||
109 | |||
110 | /** | ||
111 | * afiucv_pm_freeze() - Freeze PM callback | ||
112 | * @dev: AFIUCV dummy device | ||
113 | * | ||
114 | * Sever all established IUCV communication pathes | ||
115 | */ | ||
116 | static int afiucv_pm_freeze(struct device *dev) | ||
117 | { | ||
118 | struct iucv_sock *iucv; | ||
119 | struct sock *sk; | ||
120 | struct hlist_node *node; | ||
121 | int err = 0; | ||
122 | |||
123 | #ifdef CONFIG_PM_DEBUG | ||
124 | printk(KERN_WARNING "afiucv_pm_freeze\n"); | ||
125 | #endif | ||
126 | read_lock(&iucv_sk_list.lock); | ||
127 | sk_for_each(sk, node, &iucv_sk_list.head) { | ||
128 | iucv = iucv_sk(sk); | ||
129 | skb_queue_purge(&iucv->send_skb_q); | ||
130 | skb_queue_purge(&iucv->backlog_skb_q); | ||
131 | switch (sk->sk_state) { | ||
132 | case IUCV_SEVERED: | ||
133 | case IUCV_DISCONN: | ||
134 | case IUCV_CLOSING: | ||
135 | case IUCV_CONNECTED: | ||
136 | if (iucv->path) { | ||
137 | err = iucv_path_sever(iucv->path, NULL); | ||
138 | iucv_path_free(iucv->path); | ||
139 | iucv->path = NULL; | ||
140 | } | ||
141 | break; | ||
142 | case IUCV_OPEN: | ||
143 | case IUCV_BOUND: | ||
144 | case IUCV_LISTEN: | ||
145 | case IUCV_CLOSED: | ||
146 | default: | ||
147 | break; | ||
148 | } | ||
149 | } | ||
150 | read_unlock(&iucv_sk_list.lock); | ||
151 | return err; | ||
152 | } | ||
153 | |||
154 | /** | ||
155 | * afiucv_pm_restore_thaw() - Thaw and restore PM callback | ||
156 | * @dev: AFIUCV dummy device | ||
157 | * | ||
158 | * socket clean up after freeze | ||
159 | */ | ||
160 | static int afiucv_pm_restore_thaw(struct device *dev) | ||
161 | { | ||
162 | struct iucv_sock *iucv; | ||
163 | struct sock *sk; | ||
164 | struct hlist_node *node; | ||
165 | |||
166 | #ifdef CONFIG_PM_DEBUG | ||
167 | printk(KERN_WARNING "afiucv_pm_restore_thaw\n"); | ||
168 | #endif | ||
169 | read_lock(&iucv_sk_list.lock); | ||
170 | sk_for_each(sk, node, &iucv_sk_list.head) { | ||
171 | iucv = iucv_sk(sk); | ||
172 | switch (sk->sk_state) { | ||
173 | case IUCV_CONNECTED: | ||
174 | sk->sk_err = EPIPE; | ||
175 | sk->sk_state = IUCV_DISCONN; | ||
176 | sk->sk_state_change(sk); | ||
177 | break; | ||
178 | case IUCV_DISCONN: | ||
179 | case IUCV_SEVERED: | ||
180 | case IUCV_CLOSING: | ||
181 | case IUCV_LISTEN: | ||
182 | case IUCV_BOUND: | ||
183 | case IUCV_OPEN: | ||
184 | default: | ||
185 | break; | ||
186 | } | ||
187 | } | ||
188 | read_unlock(&iucv_sk_list.lock); | ||
189 | return 0; | ||
190 | } | ||
191 | |||
192 | static struct dev_pm_ops afiucv_pm_ops = { | ||
193 | .prepare = afiucv_pm_prepare, | ||
194 | .complete = afiucv_pm_complete, | ||
195 | .freeze = afiucv_pm_freeze, | ||
196 | .thaw = afiucv_pm_restore_thaw, | ||
197 | .restore = afiucv_pm_restore_thaw, | ||
198 | }; | ||
199 | |||
200 | static struct device_driver af_iucv_driver = { | ||
201 | .owner = THIS_MODULE, | ||
202 | .name = "afiucv", | ||
203 | .bus = &iucv_bus, | ||
204 | .pm = &afiucv_pm_ops, | ||
205 | }; | ||
206 | |||
207 | /* dummy device used as trigger for PM functions */ | ||
208 | static struct device *af_iucv_dev; | ||
209 | |||
93 | /** | 210 | /** |
94 | * iucv_msg_length() - Returns the length of an iucv message. | 211 | * iucv_msg_length() - Returns the length of an iucv message. |
95 | * @msg: Pointer to struct iucv_message, MUST NOT be NULL | 212 | * @msg: Pointer to struct iucv_message, MUST NOT be NULL |
@@ -1556,8 +1673,30 @@ static int __init afiucv_init(void) | |||
1556 | err = sock_register(&iucv_sock_family_ops); | 1673 | err = sock_register(&iucv_sock_family_ops); |
1557 | if (err) | 1674 | if (err) |
1558 | goto out_proto; | 1675 | goto out_proto; |
1676 | /* establish dummy device */ | ||
1677 | err = driver_register(&af_iucv_driver); | ||
1678 | if (err) | ||
1679 | goto out_sock; | ||
1680 | af_iucv_dev = kzalloc(sizeof(struct device), GFP_KERNEL); | ||
1681 | if (!af_iucv_dev) { | ||
1682 | err = -ENOMEM; | ||
1683 | goto out_driver; | ||
1684 | } | ||
1685 | dev_set_name(af_iucv_dev, "af_iucv"); | ||
1686 | af_iucv_dev->bus = &iucv_bus; | ||
1687 | af_iucv_dev->parent = iucv_root; | ||
1688 | af_iucv_dev->release = (void (*)(struct device *))kfree; | ||
1689 | af_iucv_dev->driver = &af_iucv_driver; | ||
1690 | err = device_register(af_iucv_dev); | ||
1691 | if (err) | ||
1692 | goto out_driver; | ||
1693 | |||
1559 | return 0; | 1694 | return 0; |
1560 | 1695 | ||
1696 | out_driver: | ||
1697 | driver_unregister(&af_iucv_driver); | ||
1698 | out_sock: | ||
1699 | sock_unregister(PF_IUCV); | ||
1561 | out_proto: | 1700 | out_proto: |
1562 | proto_unregister(&iucv_proto); | 1701 | proto_unregister(&iucv_proto); |
1563 | out_iucv: | 1702 | out_iucv: |
@@ -1568,6 +1707,8 @@ out: | |||
1568 | 1707 | ||
1569 | static void __exit afiucv_exit(void) | 1708 | static void __exit afiucv_exit(void) |
1570 | { | 1709 | { |
1710 | device_unregister(af_iucv_dev); | ||
1711 | driver_unregister(&af_iucv_driver); | ||
1571 | sock_unregister(PF_IUCV); | 1712 | sock_unregister(PF_IUCV); |
1572 | proto_unregister(&iucv_proto); | 1713 | proto_unregister(&iucv_proto); |
1573 | iucv_unregister(&af_iucv_handler, 0); | 1714 | iucv_unregister(&af_iucv_handler, 0); |
diff --git a/net/iucv/iucv.c b/net/iucv/iucv.c index 61e8038a55ee..c833481d32e3 100644 --- a/net/iucv/iucv.c +++ b/net/iucv/iucv.c | |||
@@ -1,7 +1,8 @@ | |||
1 | /* | 1 | /* |
2 | * IUCV base infrastructure. | 2 | * IUCV base infrastructure. |
3 | * | 3 | * |
4 | * Copyright 2001, 2006 IBM Deutschland Entwicklung GmbH, IBM Corporation | 4 | * Copyright IBM Corp. 2001, 2009 |
5 | * | ||
5 | * Author(s): | 6 | * Author(s): |
6 | * Original source: | 7 | * Original source: |
7 | * Alan Altmark (Alan_Altmark@us.ibm.com) Sept. 2000 | 8 | * Alan Altmark (Alan_Altmark@us.ibm.com) Sept. 2000 |
@@ -10,6 +11,8 @@ | |||
10 | * Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com) | 11 | * Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com) |
11 | * Rewritten for af_iucv: | 12 | * Rewritten for af_iucv: |
12 | * Martin Schwidefsky <schwidefsky@de.ibm.com> | 13 | * Martin Schwidefsky <schwidefsky@de.ibm.com> |
14 | * PM functions: | ||
15 | * Ursula Braun (ursula.braun@de.ibm.com) | ||
13 | * | 16 | * |
14 | * Documentation used: | 17 | * Documentation used: |
15 | * The original source | 18 | * The original source |
@@ -45,6 +48,7 @@ | |||
45 | #include <linux/err.h> | 48 | #include <linux/err.h> |
46 | #include <linux/device.h> | 49 | #include <linux/device.h> |
47 | #include <linux/cpu.h> | 50 | #include <linux/cpu.h> |
51 | #include <linux/reboot.h> | ||
48 | #include <net/iucv/iucv.h> | 52 | #include <net/iucv/iucv.h> |
49 | #include <asm/atomic.h> | 53 | #include <asm/atomic.h> |
50 | #include <asm/ebcdic.h> | 54 | #include <asm/ebcdic.h> |
@@ -75,9 +79,24 @@ static int iucv_bus_match(struct device *dev, struct device_driver *drv) | |||
75 | return 0; | 79 | return 0; |
76 | } | 80 | } |
77 | 81 | ||
82 | static int iucv_pm_prepare(struct device *); | ||
83 | static void iucv_pm_complete(struct device *); | ||
84 | static int iucv_pm_freeze(struct device *); | ||
85 | static int iucv_pm_thaw(struct device *); | ||
86 | static int iucv_pm_restore(struct device *); | ||
87 | |||
88 | static struct dev_pm_ops iucv_pm_ops = { | ||
89 | .prepare = iucv_pm_prepare, | ||
90 | .complete = iucv_pm_complete, | ||
91 | .freeze = iucv_pm_freeze, | ||
92 | .thaw = iucv_pm_thaw, | ||
93 | .restore = iucv_pm_restore, | ||
94 | }; | ||
95 | |||
78 | struct bus_type iucv_bus = { | 96 | struct bus_type iucv_bus = { |
79 | .name = "iucv", | 97 | .name = "iucv", |
80 | .match = iucv_bus_match, | 98 | .match = iucv_bus_match, |
99 | .pm = &iucv_pm_ops, | ||
81 | }; | 100 | }; |
82 | EXPORT_SYMBOL(iucv_bus); | 101 | EXPORT_SYMBOL(iucv_bus); |
83 | 102 | ||
@@ -147,6 +166,7 @@ enum iucv_command_codes { | |||
147 | IUCV_RESUME = 14, | 166 | IUCV_RESUME = 14, |
148 | IUCV_SEVER = 15, | 167 | IUCV_SEVER = 15, |
149 | IUCV_SETMASK = 16, | 168 | IUCV_SETMASK = 16, |
169 | IUCV_SETCONTROLMASK = 17, | ||
150 | }; | 170 | }; |
151 | 171 | ||
152 | /* | 172 | /* |
@@ -364,6 +384,18 @@ static void iucv_allow_cpu(void *data) | |||
364 | parm->set_mask.ipmask = 0xf8; | 384 | parm->set_mask.ipmask = 0xf8; |
365 | iucv_call_b2f0(IUCV_SETMASK, parm); | 385 | iucv_call_b2f0(IUCV_SETMASK, parm); |
366 | 386 | ||
387 | /* | ||
388 | * Enable all iucv control interrupts. | ||
389 | * ipmask contains bits for the different interrupts | ||
390 | * 0x80 - Flag to allow pending connections interrupts | ||
391 | * 0x40 - Flag to allow connection complete interrupts | ||
392 | * 0x20 - Flag to allow connection severed interrupts | ||
393 | * 0x10 - Flag to allow connection quiesced interrupts | ||
394 | * 0x08 - Flag to allow connection resumed interrupts | ||
395 | */ | ||
396 | memset(parm, 0, sizeof(union iucv_param)); | ||
397 | parm->set_mask.ipmask = 0xf8; | ||
398 | iucv_call_b2f0(IUCV_SETCONTROLMASK, parm); | ||
367 | /* Set indication that iucv interrupts are allowed for this cpu. */ | 399 | /* Set indication that iucv interrupts are allowed for this cpu. */ |
368 | cpu_set(cpu, iucv_irq_cpumask); | 400 | cpu_set(cpu, iucv_irq_cpumask); |
369 | } | 401 | } |
@@ -389,6 +421,31 @@ static void iucv_block_cpu(void *data) | |||
389 | } | 421 | } |
390 | 422 | ||
391 | /** | 423 | /** |
424 | * iucv_block_cpu_almost | ||
425 | * @data: unused | ||
426 | * | ||
427 | * Allow connection-severed interrupts only on this cpu. | ||
428 | */ | ||
429 | static void iucv_block_cpu_almost(void *data) | ||
430 | { | ||
431 | int cpu = smp_processor_id(); | ||
432 | union iucv_param *parm; | ||
433 | |||
434 | /* Allow iucv control interrupts only */ | ||
435 | parm = iucv_param_irq[cpu]; | ||
436 | memset(parm, 0, sizeof(union iucv_param)); | ||
437 | parm->set_mask.ipmask = 0x08; | ||
438 | iucv_call_b2f0(IUCV_SETMASK, parm); | ||
439 | /* Allow iucv-severed interrupt only */ | ||
440 | memset(parm, 0, sizeof(union iucv_param)); | ||
441 | parm->set_mask.ipmask = 0x20; | ||
442 | iucv_call_b2f0(IUCV_SETCONTROLMASK, parm); | ||
443 | |||
444 | /* Clear indication that iucv interrupts are allowed for this cpu. */ | ||
445 | cpu_clear(cpu, iucv_irq_cpumask); | ||
446 | } | ||
447 | |||
448 | /** | ||
392 | * iucv_declare_cpu | 449 | * iucv_declare_cpu |
393 | * @data: unused | 450 | * @data: unused |
394 | * | 451 | * |
@@ -758,6 +815,28 @@ void iucv_unregister(struct iucv_handler *handler, int smp) | |||
758 | } | 815 | } |
759 | EXPORT_SYMBOL(iucv_unregister); | 816 | EXPORT_SYMBOL(iucv_unregister); |
760 | 817 | ||
818 | static int iucv_reboot_event(struct notifier_block *this, | ||
819 | unsigned long event, void *ptr) | ||
820 | { | ||
821 | int i, rc; | ||
822 | |||
823 | get_online_cpus(); | ||
824 | on_each_cpu(iucv_block_cpu, NULL, 1); | ||
825 | preempt_disable(); | ||
826 | for (i = 0; i < iucv_max_pathid; i++) { | ||
827 | if (iucv_path_table[i]) | ||
828 | rc = iucv_sever_pathid(i, NULL); | ||
829 | } | ||
830 | preempt_enable(); | ||
831 | put_online_cpus(); | ||
832 | iucv_disable(); | ||
833 | return NOTIFY_DONE; | ||
834 | } | ||
835 | |||
836 | static struct notifier_block iucv_reboot_notifier = { | ||
837 | .notifier_call = iucv_reboot_event, | ||
838 | }; | ||
839 | |||
761 | /** | 840 | /** |
762 | * iucv_path_accept | 841 | * iucv_path_accept |
763 | * @path: address of iucv path structure | 842 | * @path: address of iucv path structure |
@@ -777,6 +856,10 @@ int iucv_path_accept(struct iucv_path *path, struct iucv_handler *handler, | |||
777 | int rc; | 856 | int rc; |
778 | 857 | ||
779 | local_bh_disable(); | 858 | local_bh_disable(); |
859 | if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) { | ||
860 | rc = -EIO; | ||
861 | goto out; | ||
862 | } | ||
780 | /* Prepare parameter block. */ | 863 | /* Prepare parameter block. */ |
781 | parm = iucv_param[smp_processor_id()]; | 864 | parm = iucv_param[smp_processor_id()]; |
782 | memset(parm, 0, sizeof(union iucv_param)); | 865 | memset(parm, 0, sizeof(union iucv_param)); |
@@ -792,6 +875,7 @@ int iucv_path_accept(struct iucv_path *path, struct iucv_handler *handler, | |||
792 | path->msglim = parm->ctrl.ipmsglim; | 875 | path->msglim = parm->ctrl.ipmsglim; |
793 | path->flags = parm->ctrl.ipflags1; | 876 | path->flags = parm->ctrl.ipflags1; |
794 | } | 877 | } |
878 | out: | ||
795 | local_bh_enable(); | 879 | local_bh_enable(); |
796 | return rc; | 880 | return rc; |
797 | } | 881 | } |
@@ -821,6 +905,10 @@ int iucv_path_connect(struct iucv_path *path, struct iucv_handler *handler, | |||
821 | 905 | ||
822 | spin_lock_bh(&iucv_table_lock); | 906 | spin_lock_bh(&iucv_table_lock); |
823 | iucv_cleanup_queue(); | 907 | iucv_cleanup_queue(); |
908 | if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) { | ||
909 | rc = -EIO; | ||
910 | goto out; | ||
911 | } | ||
824 | parm = iucv_param[smp_processor_id()]; | 912 | parm = iucv_param[smp_processor_id()]; |
825 | memset(parm, 0, sizeof(union iucv_param)); | 913 | memset(parm, 0, sizeof(union iucv_param)); |
826 | parm->ctrl.ipmsglim = path->msglim; | 914 | parm->ctrl.ipmsglim = path->msglim; |
@@ -855,6 +943,7 @@ int iucv_path_connect(struct iucv_path *path, struct iucv_handler *handler, | |||
855 | rc = -EIO; | 943 | rc = -EIO; |
856 | } | 944 | } |
857 | } | 945 | } |
946 | out: | ||
858 | spin_unlock_bh(&iucv_table_lock); | 947 | spin_unlock_bh(&iucv_table_lock); |
859 | return rc; | 948 | return rc; |
860 | } | 949 | } |
@@ -876,12 +965,17 @@ int iucv_path_quiesce(struct iucv_path *path, u8 userdata[16]) | |||
876 | int rc; | 965 | int rc; |
877 | 966 | ||
878 | local_bh_disable(); | 967 | local_bh_disable(); |
968 | if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) { | ||
969 | rc = -EIO; | ||
970 | goto out; | ||
971 | } | ||
879 | parm = iucv_param[smp_processor_id()]; | 972 | parm = iucv_param[smp_processor_id()]; |
880 | memset(parm, 0, sizeof(union iucv_param)); | 973 | memset(parm, 0, sizeof(union iucv_param)); |
881 | if (userdata) | 974 | if (userdata) |
882 | memcpy(parm->ctrl.ipuser, userdata, sizeof(parm->ctrl.ipuser)); | 975 | memcpy(parm->ctrl.ipuser, userdata, sizeof(parm->ctrl.ipuser)); |
883 | parm->ctrl.ippathid = path->pathid; | 976 | parm->ctrl.ippathid = path->pathid; |
884 | rc = iucv_call_b2f0(IUCV_QUIESCE, parm); | 977 | rc = iucv_call_b2f0(IUCV_QUIESCE, parm); |
978 | out: | ||
885 | local_bh_enable(); | 979 | local_bh_enable(); |
886 | return rc; | 980 | return rc; |
887 | } | 981 | } |
@@ -903,12 +997,17 @@ int iucv_path_resume(struct iucv_path *path, u8 userdata[16]) | |||
903 | int rc; | 997 | int rc; |
904 | 998 | ||
905 | local_bh_disable(); | 999 | local_bh_disable(); |
1000 | if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) { | ||
1001 | rc = -EIO; | ||
1002 | goto out; | ||
1003 | } | ||
906 | parm = iucv_param[smp_processor_id()]; | 1004 | parm = iucv_param[smp_processor_id()]; |
907 | memset(parm, 0, sizeof(union iucv_param)); | 1005 | memset(parm, 0, sizeof(union iucv_param)); |
908 | if (userdata) | 1006 | if (userdata) |
909 | memcpy(parm->ctrl.ipuser, userdata, sizeof(parm->ctrl.ipuser)); | 1007 | memcpy(parm->ctrl.ipuser, userdata, sizeof(parm->ctrl.ipuser)); |
910 | parm->ctrl.ippathid = path->pathid; | 1008 | parm->ctrl.ippathid = path->pathid; |
911 | rc = iucv_call_b2f0(IUCV_RESUME, parm); | 1009 | rc = iucv_call_b2f0(IUCV_RESUME, parm); |
1010 | out: | ||
912 | local_bh_enable(); | 1011 | local_bh_enable(); |
913 | return rc; | 1012 | return rc; |
914 | } | 1013 | } |
@@ -927,6 +1026,10 @@ int iucv_path_sever(struct iucv_path *path, u8 userdata[16]) | |||
927 | int rc; | 1026 | int rc; |
928 | 1027 | ||
929 | preempt_disable(); | 1028 | preempt_disable(); |
1029 | if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) { | ||
1030 | rc = -EIO; | ||
1031 | goto out; | ||
1032 | } | ||
930 | if (iucv_active_cpu != smp_processor_id()) | 1033 | if (iucv_active_cpu != smp_processor_id()) |
931 | spin_lock_bh(&iucv_table_lock); | 1034 | spin_lock_bh(&iucv_table_lock); |
932 | rc = iucv_sever_pathid(path->pathid, userdata); | 1035 | rc = iucv_sever_pathid(path->pathid, userdata); |
@@ -934,6 +1037,7 @@ int iucv_path_sever(struct iucv_path *path, u8 userdata[16]) | |||
934 | list_del_init(&path->list); | 1037 | list_del_init(&path->list); |
935 | if (iucv_active_cpu != smp_processor_id()) | 1038 | if (iucv_active_cpu != smp_processor_id()) |
936 | spin_unlock_bh(&iucv_table_lock); | 1039 | spin_unlock_bh(&iucv_table_lock); |
1040 | out: | ||
937 | preempt_enable(); | 1041 | preempt_enable(); |
938 | return rc; | 1042 | return rc; |
939 | } | 1043 | } |
@@ -956,6 +1060,10 @@ int iucv_message_purge(struct iucv_path *path, struct iucv_message *msg, | |||
956 | int rc; | 1060 | int rc; |
957 | 1061 | ||
958 | local_bh_disable(); | 1062 | local_bh_disable(); |
1063 | if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) { | ||
1064 | rc = -EIO; | ||
1065 | goto out; | ||
1066 | } | ||
959 | parm = iucv_param[smp_processor_id()]; | 1067 | parm = iucv_param[smp_processor_id()]; |
960 | memset(parm, 0, sizeof(union iucv_param)); | 1068 | memset(parm, 0, sizeof(union iucv_param)); |
961 | parm->purge.ippathid = path->pathid; | 1069 | parm->purge.ippathid = path->pathid; |
@@ -967,6 +1075,7 @@ int iucv_message_purge(struct iucv_path *path, struct iucv_message *msg, | |||
967 | msg->audit = (*(u32 *) &parm->purge.ipaudit) >> 8; | 1075 | msg->audit = (*(u32 *) &parm->purge.ipaudit) >> 8; |
968 | msg->tag = parm->purge.ipmsgtag; | 1076 | msg->tag = parm->purge.ipmsgtag; |
969 | } | 1077 | } |
1078 | out: | ||
970 | local_bh_enable(); | 1079 | local_bh_enable(); |
971 | return rc; | 1080 | return rc; |
972 | } | 1081 | } |
@@ -1043,6 +1152,10 @@ int __iucv_message_receive(struct iucv_path *path, struct iucv_message *msg, | |||
1043 | if (msg->flags & IUCV_IPRMDATA) | 1152 | if (msg->flags & IUCV_IPRMDATA) |
1044 | return iucv_message_receive_iprmdata(path, msg, flags, | 1153 | return iucv_message_receive_iprmdata(path, msg, flags, |
1045 | buffer, size, residual); | 1154 | buffer, size, residual); |
1155 | if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) { | ||
1156 | rc = -EIO; | ||
1157 | goto out; | ||
1158 | } | ||
1046 | parm = iucv_param[smp_processor_id()]; | 1159 | parm = iucv_param[smp_processor_id()]; |
1047 | memset(parm, 0, sizeof(union iucv_param)); | 1160 | memset(parm, 0, sizeof(union iucv_param)); |
1048 | parm->db.ipbfadr1 = (u32)(addr_t) buffer; | 1161 | parm->db.ipbfadr1 = (u32)(addr_t) buffer; |
@@ -1058,6 +1171,7 @@ int __iucv_message_receive(struct iucv_path *path, struct iucv_message *msg, | |||
1058 | if (residual) | 1171 | if (residual) |
1059 | *residual = parm->db.ipbfln1f; | 1172 | *residual = parm->db.ipbfln1f; |
1060 | } | 1173 | } |
1174 | out: | ||
1061 | return rc; | 1175 | return rc; |
1062 | } | 1176 | } |
1063 | EXPORT_SYMBOL(__iucv_message_receive); | 1177 | EXPORT_SYMBOL(__iucv_message_receive); |
@@ -1111,6 +1225,10 @@ int iucv_message_reject(struct iucv_path *path, struct iucv_message *msg) | |||
1111 | int rc; | 1225 | int rc; |
1112 | 1226 | ||
1113 | local_bh_disable(); | 1227 | local_bh_disable(); |
1228 | if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) { | ||
1229 | rc = -EIO; | ||
1230 | goto out; | ||
1231 | } | ||
1114 | parm = iucv_param[smp_processor_id()]; | 1232 | parm = iucv_param[smp_processor_id()]; |
1115 | memset(parm, 0, sizeof(union iucv_param)); | 1233 | memset(parm, 0, sizeof(union iucv_param)); |
1116 | parm->db.ippathid = path->pathid; | 1234 | parm->db.ippathid = path->pathid; |
@@ -1118,6 +1236,7 @@ int iucv_message_reject(struct iucv_path *path, struct iucv_message *msg) | |||
1118 | parm->db.iptrgcls = msg->class; | 1236 | parm->db.iptrgcls = msg->class; |
1119 | parm->db.ipflags1 = (IUCV_IPTRGCLS | IUCV_IPFGMID | IUCV_IPFGPID); | 1237 | parm->db.ipflags1 = (IUCV_IPTRGCLS | IUCV_IPFGMID | IUCV_IPFGPID); |
1120 | rc = iucv_call_b2f0(IUCV_REJECT, parm); | 1238 | rc = iucv_call_b2f0(IUCV_REJECT, parm); |
1239 | out: | ||
1121 | local_bh_enable(); | 1240 | local_bh_enable(); |
1122 | return rc; | 1241 | return rc; |
1123 | } | 1242 | } |
@@ -1145,6 +1264,10 @@ int iucv_message_reply(struct iucv_path *path, struct iucv_message *msg, | |||
1145 | int rc; | 1264 | int rc; |
1146 | 1265 | ||
1147 | local_bh_disable(); | 1266 | local_bh_disable(); |
1267 | if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) { | ||
1268 | rc = -EIO; | ||
1269 | goto out; | ||
1270 | } | ||
1148 | parm = iucv_param[smp_processor_id()]; | 1271 | parm = iucv_param[smp_processor_id()]; |
1149 | memset(parm, 0, sizeof(union iucv_param)); | 1272 | memset(parm, 0, sizeof(union iucv_param)); |
1150 | if (flags & IUCV_IPRMDATA) { | 1273 | if (flags & IUCV_IPRMDATA) { |
@@ -1162,6 +1285,7 @@ int iucv_message_reply(struct iucv_path *path, struct iucv_message *msg, | |||
1162 | parm->db.iptrgcls = msg->class; | 1285 | parm->db.iptrgcls = msg->class; |
1163 | } | 1286 | } |
1164 | rc = iucv_call_b2f0(IUCV_REPLY, parm); | 1287 | rc = iucv_call_b2f0(IUCV_REPLY, parm); |
1288 | out: | ||
1165 | local_bh_enable(); | 1289 | local_bh_enable(); |
1166 | return rc; | 1290 | return rc; |
1167 | } | 1291 | } |
@@ -1190,6 +1314,10 @@ int __iucv_message_send(struct iucv_path *path, struct iucv_message *msg, | |||
1190 | union iucv_param *parm; | 1314 | union iucv_param *parm; |
1191 | int rc; | 1315 | int rc; |
1192 | 1316 | ||
1317 | if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) { | ||
1318 | rc = -EIO; | ||
1319 | goto out; | ||
1320 | } | ||
1193 | parm = iucv_param[smp_processor_id()]; | 1321 | parm = iucv_param[smp_processor_id()]; |
1194 | memset(parm, 0, sizeof(union iucv_param)); | 1322 | memset(parm, 0, sizeof(union iucv_param)); |
1195 | if (flags & IUCV_IPRMDATA) { | 1323 | if (flags & IUCV_IPRMDATA) { |
@@ -1212,6 +1340,7 @@ int __iucv_message_send(struct iucv_path *path, struct iucv_message *msg, | |||
1212 | rc = iucv_call_b2f0(IUCV_SEND, parm); | 1340 | rc = iucv_call_b2f0(IUCV_SEND, parm); |
1213 | if (!rc) | 1341 | if (!rc) |
1214 | msg->id = parm->db.ipmsgid; | 1342 | msg->id = parm->db.ipmsgid; |
1343 | out: | ||
1215 | return rc; | 1344 | return rc; |
1216 | } | 1345 | } |
1217 | EXPORT_SYMBOL(__iucv_message_send); | 1346 | EXPORT_SYMBOL(__iucv_message_send); |
@@ -1272,6 +1401,10 @@ int iucv_message_send2way(struct iucv_path *path, struct iucv_message *msg, | |||
1272 | int rc; | 1401 | int rc; |
1273 | 1402 | ||
1274 | local_bh_disable(); | 1403 | local_bh_disable(); |
1404 | if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) { | ||
1405 | rc = -EIO; | ||
1406 | goto out; | ||
1407 | } | ||
1275 | parm = iucv_param[smp_processor_id()]; | 1408 | parm = iucv_param[smp_processor_id()]; |
1276 | memset(parm, 0, sizeof(union iucv_param)); | 1409 | memset(parm, 0, sizeof(union iucv_param)); |
1277 | if (flags & IUCV_IPRMDATA) { | 1410 | if (flags & IUCV_IPRMDATA) { |
@@ -1297,6 +1430,7 @@ int iucv_message_send2way(struct iucv_path *path, struct iucv_message *msg, | |||
1297 | rc = iucv_call_b2f0(IUCV_SEND, parm); | 1430 | rc = iucv_call_b2f0(IUCV_SEND, parm); |
1298 | if (!rc) | 1431 | if (!rc) |
1299 | msg->id = parm->db.ipmsgid; | 1432 | msg->id = parm->db.ipmsgid; |
1433 | out: | ||
1300 | local_bh_enable(); | 1434 | local_bh_enable(); |
1301 | return rc; | 1435 | return rc; |
1302 | } | 1436 | } |
@@ -1687,6 +1821,130 @@ static void iucv_external_interrupt(u16 code) | |||
1687 | spin_unlock(&iucv_queue_lock); | 1821 | spin_unlock(&iucv_queue_lock); |
1688 | } | 1822 | } |
1689 | 1823 | ||
1824 | static int iucv_pm_prepare(struct device *dev) | ||
1825 | { | ||
1826 | int rc = 0; | ||
1827 | |||
1828 | #ifdef CONFIG_PM_DEBUG | ||
1829 | printk(KERN_INFO "iucv_pm_prepare\n"); | ||
1830 | #endif | ||
1831 | if (dev->driver && dev->driver->pm && dev->driver->pm->prepare) | ||
1832 | rc = dev->driver->pm->prepare(dev); | ||
1833 | return rc; | ||
1834 | } | ||
1835 | |||
1836 | static void iucv_pm_complete(struct device *dev) | ||
1837 | { | ||
1838 | #ifdef CONFIG_PM_DEBUG | ||
1839 | printk(KERN_INFO "iucv_pm_complete\n"); | ||
1840 | #endif | ||
1841 | if (dev->driver && dev->driver->pm && dev->driver->pm->complete) | ||
1842 | dev->driver->pm->complete(dev); | ||
1843 | } | ||
1844 | |||
1845 | /** | ||
1846 | * iucv_path_table_empty() - determine if iucv path table is empty | ||
1847 | * | ||
1848 | * Returns 0 if there are still iucv pathes defined | ||
1849 | * 1 if there are no iucv pathes defined | ||
1850 | */ | ||
1851 | int iucv_path_table_empty(void) | ||
1852 | { | ||
1853 | int i; | ||
1854 | |||
1855 | for (i = 0; i < iucv_max_pathid; i++) { | ||
1856 | if (iucv_path_table[i]) | ||
1857 | return 0; | ||
1858 | } | ||
1859 | return 1; | ||
1860 | } | ||
1861 | |||
1862 | /** | ||
1863 | * iucv_pm_freeze() - Freeze PM callback | ||
1864 | * @dev: iucv-based device | ||
1865 | * | ||
1866 | * disable iucv interrupts | ||
1867 | * invoke callback function of the iucv-based driver | ||
1868 | * shut down iucv, if no iucv-pathes are established anymore | ||
1869 | */ | ||
1870 | static int iucv_pm_freeze(struct device *dev) | ||
1871 | { | ||
1872 | int cpu; | ||
1873 | int rc = 0; | ||
1874 | |||
1875 | #ifdef CONFIG_PM_DEBUG | ||
1876 | printk(KERN_WARNING "iucv_pm_freeze\n"); | ||
1877 | #endif | ||
1878 | for_each_cpu_mask_nr(cpu, iucv_irq_cpumask) | ||
1879 | smp_call_function_single(cpu, iucv_block_cpu_almost, NULL, 1); | ||
1880 | if (dev->driver && dev->driver->pm && dev->driver->pm->freeze) | ||
1881 | rc = dev->driver->pm->freeze(dev); | ||
1882 | if (iucv_path_table_empty()) | ||
1883 | iucv_disable(); | ||
1884 | return rc; | ||
1885 | } | ||
1886 | |||
1887 | /** | ||
1888 | * iucv_pm_thaw() - Thaw PM callback | ||
1889 | * @dev: iucv-based device | ||
1890 | * | ||
1891 | * make iucv ready for use again: allocate path table, declare interrupt buffers | ||
1892 | * and enable iucv interrupts | ||
1893 | * invoke callback function of the iucv-based driver | ||
1894 | */ | ||
1895 | static int iucv_pm_thaw(struct device *dev) | ||
1896 | { | ||
1897 | int rc = 0; | ||
1898 | |||
1899 | #ifdef CONFIG_PM_DEBUG | ||
1900 | printk(KERN_WARNING "iucv_pm_thaw\n"); | ||
1901 | #endif | ||
1902 | if (!iucv_path_table) { | ||
1903 | rc = iucv_enable(); | ||
1904 | if (rc) | ||
1905 | goto out; | ||
1906 | } | ||
1907 | if (cpus_empty(iucv_irq_cpumask)) { | ||
1908 | if (iucv_nonsmp_handler) | ||
1909 | /* enable interrupts on one cpu */ | ||
1910 | iucv_allow_cpu(NULL); | ||
1911 | else | ||
1912 | /* enable interrupts on all cpus */ | ||
1913 | iucv_setmask_mp(); | ||
1914 | } | ||
1915 | if (dev->driver && dev->driver->pm && dev->driver->pm->thaw) | ||
1916 | rc = dev->driver->pm->thaw(dev); | ||
1917 | out: | ||
1918 | return rc; | ||
1919 | } | ||
1920 | |||
1921 | /** | ||
1922 | * iucv_pm_restore() - Restore PM callback | ||
1923 | * @dev: iucv-based device | ||
1924 | * | ||
1925 | * make iucv ready for use again: allocate path table, declare interrupt buffers | ||
1926 | * and enable iucv interrupts | ||
1927 | * invoke callback function of the iucv-based driver | ||
1928 | */ | ||
1929 | static int iucv_pm_restore(struct device *dev) | ||
1930 | { | ||
1931 | int rc = 0; | ||
1932 | |||
1933 | #ifdef CONFIG_PM_DEBUG | ||
1934 | printk(KERN_WARNING "iucv_pm_restore %p\n", iucv_path_table); | ||
1935 | #endif | ||
1936 | if (cpus_empty(iucv_irq_cpumask)) { | ||
1937 | rc = iucv_query_maxconn(); | ||
1938 | rc = iucv_enable(); | ||
1939 | if (rc) | ||
1940 | goto out; | ||
1941 | } | ||
1942 | if (dev->driver && dev->driver->pm && dev->driver->pm->restore) | ||
1943 | rc = dev->driver->pm->restore(dev); | ||
1944 | out: | ||
1945 | return rc; | ||
1946 | } | ||
1947 | |||
1690 | /** | 1948 | /** |
1691 | * iucv_init | 1949 | * iucv_init |
1692 | * | 1950 | * |
@@ -1740,15 +1998,20 @@ static int __init iucv_init(void) | |||
1740 | rc = register_hotcpu_notifier(&iucv_cpu_notifier); | 1998 | rc = register_hotcpu_notifier(&iucv_cpu_notifier); |
1741 | if (rc) | 1999 | if (rc) |
1742 | goto out_free; | 2000 | goto out_free; |
2001 | rc = register_reboot_notifier(&iucv_reboot_notifier); | ||
2002 | if (rc) | ||
2003 | goto out_cpu; | ||
1743 | ASCEBC(iucv_error_no_listener, 16); | 2004 | ASCEBC(iucv_error_no_listener, 16); |
1744 | ASCEBC(iucv_error_no_memory, 16); | 2005 | ASCEBC(iucv_error_no_memory, 16); |
1745 | ASCEBC(iucv_error_pathid, 16); | 2006 | ASCEBC(iucv_error_pathid, 16); |
1746 | iucv_available = 1; | 2007 | iucv_available = 1; |
1747 | rc = bus_register(&iucv_bus); | 2008 | rc = bus_register(&iucv_bus); |
1748 | if (rc) | 2009 | if (rc) |
1749 | goto out_cpu; | 2010 | goto out_reboot; |
1750 | return 0; | 2011 | return 0; |
1751 | 2012 | ||
2013 | out_reboot: | ||
2014 | unregister_reboot_notifier(&iucv_reboot_notifier); | ||
1752 | out_cpu: | 2015 | out_cpu: |
1753 | unregister_hotcpu_notifier(&iucv_cpu_notifier); | 2016 | unregister_hotcpu_notifier(&iucv_cpu_notifier); |
1754 | out_free: | 2017 | out_free: |
@@ -1783,6 +2046,7 @@ static void __exit iucv_exit(void) | |||
1783 | list_for_each_entry_safe(p, n, &iucv_work_queue, list) | 2046 | list_for_each_entry_safe(p, n, &iucv_work_queue, list) |
1784 | kfree(p); | 2047 | kfree(p); |
1785 | spin_unlock_irq(&iucv_queue_lock); | 2048 | spin_unlock_irq(&iucv_queue_lock); |
2049 | unregister_reboot_notifier(&iucv_reboot_notifier); | ||
1786 | unregister_hotcpu_notifier(&iucv_cpu_notifier); | 2050 | unregister_hotcpu_notifier(&iucv_cpu_notifier); |
1787 | for_each_possible_cpu(cpu) { | 2051 | for_each_possible_cpu(cpu) { |
1788 | kfree(iucv_param_irq[cpu]); | 2052 | kfree(iucv_param_irq[cpu]); |