Blame view

drivers/xen/xenbus/xenbus_probe.c 17.8 KB
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
  /******************************************************************************
   * Talks to Xen Store to figure out what devices we have.
   *
   * Copyright (C) 2005 Rusty Russell, IBM Corporation
   * Copyright (C) 2005 Mike Wray, Hewlett-Packard
   * Copyright (C) 2005, 2006 XenSource Ltd
   *
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of the GNU General Public License version 2
   * as published by the Free Software Foundation; or, when distributed
   * separately from the Linux kernel or incorporated into other
   * software packages, subject to the following license:
   *
   * Permission is hereby granted, free of charge, to any person obtaining a copy
   * of this source file (the "Software"), to deal in the Software without
   * restriction, including without limitation the rights to use, copy, modify,
   * merge, publish, distribute, sublicense, and/or sell copies of the Software,
   * and to permit persons to whom the Software is furnished to do so, subject to
   * the following conditions:
   *
   * The above copyright notice and this permission notice shall be included in
   * all copies or substantial portions of the Software.
   *
   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
   * IN THE SOFTWARE.
   */
  
  #define DPRINTK(fmt, args...)				\
  	pr_debug("xenbus_probe (%s:%d) " fmt ".
  ",	\
  		 __func__, __LINE__, ##args)
  
  #include <linux/kernel.h>
  #include <linux/err.h>
  #include <linux/string.h>
  #include <linux/ctype.h>
  #include <linux/fcntl.h>
  #include <linux/mm.h>
1107ba885   Alex Zeffertt   xen: add xenfs to...
44
  #include <linux/proc_fs.h>
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
45
46
47
48
  #include <linux/notifier.h>
  #include <linux/kthread.h>
  #include <linux/mutex.h>
  #include <linux/io.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
49
  #include <linux/slab.h>
72ee5112a   Paul Gortmaker   xen: Add module.h...
50
  #include <linux/module.h>
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
51
52
53
54
  
  #include <asm/page.h>
  #include <asm/pgtable.h>
  #include <asm/xen/hypervisor.h>
1ccbf5344   Jeremy Fitzhardinge   xen: move Xen-tes...
55
56
  
  #include <xen/xen.h>
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
57
58
59
  #include <xen/xenbus.h>
  #include <xen/events.h>
  #include <xen/page.h>
bee6ab53e   Sheng Yang   x86: early PV on ...
60
  #include <xen/hvm.h>
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
61
62
  #include "xenbus_comms.h"
  #include "xenbus_probe.h"
1107ba885   Alex Zeffertt   xen: add xenfs to...
63

4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
64
  int xen_store_evtchn;
8e3e99918   Jeremy Fitzhardinge   xenbus: export xe...
65
  EXPORT_SYMBOL_GPL(xen_store_evtchn);
1107ba885   Alex Zeffertt   xen: add xenfs to...
66

4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
67
  struct xenstore_domain_interface *xen_store_interface;
8e3e99918   Jeremy Fitzhardinge   xenbus: export xe...
68
  EXPORT_SYMBOL_GPL(xen_store_interface);
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
69
70
71
  static unsigned long xen_store_mfn;
  
  static BLOCKING_NOTIFIER_HEAD(xenstore_chain);
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
  /* If something in array of ids matches this device, return it. */
  static const struct xenbus_device_id *
  match_device(const struct xenbus_device_id *arr, struct xenbus_device *dev)
  {
  	for (; *arr->devicetype != '\0'; arr++) {
  		if (!strcmp(arr->devicetype, dev->devicetype))
  			return arr;
  	}
  	return NULL;
  }
  
  int xenbus_match(struct device *_dev, struct device_driver *_drv)
  {
  	struct xenbus_driver *drv = to_xenbus_driver(_drv);
  
  	if (!drv->ids)
  		return 0;
  
  	return match_device(drv->ids, to_xenbus_device(_dev)) != NULL;
  }
2de06cc1f   Ian Campbell   xen: separate out...
92
  EXPORT_SYMBOL_GPL(xenbus_match);
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
93

4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
  static void free_otherend_details(struct xenbus_device *dev)
  {
  	kfree(dev->otherend);
  	dev->otherend = NULL;
  }
  
  
  static void free_otherend_watch(struct xenbus_device *dev)
  {
  	if (dev->otherend_watch.node) {
  		unregister_xenbus_watch(&dev->otherend_watch);
  		kfree(dev->otherend_watch.node);
  		dev->otherend_watch.node = NULL;
  	}
  }
2de06cc1f   Ian Campbell   xen: separate out...
109
110
111
112
113
114
115
116
117
118
119
120
121
122
  static int talk_to_otherend(struct xenbus_device *dev)
  {
  	struct xenbus_driver *drv = to_xenbus_driver(dev->dev.driver);
  
  	free_otherend_watch(dev);
  	free_otherend_details(dev);
  
  	return drv->read_otherend_details(dev);
  }
  
  
  
  static int watch_otherend(struct xenbus_device *dev)
  {
6bac7f9f9   Ian Campbell   xen/xenbus: fixup...
123
124
  	struct xen_bus_type *bus =
  		container_of(dev->dev.bus, struct xen_bus_type, bus);
2de06cc1f   Ian Campbell   xen: separate out...
125

6bac7f9f9   Ian Campbell   xen/xenbus: fixup...
126
127
  	return xenbus_watch_pathfmt(dev, &dev->otherend_watch,
  				    bus->otherend_changed,
2de06cc1f   Ian Campbell   xen: separate out...
128
129
130
131
132
  				    "%s/%s", dev->otherend, "state");
  }
  
  
  int xenbus_read_otherend_details(struct xenbus_device *xendev,
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
  				 char *id_node, char *path_node)
  {
  	int err = xenbus_gather(XBT_NIL, xendev->nodename,
  				id_node, "%i", &xendev->otherend_id,
  				path_node, NULL, &xendev->otherend,
  				NULL);
  	if (err) {
  		xenbus_dev_fatal(xendev, err,
  				 "reading other end details from %s",
  				 xendev->nodename);
  		return err;
  	}
  	if (strlen(xendev->otherend) == 0 ||
  	    !xenbus_exists(XBT_NIL, xendev->otherend, "")) {
  		xenbus_dev_fatal(xendev, -ENOENT,
  				 "unable to read other end from %s.  "
  				 "missing or inaccessible.",
  				 xendev->nodename);
  		free_otherend_details(xendev);
  		return -ENOENT;
  	}
  
  	return 0;
  }
2de06cc1f   Ian Campbell   xen: separate out...
157
  EXPORT_SYMBOL_GPL(xenbus_read_otherend_details);
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
158

2de06cc1f   Ian Campbell   xen: separate out...
159
160
161
  void xenbus_otherend_changed(struct xenbus_watch *watch,
  			     const char **vec, unsigned int len,
  			     int ignore_on_shutdown)
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
162
163
164
165
166
167
168
169
170
171
172
  {
  	struct xenbus_device *dev =
  		container_of(watch, struct xenbus_device, otherend_watch);
  	struct xenbus_driver *drv = to_xenbus_driver(dev->dev.driver);
  	enum xenbus_state state;
  
  	/* Protect us against watches firing on old details when the otherend
  	   details change, say immediately after a resume. */
  	if (!dev->otherend ||
  	    strncmp(dev->otherend, vec[XS_WATCH_PATH],
  		    strlen(dev->otherend))) {
898eb71cb   Joe Perches   Add missing newli...
173
174
175
  		dev_dbg(&dev->dev, "Ignoring watch at %s
  ",
  			vec[XS_WATCH_PATH]);
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
176
177
178
179
  		return;
  	}
  
  	state = xenbus_read_driver_state(dev->otherend);
898eb71cb   Joe Perches   Add missing newli...
180
181
  	dev_dbg(&dev->dev, "state is %d, (%s), %s, %s
  ",
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
182
183
184
185
186
187
188
189
  		state, xenbus_strstate(state), dev->otherend_watch.node,
  		vec[XS_WATCH_PATH]);
  
  	/*
  	 * Ignore xenbus transitions during shutdown. This prevents us doing
  	 * work that can fail e.g., when the rootfs is gone.
  	 */
  	if (system_state > SYSTEM_RUNNING) {
2de06cc1f   Ian Campbell   xen: separate out...
190
  		if (ignore_on_shutdown && (state == XenbusStateClosing))
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
191
192
193
194
195
196
197
  			xenbus_frontend_closed(dev);
  		return;
  	}
  
  	if (drv->otherend_changed)
  		drv->otherend_changed(dev, state);
  }
2de06cc1f   Ian Campbell   xen: separate out...
198
  EXPORT_SYMBOL_GPL(xenbus_otherend_changed);
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
  
  int xenbus_dev_probe(struct device *_dev)
  {
  	struct xenbus_device *dev = to_xenbus_device(_dev);
  	struct xenbus_driver *drv = to_xenbus_driver(_dev->driver);
  	const struct xenbus_device_id *id;
  	int err;
  
  	DPRINTK("%s", dev->nodename);
  
  	if (!drv->probe) {
  		err = -ENODEV;
  		goto fail;
  	}
  
  	id = match_device(drv->ids, dev);
  	if (!id) {
  		err = -ENODEV;
  		goto fail;
  	}
  
  	err = talk_to_otherend(dev);
  	if (err) {
  		dev_warn(&dev->dev, "talk_to_otherend on %s failed.
  ",
  			 dev->nodename);
  		return err;
  	}
  
  	err = drv->probe(dev, id);
  	if (err)
  		goto fail;
  
  	err = watch_otherend(dev);
  	if (err) {
  		dev_warn(&dev->dev, "watch_otherend on %s failed.
  ",
  		       dev->nodename);
  		return err;
  	}
  
  	return 0;
  fail:
  	xenbus_dev_error(dev, err, "xenbus_dev_probe on %s", dev->nodename);
  	xenbus_switch_state(dev, XenbusStateClosed);
7432e4bd0   Jeremy Fitzhardinge   xen/xenbus: clean...
244
  	return err;
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
245
  }
2de06cc1f   Ian Campbell   xen: separate out...
246
  EXPORT_SYMBOL_GPL(xenbus_dev_probe);
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
  
  int xenbus_dev_remove(struct device *_dev)
  {
  	struct xenbus_device *dev = to_xenbus_device(_dev);
  	struct xenbus_driver *drv = to_xenbus_driver(_dev->driver);
  
  	DPRINTK("%s", dev->nodename);
  
  	free_otherend_watch(dev);
  	free_otherend_details(dev);
  
  	if (drv->remove)
  		drv->remove(dev);
  
  	xenbus_switch_state(dev, XenbusStateClosed);
  	return 0;
  }
2de06cc1f   Ian Campbell   xen: separate out...
264
  EXPORT_SYMBOL_GPL(xenbus_dev_remove);
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
265

2de06cc1f   Ian Campbell   xen: separate out...
266
  void xenbus_dev_shutdown(struct device *_dev)
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
  {
  	struct xenbus_device *dev = to_xenbus_device(_dev);
  	unsigned long timeout = 5*HZ;
  
  	DPRINTK("%s", dev->nodename);
  
  	get_device(&dev->dev);
  	if (dev->state != XenbusStateConnected) {
  		printk(KERN_INFO "%s: %s: %s != Connected, skipping
  ", __func__,
  		       dev->nodename, xenbus_strstate(dev->state));
  		goto out;
  	}
  	xenbus_switch_state(dev, XenbusStateClosing);
  	timeout = wait_for_completion_timeout(&dev->down, timeout);
  	if (!timeout)
  		printk(KERN_INFO "%s: %s timeout closing device
  ",
  		       __func__, dev->nodename);
   out:
  	put_device(&dev->dev);
  }
2de06cc1f   Ian Campbell   xen: separate out...
289
  EXPORT_SYMBOL_GPL(xenbus_dev_shutdown);
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
290
291
  
  int xenbus_register_driver_common(struct xenbus_driver *drv,
73db144b5   Jan Beulich   Xen: consolidate ...
292
  				  struct xen_bus_type *bus)
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
293
  {
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
294
  	drv->driver.bus = &bus->bus;
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
295
296
297
  
  	return driver_register(&drv->driver);
  }
2de06cc1f   Ian Campbell   xen: separate out...
298
  EXPORT_SYMBOL_GPL(xenbus_register_driver_common);
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
299
300
301
302
303
304
  
  void xenbus_unregister_driver(struct xenbus_driver *drv)
  {
  	driver_unregister(&drv->driver);
  }
  EXPORT_SYMBOL_GPL(xenbus_unregister_driver);
6913200a5   Ruslan Pisarev   Xen: fix braces a...
305
  struct xb_find_info {
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
  	struct xenbus_device *dev;
  	const char *nodename;
  };
  
  static int cmp_dev(struct device *dev, void *data)
  {
  	struct xenbus_device *xendev = to_xenbus_device(dev);
  	struct xb_find_info *info = data;
  
  	if (!strcmp(xendev->nodename, info->nodename)) {
  		info->dev = xendev;
  		get_device(dev);
  		return 1;
  	}
  	return 0;
  }
  
  struct xenbus_device *xenbus_device_find(const char *nodename,
  					 struct bus_type *bus)
  {
  	struct xb_find_info info = { .dev = NULL, .nodename = nodename };
  
  	bus_for_each_dev(bus, NULL, &info, cmp_dev);
  	return info.dev;
  }
  
  static int cleanup_dev(struct device *dev, void *data)
  {
  	struct xenbus_device *xendev = to_xenbus_device(dev);
  	struct xb_find_info *info = data;
  	int len = strlen(info->nodename);
  
  	DPRINTK("%s", info->nodename);
  
  	/* Match the info->nodename path, or any subdirectory of that path. */
  	if (strncmp(xendev->nodename, info->nodename, len))
  		return 0;
  
  	/* If the node name is longer, ensure it really is a subdirectory. */
  	if ((strlen(xendev->nodename) > len) && (xendev->nodename[len] != '/'))
  		return 0;
  
  	info->dev = xendev;
  	get_device(dev);
  	return 1;
  }
  
  static void xenbus_cleanup_devices(const char *path, struct bus_type *bus)
  {
  	struct xb_find_info info = { .nodename = path };
  
  	do {
  		info.dev = NULL;
  		bus_for_each_dev(bus, NULL, &info, cleanup_dev);
  		if (info.dev) {
  			device_unregister(&info.dev->dev);
  			put_device(&info.dev->dev);
  		}
  	} while (info.dev);
  }
  
  static void xenbus_dev_release(struct device *dev)
  {
  	if (dev)
  		kfree(to_xenbus_device(dev));
  }
cc85e9334   Bastian Blank   xen: Populate xen...
372
373
  static ssize_t nodename_show(struct device *dev,
  			     struct device_attribute *attr, char *buf)
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
374
375
376
377
  {
  	return sprintf(buf, "%s
  ", to_xenbus_device(dev)->nodename);
  }
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
378

cc85e9334   Bastian Blank   xen: Populate xen...
379
380
  static ssize_t devtype_show(struct device *dev,
  			    struct device_attribute *attr, char *buf)
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
381
382
383
384
  {
  	return sprintf(buf, "%s
  ", to_xenbus_device(dev)->devicetype);
  }
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
385

cc85e9334   Bastian Blank   xen: Populate xen...
386
387
  static ssize_t modalias_show(struct device *dev,
  			     struct device_attribute *attr, char *buf)
d2f0c52be   Mark McLoughlin   xen: Module autop...
388
  {
149bb2fab   Bastian Blank   xen: Add module a...
389
390
391
  	return sprintf(buf, "%s:%s
  ", dev->bus->name,
  		       to_xenbus_device(dev)->devicetype);
d2f0c52be   Mark McLoughlin   xen: Module autop...
392
  }
cc85e9334   Bastian Blank   xen: Populate xen...
393
394
395
396
397
398
399
400
  
  struct device_attribute xenbus_dev_attrs[] = {
  	__ATTR_RO(nodename),
  	__ATTR_RO(devtype),
  	__ATTR_RO(modalias),
  	__ATTR_NULL
  };
  EXPORT_SYMBOL_GPL(xenbus_dev_attrs);
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
401
402
403
404
405
  
  int xenbus_probe_node(struct xen_bus_type *bus,
  		      const char *type,
  		      const char *nodename)
  {
2a678cc53   Kay Sievers   xen: struct devic...
406
  	char devname[XEN_BUS_ID_SIZE];
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
  	int err;
  	struct xenbus_device *xendev;
  	size_t stringlen;
  	char *tmpstring;
  
  	enum xenbus_state state = xenbus_read_driver_state(nodename);
  
  	if (state != XenbusStateInitialising) {
  		/* Device is not new, so ignore it.  This can happen if a
  		   device is going away after switching to Closed.  */
  		return 0;
  	}
  
  	stringlen = strlen(nodename) + 1 + strlen(type) + 1;
  	xendev = kzalloc(sizeof(*xendev) + stringlen, GFP_KERNEL);
  	if (!xendev)
  		return -ENOMEM;
  
  	xendev->state = XenbusStateInitialising;
  
  	/* Copy the strings into the extra space. */
  
  	tmpstring = (char *)(xendev + 1);
  	strcpy(tmpstring, nodename);
  	xendev->nodename = tmpstring;
  
  	tmpstring += strlen(tmpstring) + 1;
  	strcpy(tmpstring, type);
  	xendev->devicetype = tmpstring;
  	init_completion(&xendev->down);
  
  	xendev->dev.bus = &bus->bus;
  	xendev->dev.release = xenbus_dev_release;
2a678cc53   Kay Sievers   xen: struct devic...
440
  	err = bus->get_bus_id(devname, xendev->nodename);
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
441
442
  	if (err)
  		goto fail;
2a678cc53   Kay Sievers   xen: struct devic...
443
  	dev_set_name(&xendev->dev, devname);
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
444
445
446
447
  	/* Register with generic device framework. */
  	err = device_register(&xendev->dev);
  	if (err)
  		goto fail;
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
448
  	return 0;
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
449
450
451
452
  fail:
  	kfree(xendev);
  	return err;
  }
2de06cc1f   Ian Campbell   xen: separate out...
453
  EXPORT_SYMBOL_GPL(xenbus_probe_node);
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
454
455
456
457
458
459
460
461
462
  
  static int xenbus_probe_device_type(struct xen_bus_type *bus, const char *type)
  {
  	int err = 0;
  	char **dir;
  	unsigned int dir_n = 0;
  	int i;
  
  	dir = xenbus_directory(XBT_NIL, bus->root, type, &dir_n);
a39bda27b   Jeremy Fitzhardinge   xen/xenbus: clean...
463
  	if (IS_ERR(dir))
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
464
465
466
  		return PTR_ERR(dir);
  
  	for (i = 0; i < dir_n; i++) {
2de06cc1f   Ian Campbell   xen: separate out...
467
  		err = bus->probe(bus, type, dir[i]);
a39bda27b   Jeremy Fitzhardinge   xen/xenbus: clean...
468
  		if (err)
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
469
470
  			break;
  	}
a39bda27b   Jeremy Fitzhardinge   xen/xenbus: clean...
471

4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
472
473
474
475
476
477
478
479
480
481
482
  	kfree(dir);
  	return err;
  }
  
  int xenbus_probe_devices(struct xen_bus_type *bus)
  {
  	int err = 0;
  	char **dir;
  	unsigned int i, dir_n;
  
  	dir = xenbus_directory(XBT_NIL, bus->root, "", &dir_n);
a39bda27b   Jeremy Fitzhardinge   xen/xenbus: clean...
483
  	if (IS_ERR(dir))
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
484
485
486
487
  		return PTR_ERR(dir);
  
  	for (i = 0; i < dir_n; i++) {
  		err = xenbus_probe_device_type(bus, dir[i]);
a39bda27b   Jeremy Fitzhardinge   xen/xenbus: clean...
488
  		if (err)
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
489
490
  			break;
  	}
a39bda27b   Jeremy Fitzhardinge   xen/xenbus: clean...
491

4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
492
493
494
  	kfree(dir);
  	return err;
  }
2de06cc1f   Ian Campbell   xen: separate out...
495
  EXPORT_SYMBOL_GPL(xenbus_probe_devices);
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
  
  static unsigned int char_count(const char *str, char c)
  {
  	unsigned int i, ret = 0;
  
  	for (i = 0; str[i]; i++)
  		if (str[i] == c)
  			ret++;
  	return ret;
  }
  
  static int strsep_len(const char *str, char c, unsigned int len)
  {
  	unsigned int i;
  
  	for (i = 0; str[i]; i++)
  		if (str[i] == c) {
  			if (len == 0)
  				return i;
  			len--;
  		}
  	return (len == 0) ? i : -ERANGE;
  }
  
  void xenbus_dev_changed(const char *node, struct xen_bus_type *bus)
  {
  	int exists, rootlen;
  	struct xenbus_device *dev;
2a678cc53   Kay Sievers   xen: struct devic...
524
  	char type[XEN_BUS_ID_SIZE];
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
525
526
527
528
529
530
531
532
533
534
535
536
537
  	const char *p, *root;
  
  	if (char_count(node, '/') < 2)
  		return;
  
  	exists = xenbus_exists(XBT_NIL, node, "");
  	if (!exists) {
  		xenbus_cleanup_devices(node, &bus->bus);
  		return;
  	}
  
  	/* backend/<type>/... or device/<type>/... */
  	p = strchr(node, '/') + 1;
2a678cc53   Kay Sievers   xen: struct devic...
538
539
  	snprintf(type, XEN_BUS_ID_SIZE, "%.*s", (int)strcspn(p, "/"), p);
  	type[XEN_BUS_ID_SIZE-1] = '\0';
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
  
  	rootlen = strsep_len(node, '/', bus->levels);
  	if (rootlen < 0)
  		return;
  	root = kasprintf(GFP_KERNEL, "%.*s", rootlen, node);
  	if (!root)
  		return;
  
  	dev = xenbus_device_find(root, &bus->bus);
  	if (!dev)
  		xenbus_probe_node(bus, type, root);
  	else
  		put_device(&dev->dev);
  
  	kfree(root);
  }
c6a960ce8   Jeremy Fitzhardinge   xen/xenbus: expor...
556
  EXPORT_SYMBOL_GPL(xenbus_dev_changed);
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
557

c7853aea5   Kazuhiro SUZUKI   xen: xenbus PM ev...
558
  int xenbus_dev_suspend(struct device *dev)
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
559
560
561
  {
  	int err = 0;
  	struct xenbus_driver *drv;
6bac7f9f9   Ian Campbell   xen/xenbus: fixup...
562
563
  	struct xenbus_device *xdev
  		= container_of(dev, struct xenbus_device, dev);
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
564

2de06cc1f   Ian Campbell   xen: separate out...
565
  	DPRINTK("%s", xdev->nodename);
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
566
567
568
569
  
  	if (dev->driver == NULL)
  		return 0;
  	drv = to_xenbus_driver(dev->driver);
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
570
  	if (drv->suspend)
c7853aea5   Kazuhiro SUZUKI   xen: xenbus PM ev...
571
  		err = drv->suspend(xdev);
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
572
573
  	if (err)
  		printk(KERN_WARNING
2a678cc53   Kay Sievers   xen: struct devic...
574
575
  		       "xenbus: suspend %s failed: %i
  ", dev_name(dev), err);
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
576
577
  	return 0;
  }
2de06cc1f   Ian Campbell   xen: separate out...
578
  EXPORT_SYMBOL_GPL(xenbus_dev_suspend);
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
579

2de06cc1f   Ian Campbell   xen: separate out...
580
  int xenbus_dev_resume(struct device *dev)
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
581
582
583
  {
  	int err;
  	struct xenbus_driver *drv;
6bac7f9f9   Ian Campbell   xen/xenbus: fixup...
584
585
  	struct xenbus_device *xdev
  		= container_of(dev, struct xenbus_device, dev);
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
586

2de06cc1f   Ian Campbell   xen: separate out...
587
  	DPRINTK("%s", xdev->nodename);
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
588
589
590
  
  	if (dev->driver == NULL)
  		return 0;
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
591
  	drv = to_xenbus_driver(dev->driver);
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
592
593
594
595
596
  	err = talk_to_otherend(xdev);
  	if (err) {
  		printk(KERN_WARNING
  		       "xenbus: resume (talk_to_otherend) %s failed: %i
  ",
2a678cc53   Kay Sievers   xen: struct devic...
597
  		       dev_name(dev), err);
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
598
599
600
601
602
603
604
605
606
607
608
  		return err;
  	}
  
  	xdev->state = XenbusStateInitialising;
  
  	if (drv->resume) {
  		err = drv->resume(xdev);
  		if (err) {
  			printk(KERN_WARNING
  			       "xenbus: resume %s failed: %i
  ",
2a678cc53   Kay Sievers   xen: struct devic...
609
  			       dev_name(dev), err);
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
610
611
612
613
614
615
616
617
  			return err;
  		}
  	}
  
  	err = watch_otherend(xdev);
  	if (err) {
  		printk(KERN_WARNING
  		       "xenbus_probe: resume (watch_otherend) %s failed: "
2a678cc53   Kay Sievers   xen: struct devic...
618
619
  		       "%d.
  ", dev_name(dev), err);
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
620
621
622
623
624
  		return err;
  	}
  
  	return 0;
  }
2de06cc1f   Ian Campbell   xen: separate out...
625
  EXPORT_SYMBOL_GPL(xenbus_dev_resume);
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
626

c7853aea5   Kazuhiro SUZUKI   xen: xenbus PM ev...
627
628
629
630
631
632
633
  int xenbus_dev_cancel(struct device *dev)
  {
  	/* Do nothing */
  	DPRINTK("cancel");
  	return 0;
  }
  EXPORT_SYMBOL_GPL(xenbus_dev_cancel);
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
634
  /* A flag to determine if xenstored is 'ready' (i.e. has started) */
6913200a5   Ruslan Pisarev   Xen: fix braces a...
635
  int xenstored_ready;
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
636
637
638
639
640
  
  
  int register_xenstore_notifier(struct notifier_block *nb)
  {
  	int ret = 0;
a947f0f8f   Stefano Stabellini   xen: do not set x...
641
642
643
644
  	if (xenstored_ready > 0)
  		ret = nb->notifier_call(nb, 0, NULL);
  	else
  		blocking_notifier_chain_register(&xenstore_chain, nb);
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
645
646
647
648
649
650
651
652
653
654
655
656
657
  
  	return ret;
  }
  EXPORT_SYMBOL_GPL(register_xenstore_notifier);
  
  void unregister_xenstore_notifier(struct notifier_block *nb)
  {
  	blocking_notifier_chain_unregister(&xenstore_chain, nb);
  }
  EXPORT_SYMBOL_GPL(unregister_xenstore_notifier);
  
  void xenbus_probe(struct work_struct *unused)
  {
a947f0f8f   Stefano Stabellini   xen: do not set x...
658
  	xenstored_ready = 1;
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
659

4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
660
661
662
  	/* Notify others that xenstore is up */
  	blocking_notifier_call_chain(&xenstore_chain, 0, NULL);
  }
183d03cc4   Stefano Stabellini   xen: Xen PCI plat...
663
  EXPORT_SYMBOL_GPL(xenbus_probe);
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
664

183d03cc4   Stefano Stabellini   xen: Xen PCI plat...
665
666
667
668
669
670
671
672
673
674
675
676
677
  static int __init xenbus_probe_initcall(void)
  {
  	if (!xen_domain())
  		return -ENODEV;
  
  	if (xen_initial_domain() || xen_hvm_domain())
  		return 0;
  
  	xenbus_probe(NULL);
  	return 0;
  }
  
  device_initcall(xenbus_probe_initcall);
e4184aaf3   Daniel De Graaf   xenbus: don't rel...
678
679
680
681
  /* Set up event channel for xenstored which is run as a local process
   * (this is normally used only in dom0)
   */
  static int __init xenstored_local_init(void)
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
682
683
  {
  	int err = 0;
b37a56d6f   Juan Quintela   xen: Initialize x...
684
  	unsigned long page = 0;
e4184aaf3   Daniel De Graaf   xenbus: don't rel...
685
  	struct evtchn_alloc_unbound alloc_unbound;
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
686

e4184aaf3   Daniel De Graaf   xenbus: don't rel...
687
688
689
690
  	/* Allocate Xenstore page */
  	page = get_zeroed_page(GFP_KERNEL);
  	if (!page)
  		goto out_err;
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
691

e4184aaf3   Daniel De Graaf   xenbus: don't rel...
692
693
694
  	xen_store_mfn = xen_start_info->store_mfn =
  		pfn_to_mfn(virt_to_phys((void *)page) >>
  			   PAGE_SHIFT);
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
695

e4184aaf3   Daniel De Graaf   xenbus: don't rel...
696
697
698
  	/* Next allocate a local port which xenstored can bind to */
  	alloc_unbound.dom        = DOMID_SELF;
  	alloc_unbound.remote_dom = DOMID_SELF;
b37a56d6f   Juan Quintela   xen: Initialize x...
699

e4184aaf3   Daniel De Graaf   xenbus: don't rel...
700
701
702
703
  	err = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound,
  					  &alloc_unbound);
  	if (err == -ENOSYS)
  		goto out_err;
b37a56d6f   Juan Quintela   xen: Initialize x...
704

e4184aaf3   Daniel De Graaf   xenbus: don't rel...
705
706
707
  	BUG_ON(err);
  	xen_store_evtchn = xen_start_info->store_evtchn =
  		alloc_unbound.port;
b37a56d6f   Juan Quintela   xen: Initialize x...
708

e4184aaf3   Daniel De Graaf   xenbus: don't rel...
709
  	return 0;
b37a56d6f   Juan Quintela   xen: Initialize x...
710

e4184aaf3   Daniel De Graaf   xenbus: don't rel...
711
712
713
714
715
   out_err:
  	if (page != 0)
  		free_page(page);
  	return err;
  }
b37a56d6f   Juan Quintela   xen: Initialize x...
716

e4184aaf3   Daniel De Graaf   xenbus: don't rel...
717
718
719
  static int __init xenbus_init(void)
  {
  	int err = 0;
b37a56d6f   Juan Quintela   xen: Initialize x...
720

e4184aaf3   Daniel De Graaf   xenbus: don't rel...
721
722
  	if (!xen_domain())
  		return -ENODEV;
2c5d37d30   Daniel De Graaf   xenbus: Support H...
723
  	xenbus_ring_ops_init();
e4184aaf3   Daniel De Graaf   xenbus: don't rel...
724
725
726
727
728
729
730
731
732
733
734
  	if (xen_hvm_domain()) {
  		uint64_t v = 0;
  		err = hvm_get_parameter(HVM_PARAM_STORE_EVTCHN, &v);
  		if (err)
  			goto out_error;
  		xen_store_evtchn = (int)v;
  		err = hvm_get_parameter(HVM_PARAM_STORE_PFN, &v);
  		if (err)
  			goto out_error;
  		xen_store_mfn = (unsigned long)v;
  		xen_store_interface = ioremap(xen_store_mfn << PAGE_SHIFT, PAGE_SIZE);
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
735
  	} else {
e4184aaf3   Daniel De Graaf   xenbus: don't rel...
736
737
738
739
740
741
  		xen_store_evtchn = xen_start_info->store_evtchn;
  		xen_store_mfn = xen_start_info->store_mfn;
  		if (xen_store_evtchn)
  			xenstored_ready = 1;
  		else {
  			err = xenstored_local_init();
bee6ab53e   Sheng Yang   x86: early PV on ...
742
743
  			if (err)
  				goto out_error;
bee6ab53e   Sheng Yang   x86: early PV on ...
744
  		}
e4184aaf3   Daniel De Graaf   xenbus: don't rel...
745
  		xen_store_interface = mfn_to_virt(xen_store_mfn);
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
746
  	}
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
747
748
749
750
751
752
753
  
  	/* Initialize the interface to xenstore. */
  	err = xs_init();
  	if (err) {
  		printk(KERN_WARNING
  		       "XENBUS: Error initializing xenstore comms: %i
  ", err);
2de06cc1f   Ian Campbell   xen: separate out...
754
  		goto out_error;
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
755
  	}
1107ba885   Alex Zeffertt   xen: add xenfs to...
756
757
758
759
760
761
762
  #ifdef CONFIG_XEN_COMPAT_XENFS
  	/*
  	 * Create xenfs mountpoint in /proc for compatibility with
  	 * utilities that expect to find "xenbus" under "/proc/xen".
  	 */
  	proc_mkdir("xen", NULL);
  #endif
6913200a5   Ruslan Pisarev   Xen: fix braces a...
763
  out_error:
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
764
765
  	return err;
  }
183d03cc4   Stefano Stabellini   xen: Xen PCI plat...
766
  postcore_initcall(xenbus_init);
4bac07c99   Jeremy Fitzhardinge   xen: add the Xenb...
767
768
  
  MODULE_LICENSE("GPL");