1 1.62 bouyer /* $NetBSD: xenbus_probe.c,v 1.62 2025/02/06 15:51:58 bouyer Exp $ */ 2 1.1 bouyer /****************************************************************************** 3 1.1 bouyer * Talks to Xen Store to figure out what devices we have. 4 1.1 bouyer * 5 1.1 bouyer * Copyright (C) 2005 Rusty Russell, IBM Corporation 6 1.1 bouyer * Copyright (C) 2005 Mike Wray, Hewlett-Packard 7 1.1 bouyer * Copyright (C) 2005 XenSource Ltd 8 1.1 bouyer * 9 1.1 bouyer * This file may be distributed separately from the Linux kernel, or 10 1.1 bouyer * incorporated into other software packages, subject to the following license: 11 1.1 bouyer * 12 1.1 bouyer * Permission is hereby granted, free of charge, to any person obtaining a copy 13 1.1 bouyer * of this source file (the "Software"), to deal in the Software without 14 1.1 bouyer * restriction, including without limitation the rights to use, copy, modify, 15 1.1 bouyer * merge, publish, distribute, sublicense, and/or sell copies of the Software, 16 1.1 bouyer * and to permit persons to whom the Software is furnished to do so, subject to 17 1.1 bouyer * the following conditions: 18 1.1 bouyer * 19 1.1 bouyer * The above copyright notice and this permission notice shall be included in 20 1.1 bouyer * all copies or substantial portions of the Software. 21 1.1 bouyer * 22 1.1 bouyer * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 1.1 bouyer * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 1.1 bouyer * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 1.1 bouyer * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 1.1 bouyer * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 27 1.1 bouyer * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 28 1.1 bouyer * IN THE SOFTWARE. 29 1.1 bouyer */ 30 1.1 bouyer 31 1.2 bouyer #include <sys/cdefs.h> 32 1.62 bouyer __KERNEL_RCSID(0, "$NetBSD: xenbus_probe.c,v 1.62 2025/02/06 15:51:58 bouyer Exp $"); 33 1.2 bouyer 34 1.1 bouyer #if 0 35 1.1 bouyer #define DPRINTK(fmt, args...) \ 36 1.18 perry printf("xenbus_probe (%s:%d) " fmt ".\n", __func__, __LINE__, ##args) 37 1.1 bouyer #else 38 1.1 bouyer #define DPRINTK(fmt, args...) ((void)0) 39 1.1 bouyer #endif 40 1.1 bouyer 41 1.2 bouyer #include <sys/types.h> 42 1.2 bouyer #include <sys/null.h> 43 1.2 bouyer #include <sys/errno.h> 44 1.44 jdolecek #include <sys/kmem.h> 45 1.2 bouyer #include <sys/systm.h> 46 1.2 bouyer #include <sys/param.h> 47 1.2 bouyer #include <sys/kthread.h> 48 1.52 bouyer #include <sys/mutex.h> 49 1.7 bouyer #include <uvm/uvm.h> 50 1.7 bouyer 51 1.26 cegger #include <xen/xen.h> /* for xendomain_is_dom0() */ 52 1.17 bouyer #include <xen/hypervisor.h> 53 1.17 bouyer #include <xen/xenbus.h> 54 1.17 bouyer #include <xen/evtchn.h> 55 1.17 bouyer #include <xen/shutdown_xenbus.h> 56 1.1 bouyer 57 1.1 bouyer #include "xenbus_comms.h" 58 1.1 bouyer 59 1.55 bouyer #include "kernfs.h" 60 1.55 bouyer 61 1.20 cegger static int xenbus_match(device_t, cfdata_t, void *); 62 1.20 cegger static void xenbus_attach(device_t, device_t, void *); 63 1.2 bouyer static int xenbus_print(void *, const char *); 64 1.2 bouyer 65 1.34 jym /* power management, for save/restore */ 66 1.34 jym static bool xenbus_suspend(device_t, const pmf_qual_t *); 67 1.34 jym static bool xenbus_resume(device_t, const pmf_qual_t *); 68 1.34 jym 69 1.29 jym /* routines gathering device information from XenStore */ 70 1.29 jym static int read_otherend_details(struct xenbus_device *, 71 1.29 jym const char *, const char *); 72 1.29 jym static int read_backend_details (struct xenbus_device *); 73 1.29 jym static int read_frontend_details(struct xenbus_device *); 74 1.29 jym static void free_otherend_details(struct xenbus_device *); 75 1.29 jym 76 1.29 jym static int watch_otherend (struct xenbus_device *); 77 1.29 jym static void free_otherend_watch(struct xenbus_device *); 78 1.29 jym 79 1.2 bouyer static void xenbus_probe_init(void *); 80 1.2 bouyer 81 1.5 bouyer static struct xenbus_device *xenbus_lookup_device_path(const char *); 82 1.5 bouyer 83 1.20 cegger CFATTACH_DECL_NEW(xenbus, 0, xenbus_match, xenbus_attach, 84 1.2 bouyer NULL, NULL); 85 1.2 bouyer 86 1.24 cegger device_t xenbus_dev; 87 1.48 jdolecek bus_dma_tag_t xenbus_dmat; 88 1.5 bouyer 89 1.5 bouyer SLIST_HEAD(, xenbus_device) xenbus_device_list; 90 1.11 bouyer SLIST_HEAD(, xenbus_backend_driver) xenbus_backend_driver_list = 91 1.11 bouyer SLIST_HEAD_INITIALIZER(xenbus_backend_driver); 92 1.2 bouyer 93 1.2 bouyer int 94 1.20 cegger xenbus_match(device_t parent, cfdata_t match, void *aux) 95 1.2 bouyer { 96 1.2 bouyer struct xenbus_attach_args *xa = (struct xenbus_attach_args *)aux; 97 1.2 bouyer 98 1.2 bouyer if (strcmp(xa->xa_device, "xenbus") == 0) 99 1.2 bouyer return 1; 100 1.2 bouyer return 0; 101 1.2 bouyer } 102 1.2 bouyer 103 1.2 bouyer static void 104 1.20 cegger xenbus_attach(device_t parent, device_t self, void *aux) 105 1.2 bouyer { 106 1.48 jdolecek struct xenbus_attach_args *xa = (struct xenbus_attach_args *)aux; 107 1.15 ad int err; 108 1.15 ad 109 1.2 bouyer aprint_normal(": Xen Virtual Bus Interface\n"); 110 1.24 cegger xenbus_dev = self; 111 1.48 jdolecek xenbus_dmat = xa->xa_dmat; 112 1.38 riz config_pending_incr(self); 113 1.15 ad 114 1.52 bouyer err = kthread_create(PRI_NONE, KTHREAD_MPSAFE, NULL, 115 1.52 bouyer xenbus_probe_init, NULL, NULL, "xenbus_probe"); 116 1.15 ad if (err) 117 1.24 cegger aprint_error_dev(xenbus_dev, 118 1.23 cegger "kthread_create(xenbus_probe): %d\n", err); 119 1.34 jym 120 1.34 jym if (!pmf_device_register(self, xenbus_suspend, xenbus_resume)) 121 1.34 jym aprint_error_dev(self, "couldn't establish power handler\n"); 122 1.34 jym } 123 1.34 jym 124 1.34 jym static bool 125 1.34 jym xenbus_suspend(device_t dev, const pmf_qual_t *qual) 126 1.34 jym { 127 1.34 jym xs_suspend(); 128 1.34 jym xb_suspend_comms(dev); 129 1.34 jym 130 1.34 jym return true; 131 1.34 jym } 132 1.34 jym 133 1.34 jym static bool 134 1.34 jym xenbus_resume(device_t dev, const pmf_qual_t *qual) 135 1.34 jym { 136 1.53 jdolecek xb_resume_comms(dev); 137 1.34 jym xs_resume(); 138 1.34 jym 139 1.34 jym return true; 140 1.34 jym } 141 1.34 jym 142 1.34 jym /* 143 1.34 jym * Suspend a xenbus device 144 1.34 jym */ 145 1.34 jym bool 146 1.34 jym xenbus_device_suspend(struct xenbus_device *dev) { 147 1.34 jym 148 1.34 jym free_otherend_details(dev); 149 1.34 jym return true; 150 1.34 jym } 151 1.34 jym 152 1.34 jym /* 153 1.34 jym * Resume a xenbus device 154 1.34 jym */ 155 1.34 jym bool 156 1.34 jym xenbus_device_resume(struct xenbus_device *dev) { 157 1.34 jym 158 1.34 jym if (dev->xbusd_type == XENBUS_FRONTEND_DEVICE) { 159 1.34 jym read_backend_details(dev); 160 1.34 jym } 161 1.34 jym 162 1.34 jym return true; 163 1.2 bouyer } 164 1.2 bouyer 165 1.2 bouyer void 166 1.11 bouyer xenbus_backend_register(struct xenbus_backend_driver *xbakd) 167 1.11 bouyer { 168 1.11 bouyer SLIST_INSERT_HEAD(&xenbus_backend_driver_list, xbakd, xbakd_entries); 169 1.11 bouyer } 170 1.11 bouyer 171 1.2 bouyer static int 172 1.2 bouyer read_otherend_details(struct xenbus_device *xendev, 173 1.2 bouyer const char *id_node, const char *path_node) 174 1.2 bouyer { 175 1.2 bouyer int err; 176 1.42 jdolecek unsigned long id; 177 1.1 bouyer 178 1.42 jdolecek err = xenbus_read_ul(NULL, xendev->xbusd_path, id_node, &id, 10); 179 1.2 bouyer if (err) { 180 1.2 bouyer printf("reading other end details %s from %s\n", 181 1.2 bouyer id_node, xendev->xbusd_path); 182 1.2 bouyer xenbus_dev_fatal(xendev, err, 183 1.2 bouyer "reading other end details %s from %s", 184 1.2 bouyer id_node, xendev->xbusd_path); 185 1.2 bouyer return err; 186 1.2 bouyer } 187 1.42 jdolecek xendev->xbusd_otherend_id = (int)id; 188 1.42 jdolecek 189 1.42 jdolecek err = xenbus_read(NULL, xendev->xbusd_path, path_node, 190 1.42 jdolecek xendev->xbusd_otherend, sizeof(xendev->xbusd_otherend)); 191 1.1 bouyer if (err) { 192 1.2 bouyer printf("reading other end details %s from %s (%d)\n", 193 1.2 bouyer path_node, xendev->xbusd_path, err); 194 1.1 bouyer xenbus_dev_fatal(xendev, err, 195 1.2 bouyer "reading other end details %s from %s", 196 1.2 bouyer path_node, xendev->xbusd_path); 197 1.1 bouyer return err; 198 1.1 bouyer } 199 1.3 bouyer DPRINTK("read_otherend_details: read %s/%s returned %s\n", 200 1.54 jdolecek xendev->xbusd_path, path_node, xendev->xbusd_otherend); 201 1.2 bouyer 202 1.2 bouyer if (strlen(xendev->xbusd_otherend) == 0 || 203 1.2 bouyer !xenbus_exists(NULL, xendev->xbusd_otherend, "")) { 204 1.2 bouyer printf("missing other end from %s\n", xendev->xbusd_path); 205 1.1 bouyer xenbus_dev_fatal(xendev, -ENOENT, "missing other end from %s", 206 1.2 bouyer xendev->xbusd_path); 207 1.29 jym free_otherend_details(xendev); 208 1.2 bouyer return ENOENT; 209 1.1 bouyer } 210 1.1 bouyer 211 1.1 bouyer return 0; 212 1.1 bouyer } 213 1.1 bouyer 214 1.2 bouyer static int 215 1.2 bouyer read_backend_details(struct xenbus_device *xendev) 216 1.1 bouyer { 217 1.1 bouyer return read_otherend_details(xendev, "backend-id", "backend"); 218 1.1 bouyer } 219 1.1 bouyer 220 1.1 bouyer 221 1.2 bouyer static int 222 1.2 bouyer read_frontend_details(struct xenbus_device *xendev) 223 1.1 bouyer { 224 1.1 bouyer return read_otherend_details(xendev, "frontend-id", "frontend"); 225 1.1 bouyer } 226 1.1 bouyer 227 1.2 bouyer static void 228 1.2 bouyer free_otherend_details(struct xenbus_device *dev) 229 1.1 bouyer { 230 1.42 jdolecek /* Nothing to free */ 231 1.42 jdolecek dev->xbusd_otherend[0] = '\0'; 232 1.1 bouyer } 233 1.1 bouyer 234 1.2 bouyer static void 235 1.2 bouyer free_otherend_watch(struct xenbus_device *dev) 236 1.1 bouyer { 237 1.44 jdolecek if (dev->xbusd_otherend_watch.node) 238 1.44 jdolecek xenbus_unwatch_path(&dev->xbusd_otherend_watch); 239 1.1 bouyer } 240 1.1 bouyer 241 1.2 bouyer static void 242 1.2 bouyer otherend_changed(struct xenbus_watch *watch, 243 1.1 bouyer const char **vec, unsigned int len) 244 1.1 bouyer { 245 1.3 bouyer struct xenbus_device *xdev = watch->xbw_dev; 246 1.1 bouyer XenbusState state; 247 1.1 bouyer 248 1.1 bouyer /* Protect us against watches firing on old details when the otherend 249 1.1 bouyer details change, say immediately after a resume. */ 250 1.59 mrg if (strncmp(xdev->xbusd_otherend, vec[XS_WATCH_PATH], 251 1.3 bouyer strlen(xdev->xbusd_otherend))) { 252 1.1 bouyer DPRINTK("Ignoring watch at %s", vec[XS_WATCH_PATH]); 253 1.1 bouyer return; 254 1.1 bouyer } 255 1.1 bouyer 256 1.3 bouyer state = xenbus_read_driver_state(xdev->xbusd_otherend); 257 1.1 bouyer 258 1.1 bouyer DPRINTK("state is %d, %s, %s", 259 1.3 bouyer state, xdev->xbusd_otherend_watch.node, vec[XS_WATCH_PATH]); 260 1.5 bouyer if (state == XenbusStateClosed) { 261 1.5 bouyer int error; 262 1.11 bouyer if (xdev->xbusd_type == XENBUS_BACKEND_DEVICE) { 263 1.11 bouyer error = xdev->xbusd_u.b.b_detach( 264 1.11 bouyer xdev->xbusd_u.b.b_cookie); 265 1.11 bouyer if (error) { 266 1.11 bouyer printf("could not detach %s: %d\n", 267 1.11 bouyer xdev->xbusd_path, error); 268 1.11 bouyer return; 269 1.11 bouyer } 270 1.11 bouyer } else { 271 1.11 bouyer error = config_detach(xdev->xbusd_u.f.f_dev, 272 1.11 bouyer DETACH_FORCE); 273 1.11 bouyer if (error) { 274 1.11 bouyer printf("could not detach %s: %d\n", 275 1.19 cegger device_xname(xdev->xbusd_u.f.f_dev), error); 276 1.11 bouyer return; 277 1.11 bouyer } 278 1.5 bouyer } 279 1.5 bouyer xenbus_free_device(xdev); 280 1.5 bouyer return; 281 1.5 bouyer } 282 1.3 bouyer if (xdev->xbusd_otherend_changed) 283 1.11 bouyer xdev->xbusd_otherend_changed( 284 1.11 bouyer (xdev->xbusd_type == XENBUS_BACKEND_DEVICE) ? 285 1.11 bouyer xdev->xbusd_u.b.b_cookie : xdev->xbusd_u.f.f_dev, state); 286 1.1 bouyer } 287 1.1 bouyer 288 1.2 bouyer static int 289 1.29 jym watch_otherend(struct xenbus_device *dev) 290 1.1 bouyer { 291 1.1 bouyer free_otherend_watch(dev); 292 1.1 bouyer 293 1.2 bouyer return xenbus_watch_path2(dev, dev->xbusd_otherend, "state", 294 1.3 bouyer &dev->xbusd_otherend_watch, 295 1.3 bouyer otherend_changed); 296 1.1 bouyer } 297 1.1 bouyer 298 1.5 bouyer static struct xenbus_device * 299 1.5 bouyer xenbus_lookup_device_path(const char *path) 300 1.5 bouyer { 301 1.5 bouyer struct xenbus_device *xbusd; 302 1.5 bouyer 303 1.5 bouyer SLIST_FOREACH(xbusd, &xenbus_device_list, xbusd_entries) { 304 1.5 bouyer if (strcmp(xbusd->xbusd_path, path) == 0) 305 1.5 bouyer return xbusd; 306 1.5 bouyer } 307 1.5 bouyer return NULL; 308 1.5 bouyer } 309 1.5 bouyer 310 1.2 bouyer static int 311 1.11 bouyer xenbus_probe_device_type(const char *path, const char *type, 312 1.11 bouyer int (*create)(struct xenbus_device *)) 313 1.1 bouyer { 314 1.36 sborrill int err, i, pos, msize; 315 1.36 sborrill int *lookup = NULL; 316 1.45 jdolecek size_t lookup_sz = 0; 317 1.11 bouyer unsigned long state; 318 1.1 bouyer char **dir; 319 1.46 jdolecek unsigned int orig_dir_n = 0, dir_n; 320 1.2 bouyer struct xenbus_device *xbusd; 321 1.2 bouyer struct xenbusdev_attach_args xa; 322 1.2 bouyer char *ep; 323 1.2 bouyer 324 1.11 bouyer DPRINTK("probe %s type %s", path, type); 325 1.46 jdolecek err = xenbus_directory(NULL, path, "", &orig_dir_n, &dir); 326 1.54 jdolecek DPRINTK("directory err %d dir_n %d", err, orig_dir_n); 327 1.2 bouyer if (err) 328 1.2 bouyer return err; 329 1.46 jdolecek dir_n = orig_dir_n; 330 1.1 bouyer 331 1.36 sborrill /* Only sort frontend devices i.e. create == NULL*/ 332 1.36 sborrill if (dir_n > 1 && create == NULL) { 333 1.36 sborrill int minp; 334 1.36 sborrill unsigned long minv; 335 1.36 sborrill unsigned long *id; 336 1.45 jdolecek size_t id_sz; 337 1.36 sborrill 338 1.45 jdolecek lookup_sz = sizeof(int) * dir_n; 339 1.45 jdolecek lookup = kmem_zalloc(lookup_sz, KM_SLEEP); 340 1.45 jdolecek 341 1.45 jdolecek id_sz = sizeof(unsigned long) * dir_n; 342 1.45 jdolecek id = kmem_zalloc(id_sz, KM_SLEEP); 343 1.36 sborrill 344 1.36 sborrill /* Convert string values to numeric; skip invalid */ 345 1.36 sborrill for (i = 0; i < dir_n; i++) { 346 1.37 sborrill /* 347 1.37 sborrill * Add one to differentiate numerical zero from invalid 348 1.37 sborrill * string. Has no effect on sort order. 349 1.37 sborrill */ 350 1.37 sborrill id[i] = strtoul(dir[i], &ep, 10) + 1; 351 1.36 sborrill if (dir[i][0] == '\0' || *ep != '\0') 352 1.36 sborrill id[i] = 0; 353 1.36 sborrill } 354 1.36 sborrill 355 1.36 sborrill /* Build lookup table in ascending order */ 356 1.36 sborrill for (pos = 0; pos < dir_n; ) { 357 1.36 sborrill minv = UINT32_MAX; 358 1.36 sborrill minp = -1; 359 1.36 sborrill for (i = 0; i < dir_n; i++) { 360 1.36 sborrill if (id[i] < minv && id[i] > 0) { 361 1.36 sborrill minv = id[i]; 362 1.36 sborrill minp = i; 363 1.36 sborrill } 364 1.36 sborrill } 365 1.36 sborrill if (minp >= 0) { 366 1.36 sborrill lookup[pos++] = minp; 367 1.36 sborrill id[minp] = 0; 368 1.36 sborrill } 369 1.36 sborrill else 370 1.36 sborrill break; 371 1.36 sborrill } 372 1.45 jdolecek 373 1.45 jdolecek kmem_free(id, id_sz); 374 1.45 jdolecek 375 1.36 sborrill /* Adjust in case we had to skip non-numeric entries */ 376 1.36 sborrill dir_n = pos; 377 1.36 sborrill } 378 1.36 sborrill 379 1.36 sborrill for (pos = 0; pos < dir_n; pos++) { 380 1.30 cegger err = 0; 381 1.36 sborrill if (lookup) 382 1.36 sborrill i = lookup[pos]; 383 1.36 sborrill else 384 1.36 sborrill i = pos; 385 1.5 bouyer /* 386 1.5 bouyer * add size of path to size of xenbus_device. xenbus_device 387 1.5 bouyer * already has room for one char in xbusd_path. 388 1.5 bouyer */ 389 1.11 bouyer msize = sizeof(*xbusd) + strlen(path) + strlen(dir[i]) + 2; 390 1.45 jdolecek xbusd = kmem_zalloc(msize, KM_SLEEP); 391 1.45 jdolecek xbusd->xbusd_sz = msize; 392 1.49 jdolecek xbusd->xbusd_dmat = xenbus_dmat; 393 1.45 jdolecek 394 1.2 bouyer snprintf(__UNCONST(xbusd->xbusd_path), 395 1.11 bouyer msize - sizeof(*xbusd) + 1, "%s/%s", path, dir[i]); 396 1.5 bouyer if (xenbus_lookup_device_path(xbusd->xbusd_path) != NULL) { 397 1.5 bouyer /* device already registered */ 398 1.45 jdolecek kmem_free(xbusd, xbusd->xbusd_sz); 399 1.5 bouyer continue; 400 1.5 bouyer } 401 1.11 bouyer err = xenbus_read_ul(NULL, xbusd->xbusd_path, "state", 402 1.12 bouyer &state, 10); 403 1.11 bouyer if (err) { 404 1.51 bouyer aprint_error_dev(xenbus_dev, "can't get state " 405 1.11 bouyer "for %s (%d)\n", xbusd->xbusd_path, err); 406 1.45 jdolecek kmem_free(xbusd, xbusd->xbusd_sz); 407 1.31 cegger err = 0; 408 1.11 bouyer continue; 409 1.11 bouyer } 410 1.11 bouyer if (state != XenbusStateInitialising) { 411 1.11 bouyer /* device is not new */ 412 1.45 jdolecek kmem_free(xbusd, xbusd->xbusd_sz); 413 1.11 bouyer continue; 414 1.11 bouyer } 415 1.5 bouyer 416 1.3 bouyer xbusd->xbusd_otherend_watch.xbw_dev = xbusd; 417 1.2 bouyer DPRINTK("xenbus_probe_device_type probe %s\n", 418 1.2 bouyer xbusd->xbusd_path); 419 1.11 bouyer if (create != NULL) { 420 1.11 bouyer xbusd->xbusd_type = XENBUS_BACKEND_DEVICE; 421 1.11 bouyer err = read_frontend_details(xbusd); 422 1.11 bouyer if (err != 0) { 423 1.51 bouyer aprint_error_dev(xenbus_dev, 424 1.51 bouyer "can't get frontend details for %s (%d)\n", 425 1.51 bouyer xbusd->xbusd_path, err); 426 1.11 bouyer break; 427 1.11 bouyer } 428 1.11 bouyer if (create(xbusd)) { 429 1.45 jdolecek kmem_free(xbusd, xbusd->xbusd_sz); 430 1.11 bouyer continue; 431 1.11 bouyer } 432 1.11 bouyer } else { 433 1.11 bouyer xbusd->xbusd_type = XENBUS_FRONTEND_DEVICE; 434 1.11 bouyer xa.xa_xbusd = xbusd; 435 1.11 bouyer xa.xa_type = type; 436 1.11 bouyer xa.xa_id = strtoul(dir[i], &ep, 0); 437 1.11 bouyer if (dir[i][0] == '\0' || *ep != '\0') { 438 1.51 bouyer aprint_error_dev(xenbus_dev, 439 1.51 bouyer "device type %s: id %s is not a number\n", 440 1.51 bouyer type, dir[i]); 441 1.11 bouyer err = EFTYPE; 442 1.45 jdolecek kmem_free(xbusd, xbusd->xbusd_sz); 443 1.11 bouyer break; 444 1.11 bouyer } 445 1.51 bouyer if (strcmp(xa.xa_type, "vbd") == 0) { 446 1.51 bouyer char dtype[10]; 447 1.51 bouyer if (xenbus_read(NULL, xbusd->xbusd_path, 448 1.51 bouyer "device-type", dtype, sizeof(dtype)) !=0) { 449 1.51 bouyer aprint_error_dev(xenbus_dev, 450 1.51 bouyer "%s: can't read device-type\n", 451 1.51 bouyer xbusd->xbusd_path); 452 1.51 bouyer kmem_free(xbusd, xbusd->xbusd_sz); 453 1.51 bouyer break; 454 1.51 bouyer } 455 1.62 bouyer if (vm_guest == VM_GUEST_XENPVHVM && 456 1.62 bouyer strcmp(dtype, "cdrom") == 0) { 457 1.51 bouyer aprint_verbose_dev(xenbus_dev, 458 1.51 bouyer "ignoring %s type cdrom\n", 459 1.51 bouyer xbusd->xbusd_path); 460 1.51 bouyer kmem_free(xbusd, xbusd->xbusd_sz); 461 1.51 bouyer continue; 462 1.51 bouyer } 463 1.51 bouyer } 464 1.11 bouyer err = read_backend_details(xbusd); 465 1.11 bouyer if (err != 0) { 466 1.51 bouyer aprint_error_dev(xenbus_dev, 467 1.51 bouyer "can't get backend details for %s (%d)\n", 468 1.51 bouyer xbusd->xbusd_path, err); 469 1.45 jdolecek kmem_free(xbusd, xbusd->xbusd_sz); 470 1.11 bouyer break; 471 1.11 bouyer } 472 1.57 bouyer 473 1.57 bouyer KERNEL_LOCK(1, curlwp); 474 1.56 thorpej xbusd->xbusd_u.f.f_dev = config_found(xenbus_dev, 475 1.58 thorpej &xa, xenbus_print, CFARGS_NONE); 476 1.57 bouyer KERNEL_UNLOCK_ONE(curlwp); 477 1.11 bouyer if (xbusd->xbusd_u.f.f_dev == NULL) { 478 1.45 jdolecek kmem_free(xbusd, xbusd->xbusd_sz); 479 1.11 bouyer continue; 480 1.11 bouyer } 481 1.3 bouyer } 482 1.11 bouyer SLIST_INSERT_HEAD(&xenbus_device_list, 483 1.11 bouyer xbusd, xbusd_entries); 484 1.29 jym watch_otherend(xbusd); 485 1.1 bouyer } 486 1.46 jdolecek xenbus_directory_free(orig_dir_n, dir); 487 1.36 sborrill if (lookup) 488 1.45 jdolecek kmem_free(lookup, lookup_sz); 489 1.36 sborrill 490 1.1 bouyer return err; 491 1.1 bouyer } 492 1.1 bouyer 493 1.2 bouyer static int 494 1.2 bouyer xenbus_print(void *aux, const char *pnp) 495 1.2 bouyer { 496 1.2 bouyer struct xenbusdev_attach_args *xa = aux; 497 1.2 bouyer 498 1.2 bouyer if (pnp) { 499 1.2 bouyer if (strcmp(xa->xa_type, "vbd") == 0) 500 1.2 bouyer aprint_normal("xbd"); 501 1.2 bouyer else if (strcmp(xa->xa_type, "vif") == 0) 502 1.2 bouyer aprint_normal("xennet"); 503 1.32 jym else if (strcmp(xa->xa_type, "balloon") == 0) 504 1.32 jym aprint_normal("balloon"); 505 1.2 bouyer else 506 1.2 bouyer aprint_normal("unknown type %s", xa->xa_type); 507 1.2 bouyer aprint_normal(" at %s", pnp); 508 1.2 bouyer } 509 1.2 bouyer aprint_normal(" id %d", xa->xa_id); 510 1.2 bouyer return(UNCONF); 511 1.2 bouyer } 512 1.2 bouyer 513 1.2 bouyer static int 514 1.11 bouyer xenbus_probe_frontends(void) 515 1.1 bouyer { 516 1.2 bouyer int err; 517 1.1 bouyer char **dir; 518 1.1 bouyer unsigned int i, dir_n; 519 1.11 bouyer char path[30]; 520 1.1 bouyer 521 1.11 bouyer DPRINTK("probe device"); 522 1.11 bouyer err = xenbus_directory(NULL, "device", "", &dir_n, &dir); 523 1.2 bouyer DPRINTK("directory err %d dir_n %d", err, dir_n); 524 1.2 bouyer if (err) 525 1.2 bouyer return err; 526 1.1 bouyer 527 1.1 bouyer for (i = 0; i < dir_n; i++) { 528 1.27 jym /* 529 1.27 jym * console is configured through xen_start_info when 530 1.27 jym * xencons is attaching to hypervisor, so avoid console 531 1.27 jym * probing when configuring xenbus devices 532 1.27 jym */ 533 1.27 jym if (strcmp(dir[i], "console") == 0) 534 1.27 jym continue; 535 1.27 jym 536 1.11 bouyer snprintf(path, sizeof(path), "device/%s", dir[i]); 537 1.11 bouyer err = xenbus_probe_device_type(path, dir[i], NULL); 538 1.1 bouyer if (err) 539 1.1 bouyer break; 540 1.1 bouyer } 541 1.46 jdolecek xenbus_directory_free(dir_n, dir); 542 1.1 bouyer return err; 543 1.1 bouyer } 544 1.1 bouyer 545 1.11 bouyer static int 546 1.11 bouyer xenbus_probe_backends(void) 547 1.11 bouyer { 548 1.11 bouyer int err; 549 1.11 bouyer char **dirt, **dirid; 550 1.11 bouyer unsigned int type, id, dirt_n, dirid_n; 551 1.11 bouyer char path[30]; 552 1.11 bouyer struct xenbus_backend_driver *xbakd; 553 1.11 bouyer 554 1.11 bouyer DPRINTK("probe backend"); 555 1.11 bouyer err = xenbus_directory(NULL, "backend", "", &dirt_n, &dirt); 556 1.11 bouyer DPRINTK("directory err %d dirt_n %d", err, dirt_n); 557 1.11 bouyer if (err) 558 1.11 bouyer return err; 559 1.11 bouyer 560 1.11 bouyer for (type = 0; type < dirt_n; type++) { 561 1.11 bouyer SLIST_FOREACH(xbakd, &xenbus_backend_driver_list, 562 1.11 bouyer xbakd_entries) { 563 1.11 bouyer if (strcmp(dirt[type], xbakd->xbakd_type) == 0) 564 1.11 bouyer break; 565 1.11 bouyer } 566 1.11 bouyer if (xbakd == NULL) 567 1.11 bouyer continue; 568 1.11 bouyer err = xenbus_directory(NULL, "backend", dirt[type], 569 1.11 bouyer &dirid_n, &dirid); 570 1.11 bouyer DPRINTK("directory backend/%s err %d dirid_n %d", 571 1.11 bouyer dirt[type], err, dirid_n); 572 1.46 jdolecek if (err) 573 1.46 jdolecek goto out; 574 1.46 jdolecek 575 1.11 bouyer for (id = 0; id < dirid_n; id++) { 576 1.11 bouyer snprintf(path, sizeof(path), "backend/%s/%s", 577 1.11 bouyer dirt[type], dirid[id]); 578 1.11 bouyer err = xenbus_probe_device_type(path, dirt[type], 579 1.11 bouyer xbakd->xbakd_create); 580 1.11 bouyer if (err) 581 1.11 bouyer break; 582 1.11 bouyer } 583 1.46 jdolecek xenbus_directory_free(dirid_n, dirid); 584 1.11 bouyer } 585 1.46 jdolecek 586 1.46 jdolecek out: 587 1.46 jdolecek xenbus_directory_free(dirt_n, dirt); 588 1.11 bouyer return err; 589 1.11 bouyer } 590 1.11 bouyer 591 1.5 bouyer int 592 1.5 bouyer xenbus_free_device(struct xenbus_device *xbusd) 593 1.5 bouyer { 594 1.5 bouyer KASSERT(xenbus_lookup_device_path(xbusd->xbusd_path) == xbusd); 595 1.5 bouyer SLIST_REMOVE(&xenbus_device_list, xbusd, xenbus_device, xbusd_entries); 596 1.5 bouyer free_otherend_watch(xbusd); 597 1.29 jym free_otherend_details(xbusd); 598 1.5 bouyer xenbus_switch_state(xbusd, NULL, XenbusStateClosed); 599 1.45 jdolecek kmem_free(xbusd, xbusd->xbusd_sz); 600 1.5 bouyer return 0; 601 1.5 bouyer } 602 1.5 bouyer 603 1.2 bouyer static void 604 1.2 bouyer frontend_changed(struct xenbus_watch *watch, 605 1.1 bouyer const char **vec, unsigned int len) 606 1.1 bouyer { 607 1.11 bouyer DPRINTK("frontend_changed %s\n", vec[XS_WATCH_PATH]); 608 1.11 bouyer xenbus_probe_frontends(); 609 1.1 bouyer } 610 1.1 bouyer 611 1.2 bouyer static void 612 1.2 bouyer backend_changed(struct xenbus_watch *watch, 613 1.1 bouyer const char **vec, unsigned int len) 614 1.1 bouyer { 615 1.11 bouyer DPRINTK("backend_changed %s\n", vec[XS_WATCH_PATH]); 616 1.11 bouyer xenbus_probe_backends(); 617 1.1 bouyer } 618 1.1 bouyer 619 1.2 bouyer 620 1.1 bouyer /* We watch for devices appearing and vanishing. */ 621 1.3 bouyer static struct xenbus_watch fe_watch; 622 1.1 bouyer 623 1.3 bouyer static struct xenbus_watch be_watch; 624 1.1 bouyer 625 1.1 bouyer /* A flag to determine if xenstored is 'ready' (i.e. has started) */ 626 1.39 msaitoh int xenstored_ready = 0; 627 1.52 bouyer static kmutex_t xenstored_lock; 628 1.52 bouyer static kcondvar_t xenstored_cv; 629 1.1 bouyer 630 1.2 bouyer void 631 1.2 bouyer xenbus_probe(void *unused) 632 1.1 bouyer { 633 1.32 jym struct xenbusdev_attach_args balloon_xa = { 634 1.32 jym .xa_id = 0, 635 1.32 jym .xa_type = "balloon" 636 1.32 jym }; 637 1.32 jym 638 1.39 msaitoh KASSERT((xenstored_ready > 0)); 639 1.1 bouyer 640 1.1 bouyer /* Enumerate devices in xenstore. */ 641 1.11 bouyer xenbus_probe_frontends(); 642 1.11 bouyer xenbus_probe_backends(); 643 1.1 bouyer 644 1.1 bouyer /* Watch for changes. */ 645 1.44 jdolecek fe_watch.node_sz = strlen("device") + 1; 646 1.44 jdolecek fe_watch.node = kmem_alloc(fe_watch.node_sz, KM_SLEEP); 647 1.43 jdolecek strcpy(fe_watch.node, "device"); 648 1.3 bouyer fe_watch.xbw_callback = frontend_changed; 649 1.1 bouyer register_xenbus_watch(&fe_watch); 650 1.44 jdolecek 651 1.44 jdolecek be_watch.node_sz = strlen("backend") + 1; 652 1.44 jdolecek be_watch.node = kmem_alloc(be_watch.node_sz, KM_SLEEP); 653 1.43 jdolecek strcpy(be_watch.node, "backend"); 654 1.3 bouyer be_watch.xbw_callback = backend_changed; 655 1.1 bouyer register_xenbus_watch(&be_watch); 656 1.32 jym 657 1.32 jym /* attach balloon. */ 658 1.57 bouyer KERNEL_LOCK(1, curlwp); 659 1.56 thorpej config_found(xenbus_dev, &balloon_xa, xenbus_print, 660 1.58 thorpej CFARGS_NONE); 661 1.57 bouyer KERNEL_UNLOCK_ONE(curlwp); 662 1.32 jym 663 1.13 yamt shutdown_xenbus_setup(); 664 1.1 bouyer 665 1.1 bouyer /* Notify others that xenstore is up */ 666 1.2 bouyer //notifier_call_chain(&xenstore_chain, 0, NULL); 667 1.1 bouyer } 668 1.1 bouyer 669 1.52 bouyer void 670 1.52 bouyer xb_xenstored_make_ready(void) 671 1.52 bouyer { 672 1.52 bouyer mutex_enter(&xenstored_lock); 673 1.52 bouyer xenstored_ready = 1; 674 1.52 bouyer cv_broadcast(&xenstored_cv); 675 1.52 bouyer mutex_exit(&xenstored_lock); 676 1.52 bouyer } 677 1.52 bouyer 678 1.2 bouyer static void 679 1.2 bouyer xenbus_probe_init(void *unused) 680 1.1 bouyer { 681 1.23 cegger int err = 0; 682 1.23 cegger bool dom0; 683 1.23 cegger vaddr_t page = 0; 684 1.1 bouyer 685 1.1 bouyer DPRINTK(""); 686 1.1 bouyer 687 1.5 bouyer SLIST_INIT(&xenbus_device_list); 688 1.52 bouyer mutex_init(&xenstored_lock, MUTEX_DEFAULT, IPL_TTY); 689 1.52 bouyer cv_init(&xenstored_cv, "xsready"); 690 1.5 bouyer 691 1.1 bouyer /* 692 1.1 bouyer ** Domain0 doesn't have a store_evtchn or store_mfn yet. 693 1.1 bouyer */ 694 1.23 cegger dom0 = xendomain_is_dom0(); 695 1.1 bouyer if (dom0) { 696 1.7 bouyer #if defined(DOM0OPS) 697 1.7 bouyer paddr_t ma; 698 1.22 tron evtchn_op_t op = { .cmd = 0 }; 699 1.1 bouyer 700 1.1 bouyer /* Allocate page. */ 701 1.7 bouyer page = uvm_km_alloc(kernel_map, PAGE_SIZE, 0, 702 1.7 bouyer UVM_KMF_ZERO | UVM_KMF_WIRED); 703 1.1 bouyer if (!page) 704 1.7 bouyer panic("can't get xenstore page"); 705 1.1 bouyer 706 1.7 bouyer (void)pmap_extract_ma(pmap_kernel(), page, &ma); 707 1.7 bouyer xen_start_info.store_mfn = ma >> PAGE_SHIFT; 708 1.7 bouyer xenstore_interface = (void *)page; 709 1.1 bouyer 710 1.1 bouyer /* Next allocate a local port which xenstored can bind to */ 711 1.1 bouyer op.cmd = EVTCHNOP_alloc_unbound; 712 1.1 bouyer op.u.alloc_unbound.dom = DOMID_SELF; 713 1.39 msaitoh op.u.alloc_unbound.remote_dom = 0; 714 1.1 bouyer 715 1.23 cegger err = HYPERVISOR_event_channel_op(&op); 716 1.23 cegger if (err) { 717 1.24 cegger aprint_error_dev(xenbus_dev, 718 1.23 cegger "can't register xenstore event\n"); 719 1.23 cegger goto err0; 720 1.23 cegger } 721 1.23 cegger 722 1.7 bouyer xen_start_info.store_evtchn = op.u.alloc_unbound.port; 723 1.1 bouyer 724 1.21 cegger DELAY(1000); 725 1.7 bouyer #else /* DOM0OPS */ 726 1.60 bouyer panic("dom0 support not compiled in"); 727 1.7 bouyer #endif /* DOM0OPS */ 728 1.1 bouyer } 729 1.1 bouyer 730 1.55 bouyer #if NKERNFS > 0 731 1.35 jym /* Publish xenbus and Xenstore info in /kern/xen */ 732 1.35 jym xenbus_kernfs_init(); 733 1.55 bouyer #endif 734 1.35 jym 735 1.10 bouyer /* register event handler */ 736 1.24 cegger xb_init_comms(xenbus_dev); 737 1.10 bouyer 738 1.1 bouyer /* Initialize the interface to xenstore. */ 739 1.39 msaitoh err = xs_init(xenbus_dev); 740 1.1 bouyer if (err) { 741 1.24 cegger aprint_error_dev(xenbus_dev, 742 1.39 msaitoh "Error initializing xenstore comms: %i\n", err); 743 1.23 cegger goto err0; 744 1.1 bouyer } 745 1.1 bouyer 746 1.1 bouyer if (!dom0) { 747 1.1 bouyer xenstored_ready = 1; 748 1.1 bouyer xenbus_probe(NULL); 749 1.1 bouyer } 750 1.1 bouyer 751 1.2 bouyer DPRINTK("done"); 752 1.38 riz config_pending_decr(xenbus_dev); 753 1.11 bouyer #ifdef DOM0OPS 754 1.11 bouyer if (dom0) { 755 1.52 bouyer mutex_enter(&xenstored_lock); 756 1.11 bouyer while (xenstored_ready == 0) { 757 1.52 bouyer cv_wait(&xenstored_cv, &xenstored_lock); 758 1.52 bouyer mutex_exit(&xenstored_lock); 759 1.11 bouyer xenbus_probe(NULL); 760 1.52 bouyer mutex_enter(&xenstored_lock); 761 1.11 bouyer } 762 1.52 bouyer mutex_exit(&xenstored_lock); 763 1.11 bouyer } 764 1.11 bouyer #endif 765 1.2 bouyer kthread_exit(0); 766 1.23 cegger 767 1.23 cegger err0: 768 1.23 cegger if (page) 769 1.23 cegger uvm_km_free(kernel_map, page, PAGE_SIZE, 770 1.23 cegger UVM_KMF_ZERO | UVM_KMF_WIRED); 771 1.23 cegger kthread_exit(err); 772 1.1 bouyer } 773 1.1 bouyer 774 1.1 bouyer /* 775 1.1 bouyer * Local variables: 776 1.1 bouyer * c-file-style: "linux" 777 1.1 bouyer * indent-tabs-mode: t 778 1.1 bouyer * c-indent-level: 8 779 1.1 bouyer * c-basic-offset: 8 780 1.1 bouyer * tab-width: 8 781 1.1 bouyer * End: 782 1.1 bouyer */ 783