aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUrsula Braun <ursula.braun@de.ibm.com>2009-06-16 04:30:44 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2009-06-16 04:31:19 -0400
commitc23cad923bfebd295ec49dc9265569993903488d (patch)
tree263bb2b6ed99f250bb8ed9f5fdeed1918cceb45e
parent1175b257c8a2cb384823621cad0c1e0945f74300 (diff)
[S390] PM: af_iucv power management callbacks.
Patch establishes a dummy afiucv-device to make sure af_iucv is notified as iucv-bus device about suspend/resume. The PM freeze callback severs all iucv pathes of connected af_iucv sockets. The PM thaw/restore callback switches the state of all previously connected sockets to IUCV_DISCONN. Signed-off-by: Ursula Braun <ursula.braun@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r--net/iucv/af_iucv.c147
1 files changed, 144 insertions, 3 deletions
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
94static 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
102static 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 */
116static 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 */
160static 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
192static 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
200static 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 */
208static 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
1696out_driver:
1697 driver_unregister(&af_iucv_driver);
1698out_sock:
1699 sock_unregister(PF_IUCV);
1561out_proto: 1700out_proto:
1562 proto_unregister(&iucv_proto); 1701 proto_unregister(&iucv_proto);
1563out_iucv: 1702out_iucv:
@@ -1568,6 +1707,8 @@ out:
1568 1707
1569static void __exit afiucv_exit(void) 1708static 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);