162306a36Sopenharmony_ci/****************************************************************************** 262306a36Sopenharmony_ci * Client-facing interface for the Xenbus driver. In other words, the 362306a36Sopenharmony_ci * interface between the Xenbus and the device-specific code, be it the 462306a36Sopenharmony_ci * frontend or the backend of that driver. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (C) 2005 XenSource Ltd 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * This program is free software; you can redistribute it and/or 962306a36Sopenharmony_ci * modify it under the terms of the GNU General Public License version 2 1062306a36Sopenharmony_ci * as published by the Free Software Foundation; or, when distributed 1162306a36Sopenharmony_ci * separately from the Linux kernel or incorporated into other 1262306a36Sopenharmony_ci * software packages, subject to the following license: 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy 1562306a36Sopenharmony_ci * of this source file (the "Software"), to deal in the Software without 1662306a36Sopenharmony_ci * restriction, including without limitation the rights to use, copy, modify, 1762306a36Sopenharmony_ci * merge, publish, distribute, sublicense, and/or sell copies of the Software, 1862306a36Sopenharmony_ci * and to permit persons to whom the Software is furnished to do so, subject to 1962306a36Sopenharmony_ci * the following conditions: 2062306a36Sopenharmony_ci * 2162306a36Sopenharmony_ci * The above copyright notice and this permission notice shall be included in 2262306a36Sopenharmony_ci * all copies or substantial portions of the Software. 2362306a36Sopenharmony_ci * 2462306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 2562306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 2662306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 2762306a36Sopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 2862306a36Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 2962306a36Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 3062306a36Sopenharmony_ci * IN THE SOFTWARE. 3162306a36Sopenharmony_ci */ 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#include <linux/mm.h> 3462306a36Sopenharmony_ci#include <linux/slab.h> 3562306a36Sopenharmony_ci#include <linux/types.h> 3662306a36Sopenharmony_ci#include <linux/spinlock.h> 3762306a36Sopenharmony_ci#include <linux/vmalloc.h> 3862306a36Sopenharmony_ci#include <linux/export.h> 3962306a36Sopenharmony_ci#include <asm/xen/hypervisor.h> 4062306a36Sopenharmony_ci#include <xen/page.h> 4162306a36Sopenharmony_ci#include <xen/interface/xen.h> 4262306a36Sopenharmony_ci#include <xen/interface/event_channel.h> 4362306a36Sopenharmony_ci#include <xen/balloon.h> 4462306a36Sopenharmony_ci#include <xen/events.h> 4562306a36Sopenharmony_ci#include <xen/grant_table.h> 4662306a36Sopenharmony_ci#include <xen/xenbus.h> 4762306a36Sopenharmony_ci#include <xen/xen.h> 4862306a36Sopenharmony_ci#include <xen/features.h> 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci#include "xenbus.h" 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci#define XENBUS_PAGES(_grants) (DIV_ROUND_UP(_grants, XEN_PFN_PER_PAGE)) 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci#define XENBUS_MAX_RING_PAGES (XENBUS_PAGES(XENBUS_MAX_RING_GRANTS)) 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistruct xenbus_map_node { 5762306a36Sopenharmony_ci struct list_head next; 5862306a36Sopenharmony_ci union { 5962306a36Sopenharmony_ci struct { 6062306a36Sopenharmony_ci struct vm_struct *area; 6162306a36Sopenharmony_ci } pv; 6262306a36Sopenharmony_ci struct { 6362306a36Sopenharmony_ci struct page *pages[XENBUS_MAX_RING_PAGES]; 6462306a36Sopenharmony_ci unsigned long addrs[XENBUS_MAX_RING_GRANTS]; 6562306a36Sopenharmony_ci void *addr; 6662306a36Sopenharmony_ci } hvm; 6762306a36Sopenharmony_ci }; 6862306a36Sopenharmony_ci grant_handle_t handles[XENBUS_MAX_RING_GRANTS]; 6962306a36Sopenharmony_ci unsigned int nr_handles; 7062306a36Sopenharmony_ci}; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistruct map_ring_valloc { 7362306a36Sopenharmony_ci struct xenbus_map_node *node; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci /* Why do we need two arrays? See comment of __xenbus_map_ring */ 7662306a36Sopenharmony_ci unsigned long addrs[XENBUS_MAX_RING_GRANTS]; 7762306a36Sopenharmony_ci phys_addr_t phys_addrs[XENBUS_MAX_RING_GRANTS]; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci struct gnttab_map_grant_ref map[XENBUS_MAX_RING_GRANTS]; 8062306a36Sopenharmony_ci struct gnttab_unmap_grant_ref unmap[XENBUS_MAX_RING_GRANTS]; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci unsigned int idx; 8362306a36Sopenharmony_ci}; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_cistatic DEFINE_SPINLOCK(xenbus_valloc_lock); 8662306a36Sopenharmony_cistatic LIST_HEAD(xenbus_valloc_pages); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_cistruct xenbus_ring_ops { 8962306a36Sopenharmony_ci int (*map)(struct xenbus_device *dev, struct map_ring_valloc *info, 9062306a36Sopenharmony_ci grant_ref_t *gnt_refs, unsigned int nr_grefs, 9162306a36Sopenharmony_ci void **vaddr); 9262306a36Sopenharmony_ci int (*unmap)(struct xenbus_device *dev, void *vaddr); 9362306a36Sopenharmony_ci}; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cistatic const struct xenbus_ring_ops *ring_ops __read_mostly; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ciconst char *xenbus_strstate(enum xenbus_state state) 9862306a36Sopenharmony_ci{ 9962306a36Sopenharmony_ci static const char *const name[] = { 10062306a36Sopenharmony_ci [ XenbusStateUnknown ] = "Unknown", 10162306a36Sopenharmony_ci [ XenbusStateInitialising ] = "Initialising", 10262306a36Sopenharmony_ci [ XenbusStateInitWait ] = "InitWait", 10362306a36Sopenharmony_ci [ XenbusStateInitialised ] = "Initialised", 10462306a36Sopenharmony_ci [ XenbusStateConnected ] = "Connected", 10562306a36Sopenharmony_ci [ XenbusStateClosing ] = "Closing", 10662306a36Sopenharmony_ci [ XenbusStateClosed ] = "Closed", 10762306a36Sopenharmony_ci [XenbusStateReconfiguring] = "Reconfiguring", 10862306a36Sopenharmony_ci [XenbusStateReconfigured] = "Reconfigured", 10962306a36Sopenharmony_ci }; 11062306a36Sopenharmony_ci return (state < ARRAY_SIZE(name)) ? name[state] : "INVALID"; 11162306a36Sopenharmony_ci} 11262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(xenbus_strstate); 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci/** 11562306a36Sopenharmony_ci * xenbus_watch_path - register a watch 11662306a36Sopenharmony_ci * @dev: xenbus device 11762306a36Sopenharmony_ci * @path: path to watch 11862306a36Sopenharmony_ci * @watch: watch to register 11962306a36Sopenharmony_ci * @callback: callback to register 12062306a36Sopenharmony_ci * 12162306a36Sopenharmony_ci * Register a @watch on the given path, using the given xenbus_watch structure 12262306a36Sopenharmony_ci * for storage, and the given @callback function as the callback. Return 0 on 12362306a36Sopenharmony_ci * success, or -errno on error. On success, the given @path will be saved as 12462306a36Sopenharmony_ci * @watch->node, and remains the caller's to free. On error, @watch->node will 12562306a36Sopenharmony_ci * be NULL, the device will switch to %XenbusStateClosing, and the error will 12662306a36Sopenharmony_ci * be saved in the store. 12762306a36Sopenharmony_ci */ 12862306a36Sopenharmony_ciint xenbus_watch_path(struct xenbus_device *dev, const char *path, 12962306a36Sopenharmony_ci struct xenbus_watch *watch, 13062306a36Sopenharmony_ci bool (*will_handle)(struct xenbus_watch *, 13162306a36Sopenharmony_ci const char *, const char *), 13262306a36Sopenharmony_ci void (*callback)(struct xenbus_watch *, 13362306a36Sopenharmony_ci const char *, const char *)) 13462306a36Sopenharmony_ci{ 13562306a36Sopenharmony_ci int err; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci watch->node = path; 13862306a36Sopenharmony_ci watch->will_handle = will_handle; 13962306a36Sopenharmony_ci watch->callback = callback; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci err = register_xenbus_watch(watch); 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci if (err) { 14462306a36Sopenharmony_ci watch->node = NULL; 14562306a36Sopenharmony_ci watch->will_handle = NULL; 14662306a36Sopenharmony_ci watch->callback = NULL; 14762306a36Sopenharmony_ci xenbus_dev_fatal(dev, err, "adding watch on %s", path); 14862306a36Sopenharmony_ci } 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci return err; 15162306a36Sopenharmony_ci} 15262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(xenbus_watch_path); 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci/** 15662306a36Sopenharmony_ci * xenbus_watch_pathfmt - register a watch on a sprintf-formatted path 15762306a36Sopenharmony_ci * @dev: xenbus device 15862306a36Sopenharmony_ci * @watch: watch to register 15962306a36Sopenharmony_ci * @callback: callback to register 16062306a36Sopenharmony_ci * @pathfmt: format of path to watch 16162306a36Sopenharmony_ci * 16262306a36Sopenharmony_ci * Register a watch on the given @path, using the given xenbus_watch 16362306a36Sopenharmony_ci * structure for storage, and the given @callback function as the callback. 16462306a36Sopenharmony_ci * Return 0 on success, or -errno on error. On success, the watched path 16562306a36Sopenharmony_ci * (@path/@path2) will be saved as @watch->node, and becomes the caller's to 16662306a36Sopenharmony_ci * kfree(). On error, watch->node will be NULL, so the caller has nothing to 16762306a36Sopenharmony_ci * free, the device will switch to %XenbusStateClosing, and the error will be 16862306a36Sopenharmony_ci * saved in the store. 16962306a36Sopenharmony_ci */ 17062306a36Sopenharmony_ciint xenbus_watch_pathfmt(struct xenbus_device *dev, 17162306a36Sopenharmony_ci struct xenbus_watch *watch, 17262306a36Sopenharmony_ci bool (*will_handle)(struct xenbus_watch *, 17362306a36Sopenharmony_ci const char *, const char *), 17462306a36Sopenharmony_ci void (*callback)(struct xenbus_watch *, 17562306a36Sopenharmony_ci const char *, const char *), 17662306a36Sopenharmony_ci const char *pathfmt, ...) 17762306a36Sopenharmony_ci{ 17862306a36Sopenharmony_ci int err; 17962306a36Sopenharmony_ci va_list ap; 18062306a36Sopenharmony_ci char *path; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci va_start(ap, pathfmt); 18362306a36Sopenharmony_ci path = kvasprintf(GFP_NOIO | __GFP_HIGH, pathfmt, ap); 18462306a36Sopenharmony_ci va_end(ap); 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci if (!path) { 18762306a36Sopenharmony_ci xenbus_dev_fatal(dev, -ENOMEM, "allocating path for watch"); 18862306a36Sopenharmony_ci return -ENOMEM; 18962306a36Sopenharmony_ci } 19062306a36Sopenharmony_ci err = xenbus_watch_path(dev, path, watch, will_handle, callback); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci if (err) 19362306a36Sopenharmony_ci kfree(path); 19462306a36Sopenharmony_ci return err; 19562306a36Sopenharmony_ci} 19662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(xenbus_watch_pathfmt); 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_cistatic void xenbus_switch_fatal(struct xenbus_device *, int, int, 19962306a36Sopenharmony_ci const char *, ...); 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_cistatic int 20262306a36Sopenharmony_ci__xenbus_switch_state(struct xenbus_device *dev, 20362306a36Sopenharmony_ci enum xenbus_state state, int depth) 20462306a36Sopenharmony_ci{ 20562306a36Sopenharmony_ci /* We check whether the state is currently set to the given value, and 20662306a36Sopenharmony_ci if not, then the state is set. We don't want to unconditionally 20762306a36Sopenharmony_ci write the given state, because we don't want to fire watches 20862306a36Sopenharmony_ci unnecessarily. Furthermore, if the node has gone, we don't write 20962306a36Sopenharmony_ci to it, as the device will be tearing down, and we don't want to 21062306a36Sopenharmony_ci resurrect that directory. 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci Note that, because of this cached value of our state, this 21362306a36Sopenharmony_ci function will not take a caller's Xenstore transaction 21462306a36Sopenharmony_ci (something it was trying to in the past) because dev->state 21562306a36Sopenharmony_ci would not get reset if the transaction was aborted. 21662306a36Sopenharmony_ci */ 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci struct xenbus_transaction xbt; 21962306a36Sopenharmony_ci int current_state; 22062306a36Sopenharmony_ci int err, abort; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci if (state == dev->state) 22362306a36Sopenharmony_ci return 0; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ciagain: 22662306a36Sopenharmony_ci abort = 1; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci err = xenbus_transaction_start(&xbt); 22962306a36Sopenharmony_ci if (err) { 23062306a36Sopenharmony_ci xenbus_switch_fatal(dev, depth, err, "starting transaction"); 23162306a36Sopenharmony_ci return 0; 23262306a36Sopenharmony_ci } 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci err = xenbus_scanf(xbt, dev->nodename, "state", "%d", ¤t_state); 23562306a36Sopenharmony_ci if (err != 1) 23662306a36Sopenharmony_ci goto abort; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci err = xenbus_printf(xbt, dev->nodename, "state", "%d", state); 23962306a36Sopenharmony_ci if (err) { 24062306a36Sopenharmony_ci xenbus_switch_fatal(dev, depth, err, "writing new state"); 24162306a36Sopenharmony_ci goto abort; 24262306a36Sopenharmony_ci } 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci abort = 0; 24562306a36Sopenharmony_ciabort: 24662306a36Sopenharmony_ci err = xenbus_transaction_end(xbt, abort); 24762306a36Sopenharmony_ci if (err) { 24862306a36Sopenharmony_ci if (err == -EAGAIN && !abort) 24962306a36Sopenharmony_ci goto again; 25062306a36Sopenharmony_ci xenbus_switch_fatal(dev, depth, err, "ending transaction"); 25162306a36Sopenharmony_ci } else 25262306a36Sopenharmony_ci dev->state = state; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci return 0; 25562306a36Sopenharmony_ci} 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci/** 25862306a36Sopenharmony_ci * xenbus_switch_state 25962306a36Sopenharmony_ci * @dev: xenbus device 26062306a36Sopenharmony_ci * @state: new state 26162306a36Sopenharmony_ci * 26262306a36Sopenharmony_ci * Advertise in the store a change of the given driver to the given new_state. 26362306a36Sopenharmony_ci * Return 0 on success, or -errno on error. On error, the device will switch 26462306a36Sopenharmony_ci * to XenbusStateClosing, and the error will be saved in the store. 26562306a36Sopenharmony_ci */ 26662306a36Sopenharmony_ciint xenbus_switch_state(struct xenbus_device *dev, enum xenbus_state state) 26762306a36Sopenharmony_ci{ 26862306a36Sopenharmony_ci return __xenbus_switch_state(dev, state, 0); 26962306a36Sopenharmony_ci} 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(xenbus_switch_state); 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ciint xenbus_frontend_closed(struct xenbus_device *dev) 27462306a36Sopenharmony_ci{ 27562306a36Sopenharmony_ci xenbus_switch_state(dev, XenbusStateClosed); 27662306a36Sopenharmony_ci complete(&dev->down); 27762306a36Sopenharmony_ci return 0; 27862306a36Sopenharmony_ci} 27962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(xenbus_frontend_closed); 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_cistatic void xenbus_va_dev_error(struct xenbus_device *dev, int err, 28262306a36Sopenharmony_ci const char *fmt, va_list ap) 28362306a36Sopenharmony_ci{ 28462306a36Sopenharmony_ci unsigned int len; 28562306a36Sopenharmony_ci char *printf_buffer; 28662306a36Sopenharmony_ci char *path_buffer; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci#define PRINTF_BUFFER_SIZE 4096 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci printf_buffer = kmalloc(PRINTF_BUFFER_SIZE, GFP_KERNEL); 29162306a36Sopenharmony_ci if (!printf_buffer) 29262306a36Sopenharmony_ci return; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci len = sprintf(printf_buffer, "%i ", -err); 29562306a36Sopenharmony_ci vsnprintf(printf_buffer + len, PRINTF_BUFFER_SIZE - len, fmt, ap); 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci dev_err(&dev->dev, "%s\n", printf_buffer); 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci path_buffer = kasprintf(GFP_KERNEL, "error/%s", dev->nodename); 30062306a36Sopenharmony_ci if (path_buffer) 30162306a36Sopenharmony_ci xenbus_write(XBT_NIL, path_buffer, "error", printf_buffer); 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci kfree(printf_buffer); 30462306a36Sopenharmony_ci kfree(path_buffer); 30562306a36Sopenharmony_ci} 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci/** 30862306a36Sopenharmony_ci * xenbus_dev_error 30962306a36Sopenharmony_ci * @dev: xenbus device 31062306a36Sopenharmony_ci * @err: error to report 31162306a36Sopenharmony_ci * @fmt: error message format 31262306a36Sopenharmony_ci * 31362306a36Sopenharmony_ci * Report the given negative errno into the store, along with the given 31462306a36Sopenharmony_ci * formatted message. 31562306a36Sopenharmony_ci */ 31662306a36Sopenharmony_civoid xenbus_dev_error(struct xenbus_device *dev, int err, const char *fmt, ...) 31762306a36Sopenharmony_ci{ 31862306a36Sopenharmony_ci va_list ap; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci va_start(ap, fmt); 32162306a36Sopenharmony_ci xenbus_va_dev_error(dev, err, fmt, ap); 32262306a36Sopenharmony_ci va_end(ap); 32362306a36Sopenharmony_ci} 32462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(xenbus_dev_error); 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci/** 32762306a36Sopenharmony_ci * xenbus_dev_fatal 32862306a36Sopenharmony_ci * @dev: xenbus device 32962306a36Sopenharmony_ci * @err: error to report 33062306a36Sopenharmony_ci * @fmt: error message format 33162306a36Sopenharmony_ci * 33262306a36Sopenharmony_ci * Equivalent to xenbus_dev_error(dev, err, fmt, args), followed by 33362306a36Sopenharmony_ci * xenbus_switch_state(dev, XenbusStateClosing) to schedule an orderly 33462306a36Sopenharmony_ci * closedown of this driver and its peer. 33562306a36Sopenharmony_ci */ 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_civoid xenbus_dev_fatal(struct xenbus_device *dev, int err, const char *fmt, ...) 33862306a36Sopenharmony_ci{ 33962306a36Sopenharmony_ci va_list ap; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci va_start(ap, fmt); 34262306a36Sopenharmony_ci xenbus_va_dev_error(dev, err, fmt, ap); 34362306a36Sopenharmony_ci va_end(ap); 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci xenbus_switch_state(dev, XenbusStateClosing); 34662306a36Sopenharmony_ci} 34762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(xenbus_dev_fatal); 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci/** 35062306a36Sopenharmony_ci * Equivalent to xenbus_dev_fatal(dev, err, fmt, args), but helps 35162306a36Sopenharmony_ci * avoiding recursion within xenbus_switch_state. 35262306a36Sopenharmony_ci */ 35362306a36Sopenharmony_cistatic void xenbus_switch_fatal(struct xenbus_device *dev, int depth, int err, 35462306a36Sopenharmony_ci const char *fmt, ...) 35562306a36Sopenharmony_ci{ 35662306a36Sopenharmony_ci va_list ap; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci va_start(ap, fmt); 35962306a36Sopenharmony_ci xenbus_va_dev_error(dev, err, fmt, ap); 36062306a36Sopenharmony_ci va_end(ap); 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci if (!depth) 36362306a36Sopenharmony_ci __xenbus_switch_state(dev, XenbusStateClosing, 1); 36462306a36Sopenharmony_ci} 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci/* 36762306a36Sopenharmony_ci * xenbus_setup_ring 36862306a36Sopenharmony_ci * @dev: xenbus device 36962306a36Sopenharmony_ci * @vaddr: pointer to starting virtual address of the ring 37062306a36Sopenharmony_ci * @nr_pages: number of pages to be granted 37162306a36Sopenharmony_ci * @grefs: grant reference array to be filled in 37262306a36Sopenharmony_ci * 37362306a36Sopenharmony_ci * Allocate physically contiguous pages for a shared ring buffer and grant it 37462306a36Sopenharmony_ci * to the peer of the given device. The ring buffer is initially filled with 37562306a36Sopenharmony_ci * zeroes. The virtual address of the ring is stored at @vaddr and the 37662306a36Sopenharmony_ci * grant references are stored in the @grefs array. In case of error @vaddr 37762306a36Sopenharmony_ci * will be set to NULL and @grefs will be filled with INVALID_GRANT_REF. 37862306a36Sopenharmony_ci */ 37962306a36Sopenharmony_ciint xenbus_setup_ring(struct xenbus_device *dev, gfp_t gfp, void **vaddr, 38062306a36Sopenharmony_ci unsigned int nr_pages, grant_ref_t *grefs) 38162306a36Sopenharmony_ci{ 38262306a36Sopenharmony_ci unsigned long ring_size = nr_pages * XEN_PAGE_SIZE; 38362306a36Sopenharmony_ci grant_ref_t gref_head; 38462306a36Sopenharmony_ci unsigned int i; 38562306a36Sopenharmony_ci void *addr; 38662306a36Sopenharmony_ci int ret; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci addr = *vaddr = alloc_pages_exact(ring_size, gfp | __GFP_ZERO); 38962306a36Sopenharmony_ci if (!*vaddr) { 39062306a36Sopenharmony_ci ret = -ENOMEM; 39162306a36Sopenharmony_ci goto err; 39262306a36Sopenharmony_ci } 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci ret = gnttab_alloc_grant_references(nr_pages, &gref_head); 39562306a36Sopenharmony_ci if (ret) { 39662306a36Sopenharmony_ci xenbus_dev_fatal(dev, ret, "granting access to %u ring pages", 39762306a36Sopenharmony_ci nr_pages); 39862306a36Sopenharmony_ci goto err; 39962306a36Sopenharmony_ci } 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci for (i = 0; i < nr_pages; i++) { 40262306a36Sopenharmony_ci unsigned long gfn; 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci if (is_vmalloc_addr(*vaddr)) 40562306a36Sopenharmony_ci gfn = pfn_to_gfn(vmalloc_to_pfn(addr)); 40662306a36Sopenharmony_ci else 40762306a36Sopenharmony_ci gfn = virt_to_gfn(addr); 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci grefs[i] = gnttab_claim_grant_reference(&gref_head); 41062306a36Sopenharmony_ci gnttab_grant_foreign_access_ref(grefs[i], dev->otherend_id, 41162306a36Sopenharmony_ci gfn, 0); 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci addr += XEN_PAGE_SIZE; 41462306a36Sopenharmony_ci } 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci return 0; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci err: 41962306a36Sopenharmony_ci if (*vaddr) 42062306a36Sopenharmony_ci free_pages_exact(*vaddr, ring_size); 42162306a36Sopenharmony_ci for (i = 0; i < nr_pages; i++) 42262306a36Sopenharmony_ci grefs[i] = INVALID_GRANT_REF; 42362306a36Sopenharmony_ci *vaddr = NULL; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci return ret; 42662306a36Sopenharmony_ci} 42762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(xenbus_setup_ring); 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci/* 43062306a36Sopenharmony_ci * xenbus_teardown_ring 43162306a36Sopenharmony_ci * @vaddr: starting virtual address of the ring 43262306a36Sopenharmony_ci * @nr_pages: number of pages 43362306a36Sopenharmony_ci * @grefs: grant reference array 43462306a36Sopenharmony_ci * 43562306a36Sopenharmony_ci * Remove grants for the shared ring buffer and free the associated memory. 43662306a36Sopenharmony_ci * On return the grant reference array is filled with INVALID_GRANT_REF. 43762306a36Sopenharmony_ci */ 43862306a36Sopenharmony_civoid xenbus_teardown_ring(void **vaddr, unsigned int nr_pages, 43962306a36Sopenharmony_ci grant_ref_t *grefs) 44062306a36Sopenharmony_ci{ 44162306a36Sopenharmony_ci unsigned int i; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci for (i = 0; i < nr_pages; i++) { 44462306a36Sopenharmony_ci if (grefs[i] != INVALID_GRANT_REF) { 44562306a36Sopenharmony_ci gnttab_end_foreign_access(grefs[i], NULL); 44662306a36Sopenharmony_ci grefs[i] = INVALID_GRANT_REF; 44762306a36Sopenharmony_ci } 44862306a36Sopenharmony_ci } 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci if (*vaddr) 45162306a36Sopenharmony_ci free_pages_exact(*vaddr, nr_pages * XEN_PAGE_SIZE); 45262306a36Sopenharmony_ci *vaddr = NULL; 45362306a36Sopenharmony_ci} 45462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(xenbus_teardown_ring); 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci/** 45762306a36Sopenharmony_ci * Allocate an event channel for the given xenbus_device, assigning the newly 45862306a36Sopenharmony_ci * created local port to *port. Return 0 on success, or -errno on error. On 45962306a36Sopenharmony_ci * error, the device will switch to XenbusStateClosing, and the error will be 46062306a36Sopenharmony_ci * saved in the store. 46162306a36Sopenharmony_ci */ 46262306a36Sopenharmony_ciint xenbus_alloc_evtchn(struct xenbus_device *dev, evtchn_port_t *port) 46362306a36Sopenharmony_ci{ 46462306a36Sopenharmony_ci struct evtchn_alloc_unbound alloc_unbound; 46562306a36Sopenharmony_ci int err; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci alloc_unbound.dom = DOMID_SELF; 46862306a36Sopenharmony_ci alloc_unbound.remote_dom = dev->otherend_id; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci err = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound, 47162306a36Sopenharmony_ci &alloc_unbound); 47262306a36Sopenharmony_ci if (err) 47362306a36Sopenharmony_ci xenbus_dev_fatal(dev, err, "allocating event channel"); 47462306a36Sopenharmony_ci else 47562306a36Sopenharmony_ci *port = alloc_unbound.port; 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci return err; 47862306a36Sopenharmony_ci} 47962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(xenbus_alloc_evtchn); 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci/** 48362306a36Sopenharmony_ci * Free an existing event channel. Returns 0 on success or -errno on error. 48462306a36Sopenharmony_ci */ 48562306a36Sopenharmony_ciint xenbus_free_evtchn(struct xenbus_device *dev, evtchn_port_t port) 48662306a36Sopenharmony_ci{ 48762306a36Sopenharmony_ci struct evtchn_close close; 48862306a36Sopenharmony_ci int err; 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci close.port = port; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci err = HYPERVISOR_event_channel_op(EVTCHNOP_close, &close); 49362306a36Sopenharmony_ci if (err) 49462306a36Sopenharmony_ci xenbus_dev_error(dev, err, "freeing event channel %u", port); 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci return err; 49762306a36Sopenharmony_ci} 49862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(xenbus_free_evtchn); 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci/** 50262306a36Sopenharmony_ci * xenbus_map_ring_valloc 50362306a36Sopenharmony_ci * @dev: xenbus device 50462306a36Sopenharmony_ci * @gnt_refs: grant reference array 50562306a36Sopenharmony_ci * @nr_grefs: number of grant references 50662306a36Sopenharmony_ci * @vaddr: pointer to address to be filled out by mapping 50762306a36Sopenharmony_ci * 50862306a36Sopenharmony_ci * Map @nr_grefs pages of memory into this domain from another 50962306a36Sopenharmony_ci * domain's grant table. xenbus_map_ring_valloc allocates @nr_grefs 51062306a36Sopenharmony_ci * pages of virtual address space, maps the pages to that address, and 51162306a36Sopenharmony_ci * sets *vaddr to that address. Returns 0 on success, and -errno on 51262306a36Sopenharmony_ci * error. If an error is returned, device will switch to 51362306a36Sopenharmony_ci * XenbusStateClosing and the error message will be saved in XenStore. 51462306a36Sopenharmony_ci */ 51562306a36Sopenharmony_ciint xenbus_map_ring_valloc(struct xenbus_device *dev, grant_ref_t *gnt_refs, 51662306a36Sopenharmony_ci unsigned int nr_grefs, void **vaddr) 51762306a36Sopenharmony_ci{ 51862306a36Sopenharmony_ci int err; 51962306a36Sopenharmony_ci struct map_ring_valloc *info; 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci *vaddr = NULL; 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci if (nr_grefs > XENBUS_MAX_RING_GRANTS) 52462306a36Sopenharmony_ci return -EINVAL; 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci info = kzalloc(sizeof(*info), GFP_KERNEL); 52762306a36Sopenharmony_ci if (!info) 52862306a36Sopenharmony_ci return -ENOMEM; 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci info->node = kzalloc(sizeof(*info->node), GFP_KERNEL); 53162306a36Sopenharmony_ci if (!info->node) 53262306a36Sopenharmony_ci err = -ENOMEM; 53362306a36Sopenharmony_ci else 53462306a36Sopenharmony_ci err = ring_ops->map(dev, info, gnt_refs, nr_grefs, vaddr); 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci kfree(info->node); 53762306a36Sopenharmony_ci kfree(info); 53862306a36Sopenharmony_ci return err; 53962306a36Sopenharmony_ci} 54062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(xenbus_map_ring_valloc); 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci/* N.B. sizeof(phys_addr_t) doesn't always equal to sizeof(unsigned 54362306a36Sopenharmony_ci * long), e.g. 32-on-64. Caller is responsible for preparing the 54462306a36Sopenharmony_ci * right array to feed into this function */ 54562306a36Sopenharmony_cistatic int __xenbus_map_ring(struct xenbus_device *dev, 54662306a36Sopenharmony_ci grant_ref_t *gnt_refs, 54762306a36Sopenharmony_ci unsigned int nr_grefs, 54862306a36Sopenharmony_ci grant_handle_t *handles, 54962306a36Sopenharmony_ci struct map_ring_valloc *info, 55062306a36Sopenharmony_ci unsigned int flags, 55162306a36Sopenharmony_ci bool *leaked) 55262306a36Sopenharmony_ci{ 55362306a36Sopenharmony_ci int i, j; 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci if (nr_grefs > XENBUS_MAX_RING_GRANTS) 55662306a36Sopenharmony_ci return -EINVAL; 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci for (i = 0; i < nr_grefs; i++) { 55962306a36Sopenharmony_ci gnttab_set_map_op(&info->map[i], info->phys_addrs[i], flags, 56062306a36Sopenharmony_ci gnt_refs[i], dev->otherend_id); 56162306a36Sopenharmony_ci handles[i] = INVALID_GRANT_HANDLE; 56262306a36Sopenharmony_ci } 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci gnttab_batch_map(info->map, i); 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci for (i = 0; i < nr_grefs; i++) { 56762306a36Sopenharmony_ci if (info->map[i].status != GNTST_okay) { 56862306a36Sopenharmony_ci xenbus_dev_fatal(dev, info->map[i].status, 56962306a36Sopenharmony_ci "mapping in shared page %d from domain %d", 57062306a36Sopenharmony_ci gnt_refs[i], dev->otherend_id); 57162306a36Sopenharmony_ci goto fail; 57262306a36Sopenharmony_ci } else 57362306a36Sopenharmony_ci handles[i] = info->map[i].handle; 57462306a36Sopenharmony_ci } 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci return 0; 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci fail: 57962306a36Sopenharmony_ci for (i = j = 0; i < nr_grefs; i++) { 58062306a36Sopenharmony_ci if (handles[i] != INVALID_GRANT_HANDLE) { 58162306a36Sopenharmony_ci gnttab_set_unmap_op(&info->unmap[j], 58262306a36Sopenharmony_ci info->phys_addrs[i], 58362306a36Sopenharmony_ci GNTMAP_host_map, handles[i]); 58462306a36Sopenharmony_ci j++; 58562306a36Sopenharmony_ci } 58662306a36Sopenharmony_ci } 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci BUG_ON(HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, info->unmap, j)); 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci *leaked = false; 59162306a36Sopenharmony_ci for (i = 0; i < j; i++) { 59262306a36Sopenharmony_ci if (info->unmap[i].status != GNTST_okay) { 59362306a36Sopenharmony_ci *leaked = true; 59462306a36Sopenharmony_ci break; 59562306a36Sopenharmony_ci } 59662306a36Sopenharmony_ci } 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci return -ENOENT; 59962306a36Sopenharmony_ci} 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci/** 60262306a36Sopenharmony_ci * xenbus_unmap_ring 60362306a36Sopenharmony_ci * @dev: xenbus device 60462306a36Sopenharmony_ci * @handles: grant handle array 60562306a36Sopenharmony_ci * @nr_handles: number of handles in the array 60662306a36Sopenharmony_ci * @vaddrs: addresses to unmap 60762306a36Sopenharmony_ci * 60862306a36Sopenharmony_ci * Unmap memory in this domain that was imported from another domain. 60962306a36Sopenharmony_ci * Returns 0 on success and returns GNTST_* on error 61062306a36Sopenharmony_ci * (see xen/include/interface/grant_table.h). 61162306a36Sopenharmony_ci */ 61262306a36Sopenharmony_cistatic int xenbus_unmap_ring(struct xenbus_device *dev, grant_handle_t *handles, 61362306a36Sopenharmony_ci unsigned int nr_handles, unsigned long *vaddrs) 61462306a36Sopenharmony_ci{ 61562306a36Sopenharmony_ci struct gnttab_unmap_grant_ref unmap[XENBUS_MAX_RING_GRANTS]; 61662306a36Sopenharmony_ci int i; 61762306a36Sopenharmony_ci int err; 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci if (nr_handles > XENBUS_MAX_RING_GRANTS) 62062306a36Sopenharmony_ci return -EINVAL; 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci for (i = 0; i < nr_handles; i++) 62362306a36Sopenharmony_ci gnttab_set_unmap_op(&unmap[i], vaddrs[i], 62462306a36Sopenharmony_ci GNTMAP_host_map, handles[i]); 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci BUG_ON(HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, unmap, i)); 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci err = GNTST_okay; 62962306a36Sopenharmony_ci for (i = 0; i < nr_handles; i++) { 63062306a36Sopenharmony_ci if (unmap[i].status != GNTST_okay) { 63162306a36Sopenharmony_ci xenbus_dev_error(dev, unmap[i].status, 63262306a36Sopenharmony_ci "unmapping page at handle %d error %d", 63362306a36Sopenharmony_ci handles[i], unmap[i].status); 63462306a36Sopenharmony_ci err = unmap[i].status; 63562306a36Sopenharmony_ci break; 63662306a36Sopenharmony_ci } 63762306a36Sopenharmony_ci } 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci return err; 64062306a36Sopenharmony_ci} 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_cistatic void xenbus_map_ring_setup_grant_hvm(unsigned long gfn, 64362306a36Sopenharmony_ci unsigned int goffset, 64462306a36Sopenharmony_ci unsigned int len, 64562306a36Sopenharmony_ci void *data) 64662306a36Sopenharmony_ci{ 64762306a36Sopenharmony_ci struct map_ring_valloc *info = data; 64862306a36Sopenharmony_ci unsigned long vaddr = (unsigned long)gfn_to_virt(gfn); 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci info->phys_addrs[info->idx] = vaddr; 65162306a36Sopenharmony_ci info->addrs[info->idx] = vaddr; 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci info->idx++; 65462306a36Sopenharmony_ci} 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_cistatic int xenbus_map_ring_hvm(struct xenbus_device *dev, 65762306a36Sopenharmony_ci struct map_ring_valloc *info, 65862306a36Sopenharmony_ci grant_ref_t *gnt_ref, 65962306a36Sopenharmony_ci unsigned int nr_grefs, 66062306a36Sopenharmony_ci void **vaddr) 66162306a36Sopenharmony_ci{ 66262306a36Sopenharmony_ci struct xenbus_map_node *node = info->node; 66362306a36Sopenharmony_ci int err; 66462306a36Sopenharmony_ci void *addr; 66562306a36Sopenharmony_ci bool leaked = false; 66662306a36Sopenharmony_ci unsigned int nr_pages = XENBUS_PAGES(nr_grefs); 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci err = xen_alloc_unpopulated_pages(nr_pages, node->hvm.pages); 66962306a36Sopenharmony_ci if (err) 67062306a36Sopenharmony_ci goto out_err; 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci gnttab_foreach_grant(node->hvm.pages, nr_grefs, 67362306a36Sopenharmony_ci xenbus_map_ring_setup_grant_hvm, 67462306a36Sopenharmony_ci info); 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci err = __xenbus_map_ring(dev, gnt_ref, nr_grefs, node->handles, 67762306a36Sopenharmony_ci info, GNTMAP_host_map, &leaked); 67862306a36Sopenharmony_ci node->nr_handles = nr_grefs; 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci if (err) 68162306a36Sopenharmony_ci goto out_free_ballooned_pages; 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci addr = vmap(node->hvm.pages, nr_pages, VM_MAP | VM_IOREMAP, 68462306a36Sopenharmony_ci PAGE_KERNEL); 68562306a36Sopenharmony_ci if (!addr) { 68662306a36Sopenharmony_ci err = -ENOMEM; 68762306a36Sopenharmony_ci goto out_xenbus_unmap_ring; 68862306a36Sopenharmony_ci } 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci node->hvm.addr = addr; 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci spin_lock(&xenbus_valloc_lock); 69362306a36Sopenharmony_ci list_add(&node->next, &xenbus_valloc_pages); 69462306a36Sopenharmony_ci spin_unlock(&xenbus_valloc_lock); 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci *vaddr = addr; 69762306a36Sopenharmony_ci info->node = NULL; 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci return 0; 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci out_xenbus_unmap_ring: 70262306a36Sopenharmony_ci if (!leaked) 70362306a36Sopenharmony_ci xenbus_unmap_ring(dev, node->handles, nr_grefs, info->addrs); 70462306a36Sopenharmony_ci else 70562306a36Sopenharmony_ci pr_alert("leaking %p size %u page(s)", 70662306a36Sopenharmony_ci addr, nr_pages); 70762306a36Sopenharmony_ci out_free_ballooned_pages: 70862306a36Sopenharmony_ci if (!leaked) 70962306a36Sopenharmony_ci xen_free_unpopulated_pages(nr_pages, node->hvm.pages); 71062306a36Sopenharmony_ci out_err: 71162306a36Sopenharmony_ci return err; 71262306a36Sopenharmony_ci} 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci/** 71562306a36Sopenharmony_ci * xenbus_unmap_ring_vfree 71662306a36Sopenharmony_ci * @dev: xenbus device 71762306a36Sopenharmony_ci * @vaddr: addr to unmap 71862306a36Sopenharmony_ci * 71962306a36Sopenharmony_ci * Based on Rusty Russell's skeleton driver's unmap_page. 72062306a36Sopenharmony_ci * Unmap a page of memory in this domain that was imported from another domain. 72162306a36Sopenharmony_ci * Use xenbus_unmap_ring_vfree if you mapped in your memory with 72262306a36Sopenharmony_ci * xenbus_map_ring_valloc (it will free the virtual address space). 72362306a36Sopenharmony_ci * Returns 0 on success and returns GNTST_* on error 72462306a36Sopenharmony_ci * (see xen/include/interface/grant_table.h). 72562306a36Sopenharmony_ci */ 72662306a36Sopenharmony_ciint xenbus_unmap_ring_vfree(struct xenbus_device *dev, void *vaddr) 72762306a36Sopenharmony_ci{ 72862306a36Sopenharmony_ci return ring_ops->unmap(dev, vaddr); 72962306a36Sopenharmony_ci} 73062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(xenbus_unmap_ring_vfree); 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci#ifdef CONFIG_XEN_PV 73362306a36Sopenharmony_cistatic int map_ring_apply(pte_t *pte, unsigned long addr, void *data) 73462306a36Sopenharmony_ci{ 73562306a36Sopenharmony_ci struct map_ring_valloc *info = data; 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci info->phys_addrs[info->idx++] = arbitrary_virt_to_machine(pte).maddr; 73862306a36Sopenharmony_ci return 0; 73962306a36Sopenharmony_ci} 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_cistatic int xenbus_map_ring_pv(struct xenbus_device *dev, 74262306a36Sopenharmony_ci struct map_ring_valloc *info, 74362306a36Sopenharmony_ci grant_ref_t *gnt_refs, 74462306a36Sopenharmony_ci unsigned int nr_grefs, 74562306a36Sopenharmony_ci void **vaddr) 74662306a36Sopenharmony_ci{ 74762306a36Sopenharmony_ci struct xenbus_map_node *node = info->node; 74862306a36Sopenharmony_ci struct vm_struct *area; 74962306a36Sopenharmony_ci bool leaked = false; 75062306a36Sopenharmony_ci int err = -ENOMEM; 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci area = get_vm_area(XEN_PAGE_SIZE * nr_grefs, VM_IOREMAP); 75362306a36Sopenharmony_ci if (!area) 75462306a36Sopenharmony_ci return -ENOMEM; 75562306a36Sopenharmony_ci if (apply_to_page_range(&init_mm, (unsigned long)area->addr, 75662306a36Sopenharmony_ci XEN_PAGE_SIZE * nr_grefs, map_ring_apply, info)) 75762306a36Sopenharmony_ci goto failed; 75862306a36Sopenharmony_ci err = __xenbus_map_ring(dev, gnt_refs, nr_grefs, node->handles, 75962306a36Sopenharmony_ci info, GNTMAP_host_map | GNTMAP_contains_pte, 76062306a36Sopenharmony_ci &leaked); 76162306a36Sopenharmony_ci if (err) 76262306a36Sopenharmony_ci goto failed; 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci node->nr_handles = nr_grefs; 76562306a36Sopenharmony_ci node->pv.area = area; 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci spin_lock(&xenbus_valloc_lock); 76862306a36Sopenharmony_ci list_add(&node->next, &xenbus_valloc_pages); 76962306a36Sopenharmony_ci spin_unlock(&xenbus_valloc_lock); 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci *vaddr = area->addr; 77262306a36Sopenharmony_ci info->node = NULL; 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci return 0; 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_cifailed: 77762306a36Sopenharmony_ci if (!leaked) 77862306a36Sopenharmony_ci free_vm_area(area); 77962306a36Sopenharmony_ci else 78062306a36Sopenharmony_ci pr_alert("leaking VM area %p size %u page(s)", area, nr_grefs); 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci return err; 78362306a36Sopenharmony_ci} 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_cistatic int xenbus_unmap_ring_pv(struct xenbus_device *dev, void *vaddr) 78662306a36Sopenharmony_ci{ 78762306a36Sopenharmony_ci struct xenbus_map_node *node; 78862306a36Sopenharmony_ci struct gnttab_unmap_grant_ref unmap[XENBUS_MAX_RING_GRANTS]; 78962306a36Sopenharmony_ci unsigned int level; 79062306a36Sopenharmony_ci int i; 79162306a36Sopenharmony_ci bool leaked = false; 79262306a36Sopenharmony_ci int err; 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci spin_lock(&xenbus_valloc_lock); 79562306a36Sopenharmony_ci list_for_each_entry(node, &xenbus_valloc_pages, next) { 79662306a36Sopenharmony_ci if (node->pv.area->addr == vaddr) { 79762306a36Sopenharmony_ci list_del(&node->next); 79862306a36Sopenharmony_ci goto found; 79962306a36Sopenharmony_ci } 80062306a36Sopenharmony_ci } 80162306a36Sopenharmony_ci node = NULL; 80262306a36Sopenharmony_ci found: 80362306a36Sopenharmony_ci spin_unlock(&xenbus_valloc_lock); 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci if (!node) { 80662306a36Sopenharmony_ci xenbus_dev_error(dev, -ENOENT, 80762306a36Sopenharmony_ci "can't find mapped virtual address %p", vaddr); 80862306a36Sopenharmony_ci return GNTST_bad_virt_addr; 80962306a36Sopenharmony_ci } 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci for (i = 0; i < node->nr_handles; i++) { 81262306a36Sopenharmony_ci unsigned long addr; 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci memset(&unmap[i], 0, sizeof(unmap[i])); 81562306a36Sopenharmony_ci addr = (unsigned long)vaddr + (XEN_PAGE_SIZE * i); 81662306a36Sopenharmony_ci unmap[i].host_addr = arbitrary_virt_to_machine( 81762306a36Sopenharmony_ci lookup_address(addr, &level)).maddr; 81862306a36Sopenharmony_ci unmap[i].dev_bus_addr = 0; 81962306a36Sopenharmony_ci unmap[i].handle = node->handles[i]; 82062306a36Sopenharmony_ci } 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci BUG_ON(HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, unmap, i)); 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci err = GNTST_okay; 82562306a36Sopenharmony_ci leaked = false; 82662306a36Sopenharmony_ci for (i = 0; i < node->nr_handles; i++) { 82762306a36Sopenharmony_ci if (unmap[i].status != GNTST_okay) { 82862306a36Sopenharmony_ci leaked = true; 82962306a36Sopenharmony_ci xenbus_dev_error(dev, unmap[i].status, 83062306a36Sopenharmony_ci "unmapping page at handle %d error %d", 83162306a36Sopenharmony_ci node->handles[i], unmap[i].status); 83262306a36Sopenharmony_ci err = unmap[i].status; 83362306a36Sopenharmony_ci break; 83462306a36Sopenharmony_ci } 83562306a36Sopenharmony_ci } 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci if (!leaked) 83862306a36Sopenharmony_ci free_vm_area(node->pv.area); 83962306a36Sopenharmony_ci else 84062306a36Sopenharmony_ci pr_alert("leaking VM area %p size %u page(s)", 84162306a36Sopenharmony_ci node->pv.area, node->nr_handles); 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci kfree(node); 84462306a36Sopenharmony_ci return err; 84562306a36Sopenharmony_ci} 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_cistatic const struct xenbus_ring_ops ring_ops_pv = { 84862306a36Sopenharmony_ci .map = xenbus_map_ring_pv, 84962306a36Sopenharmony_ci .unmap = xenbus_unmap_ring_pv, 85062306a36Sopenharmony_ci}; 85162306a36Sopenharmony_ci#endif 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_cistruct unmap_ring_hvm 85462306a36Sopenharmony_ci{ 85562306a36Sopenharmony_ci unsigned int idx; 85662306a36Sopenharmony_ci unsigned long addrs[XENBUS_MAX_RING_GRANTS]; 85762306a36Sopenharmony_ci}; 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_cistatic void xenbus_unmap_ring_setup_grant_hvm(unsigned long gfn, 86062306a36Sopenharmony_ci unsigned int goffset, 86162306a36Sopenharmony_ci unsigned int len, 86262306a36Sopenharmony_ci void *data) 86362306a36Sopenharmony_ci{ 86462306a36Sopenharmony_ci struct unmap_ring_hvm *info = data; 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci info->addrs[info->idx] = (unsigned long)gfn_to_virt(gfn); 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci info->idx++; 86962306a36Sopenharmony_ci} 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_cistatic int xenbus_unmap_ring_hvm(struct xenbus_device *dev, void *vaddr) 87262306a36Sopenharmony_ci{ 87362306a36Sopenharmony_ci int rv; 87462306a36Sopenharmony_ci struct xenbus_map_node *node; 87562306a36Sopenharmony_ci void *addr; 87662306a36Sopenharmony_ci struct unmap_ring_hvm info = { 87762306a36Sopenharmony_ci .idx = 0, 87862306a36Sopenharmony_ci }; 87962306a36Sopenharmony_ci unsigned int nr_pages; 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci spin_lock(&xenbus_valloc_lock); 88262306a36Sopenharmony_ci list_for_each_entry(node, &xenbus_valloc_pages, next) { 88362306a36Sopenharmony_ci addr = node->hvm.addr; 88462306a36Sopenharmony_ci if (addr == vaddr) { 88562306a36Sopenharmony_ci list_del(&node->next); 88662306a36Sopenharmony_ci goto found; 88762306a36Sopenharmony_ci } 88862306a36Sopenharmony_ci } 88962306a36Sopenharmony_ci node = addr = NULL; 89062306a36Sopenharmony_ci found: 89162306a36Sopenharmony_ci spin_unlock(&xenbus_valloc_lock); 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci if (!node) { 89462306a36Sopenharmony_ci xenbus_dev_error(dev, -ENOENT, 89562306a36Sopenharmony_ci "can't find mapped virtual address %p", vaddr); 89662306a36Sopenharmony_ci return GNTST_bad_virt_addr; 89762306a36Sopenharmony_ci } 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci nr_pages = XENBUS_PAGES(node->nr_handles); 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci gnttab_foreach_grant(node->hvm.pages, node->nr_handles, 90262306a36Sopenharmony_ci xenbus_unmap_ring_setup_grant_hvm, 90362306a36Sopenharmony_ci &info); 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci rv = xenbus_unmap_ring(dev, node->handles, node->nr_handles, 90662306a36Sopenharmony_ci info.addrs); 90762306a36Sopenharmony_ci if (!rv) { 90862306a36Sopenharmony_ci vunmap(vaddr); 90962306a36Sopenharmony_ci xen_free_unpopulated_pages(nr_pages, node->hvm.pages); 91062306a36Sopenharmony_ci } 91162306a36Sopenharmony_ci else 91262306a36Sopenharmony_ci WARN(1, "Leaking %p, size %u page(s)\n", vaddr, nr_pages); 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci kfree(node); 91562306a36Sopenharmony_ci return rv; 91662306a36Sopenharmony_ci} 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci/** 91962306a36Sopenharmony_ci * xenbus_read_driver_state 92062306a36Sopenharmony_ci * @path: path for driver 92162306a36Sopenharmony_ci * 92262306a36Sopenharmony_ci * Return the state of the driver rooted at the given store path, or 92362306a36Sopenharmony_ci * XenbusStateUnknown if no state can be read. 92462306a36Sopenharmony_ci */ 92562306a36Sopenharmony_cienum xenbus_state xenbus_read_driver_state(const char *path) 92662306a36Sopenharmony_ci{ 92762306a36Sopenharmony_ci enum xenbus_state result; 92862306a36Sopenharmony_ci int err = xenbus_gather(XBT_NIL, path, "state", "%d", &result, NULL); 92962306a36Sopenharmony_ci if (err) 93062306a36Sopenharmony_ci result = XenbusStateUnknown; 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci return result; 93362306a36Sopenharmony_ci} 93462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(xenbus_read_driver_state); 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_cistatic const struct xenbus_ring_ops ring_ops_hvm = { 93762306a36Sopenharmony_ci .map = xenbus_map_ring_hvm, 93862306a36Sopenharmony_ci .unmap = xenbus_unmap_ring_hvm, 93962306a36Sopenharmony_ci}; 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_civoid __init xenbus_ring_ops_init(void) 94262306a36Sopenharmony_ci{ 94362306a36Sopenharmony_ci#ifdef CONFIG_XEN_PV 94462306a36Sopenharmony_ci if (!xen_feature(XENFEAT_auto_translated_physmap)) 94562306a36Sopenharmony_ci ring_ops = &ring_ops_pv; 94662306a36Sopenharmony_ci else 94762306a36Sopenharmony_ci#endif 94862306a36Sopenharmony_ci ring_ops = &ring_ops_hvm; 94962306a36Sopenharmony_ci} 950