- patches.rt/0001-sched-count-of-queued-RT-tasks.patch: Delete.
[linux-flexiantxendom0-3.2.10.git] / drivers / xen / tpmback / xenbus.c
1 /*  Xenbus code for tpmif backend
2     Copyright (C) 2005 IBM Corporation
3     Copyright (C) 2005 Rusty Russell <rusty@rustcorp.com.au>
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 */
19 #include <stdarg.h>
20 #include <linux/module.h>
21 #include <xen/xenbus.h>
22 #include "common.h"
23
24 struct backend_info
25 {
26         struct xenbus_device *dev;
27
28         /* our communications channel */
29         tpmif_t *tpmif;
30
31         long int frontend_id;
32         long int instance; // instance of TPM
33         u8 is_instance_set;// whether instance number has been set
34
35         /* watch front end for changes */
36         struct xenbus_watch backend_watch;
37 };
38
39 static void maybe_connect(struct backend_info *be);
40 static void connect(struct backend_info *be);
41 static int connect_ring(struct backend_info *be);
42 static void backend_changed(struct xenbus_watch *watch,
43                             const char **vec, unsigned int len);
44 static void frontend_changed(struct xenbus_device *dev,
45                              enum xenbus_state frontend_state);
46
47 long int tpmback_get_instance(struct backend_info *bi)
48 {
49         long int res = -1;
50         if (bi && bi->is_instance_set)
51                 res = bi->instance;
52         return res;
53 }
54
55 static int tpmback_remove(struct xenbus_device *dev)
56 {
57         struct backend_info *be = dev->dev.driver_data;
58
59         if (!be) return 0;
60
61         if (be->backend_watch.node) {
62                 unregister_xenbus_watch(&be->backend_watch);
63                 kfree(be->backend_watch.node);
64                 be->backend_watch.node = NULL;
65         }
66         if (be->tpmif) {
67                 be->tpmif->bi = NULL;
68                 vtpm_release_packets(be->tpmif, 0);
69                 tpmif_put(be->tpmif);
70                 be->tpmif = NULL;
71         }
72         kfree(be);
73         dev->dev.driver_data = NULL;
74         return 0;
75 }
76
77 static int tpmback_probe(struct xenbus_device *dev,
78                          const struct xenbus_device_id *id)
79 {
80         int err;
81         struct backend_info *be = kzalloc(sizeof(struct backend_info),
82                                           GFP_KERNEL);
83
84         if (!be) {
85                 xenbus_dev_fatal(dev, -ENOMEM,
86                                  "allocating backend structure");
87                 return -ENOMEM;
88         }
89
90         be->is_instance_set = 0;
91         be->dev = dev;
92         dev->dev.driver_data = be;
93
94         err = xenbus_watch_path2(dev, dev->nodename,
95                                  "instance", &be->backend_watch,
96                                  backend_changed);
97         if (err) {
98                 goto fail;
99         }
100
101         err = xenbus_switch_state(dev, XenbusStateInitWait);
102         if (err) {
103                 goto fail;
104         }
105         return 0;
106 fail:
107         tpmback_remove(dev);
108         return err;
109 }
110
111
112 static void backend_changed(struct xenbus_watch *watch,
113                             const char **vec, unsigned int len)
114 {
115         int err;
116         long instance;
117         struct backend_info *be
118                 = container_of(watch, struct backend_info, backend_watch);
119         struct xenbus_device *dev = be->dev;
120
121         err = xenbus_scanf(XBT_NIL, dev->nodename,
122                            "instance","%li", &instance);
123         if (XENBUS_EXIST_ERR(err)) {
124                 return;
125         }
126
127         if (err != 1) {
128                 xenbus_dev_fatal(dev, err, "reading instance");
129                 return;
130         }
131
132         if (be->is_instance_set == 0) {
133                 be->instance = instance;
134                 be->is_instance_set = 1;
135         }
136 }
137
138
139 static void frontend_changed(struct xenbus_device *dev,
140                              enum xenbus_state frontend_state)
141 {
142         struct backend_info *be = dev->dev.driver_data;
143         int err;
144
145         switch (frontend_state) {
146         case XenbusStateInitialising:
147         case XenbusStateInitialised:
148                 break;
149
150         case XenbusStateConnected:
151                 err = connect_ring(be);
152                 if (err) {
153                         return;
154                 }
155                 maybe_connect(be);
156                 break;
157
158         case XenbusStateClosing:
159                 be->instance = -1;
160                 xenbus_switch_state(dev, XenbusStateClosing);
161                 break;
162
163         case XenbusStateUnknown: /* keep it here */
164         case XenbusStateClosed:
165                 xenbus_switch_state(dev, XenbusStateClosed);
166                 device_unregister(&be->dev->dev);
167                 tpmback_remove(dev);
168                 break;
169
170         default:
171                 xenbus_dev_fatal(dev, -EINVAL,
172                                  "saw state %d at frontend",
173                                  frontend_state);
174                 break;
175         }
176 }
177
178
179
180 static void maybe_connect(struct backend_info *be)
181 {
182         if (be->tpmif == NULL || be->tpmif->status == CONNECTED)
183                 return;
184
185         connect(be);
186 }
187
188
189 static void connect(struct backend_info *be)
190 {
191         struct xenbus_transaction xbt;
192         int err;
193         struct xenbus_device *dev = be->dev;
194         unsigned long ready = 1;
195
196 again:
197         err = xenbus_transaction_start(&xbt);
198         if (err) {
199                 xenbus_dev_fatal(be->dev, err, "starting transaction");
200                 return;
201         }
202
203         err = xenbus_printf(xbt, be->dev->nodename,
204                             "ready", "%lu", ready);
205         if (err) {
206                 xenbus_dev_fatal(be->dev, err, "writing 'ready'");
207                 goto abort;
208         }
209
210         err = xenbus_transaction_end(xbt, 0);
211         if (err == -EAGAIN)
212                 goto again;
213         if (err)
214                 xenbus_dev_fatal(be->dev, err, "end of transaction");
215
216         err = xenbus_switch_state(dev, XenbusStateConnected);
217         if (!err)
218                 be->tpmif->status = CONNECTED;
219         return;
220 abort:
221         xenbus_transaction_end(xbt, 1);
222 }
223
224
225 static int connect_ring(struct backend_info *be)
226 {
227         struct xenbus_device *dev = be->dev;
228         unsigned long ring_ref;
229         unsigned int evtchn;
230         int err;
231
232         err = xenbus_gather(XBT_NIL, dev->otherend,
233                             "ring-ref", "%lu", &ring_ref,
234                             "event-channel", "%u", &evtchn, NULL);
235         if (err) {
236                 xenbus_dev_error(dev, err,
237                                  "reading %s/ring-ref and event-channel",
238                                  dev->otherend);
239                 return err;
240         }
241
242         if (!be->tpmif) {
243                 be->tpmif = tpmif_find(dev->otherend_id, be);
244                 if (IS_ERR(be->tpmif)) {
245                         err = PTR_ERR(be->tpmif);
246                         be->tpmif = NULL;
247                         xenbus_dev_fatal(dev,err,"creating vtpm interface");
248                         return err;
249                 }
250         }
251
252         if (be->tpmif != NULL) {
253                 err = tpmif_map(be->tpmif, ring_ref, evtchn);
254                 if (err) {
255                         xenbus_dev_error(dev, err,
256                                          "mapping shared-frame %lu port %u",
257                                          ring_ref, evtchn);
258                         return err;
259                 }
260         }
261         return 0;
262 }
263
264
265 static struct xenbus_device_id tpmback_ids[] = {
266         { "vtpm" },
267         { "" }
268 };
269
270
271 static struct xenbus_driver tpmback = {
272         .name = "vtpm",
273         .ids = tpmback_ids,
274         .probe = tpmback_probe,
275         .remove = tpmback_remove,
276         .otherend_changed = frontend_changed,
277 };
278
279
280 int tpmif_xenbus_init(void)
281 {
282         return xenbus_register_backend(&tpmback);
283 }
284
285 void tpmif_xenbus_exit(void)
286 {
287         xenbus_unregister_driver(&tpmback);
288 }