ia64/xen-unstable

changeset 8878:294b3a447dce

Provide a simpler, higher-level interface for mapping in pages from another domain.

I also added a one-liner that causes xenbus_dev_(error|fatal) to output
to the kernel log buffer (and thus syslog) which was invaluable to me
while debugging (by default, error messages only appear in xenstore).

Signed-off-by: Ryan Wilson <hap9@epoch.ncsc.mil>
author kaf24@firebug.cl.cam.ac.uk
date Thu Feb 16 23:37:40 2006 +0100 (2006-02-16)
parents 201d48272a57
children 5b433b4fca34
files linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_client.c linux-2.6-xen-sparse/include/xen/xenbus.h
line diff
     1.1 --- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_client.c	Thu Feb 16 23:00:00 2006 +0100
     1.2 +++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_client.c	Thu Feb 16 23:37:40 2006 +0100
     1.3 @@ -30,6 +30,7 @@
     1.4  #include <xen/evtchn.h>
     1.5  #include <xen/gnttab.h>
     1.6  #include <xen/xenbus.h>
     1.7 +#include <xen/driver_util.h>
     1.8  
     1.9  /* xenbus_probe.c */
    1.10  extern char *kasprintf(const char *fmt, ...);
    1.11 @@ -139,6 +140,8 @@ void _dev_error(struct xenbus_device *de
    1.12  	BUG_ON(len + ret > PRINTF_BUFFER_SIZE-1);
    1.13  	dev->has_error = 1;
    1.14  
    1.15 +	dev_err(&dev->dev, "%s\n", printf_buffer);
    1.16 +
    1.17  	path_buffer = error_path(dev);
    1.18  
    1.19  	if (path_buffer == NULL) {
    1.20 @@ -202,7 +205,8 @@ int xenbus_alloc_evtchn(struct xenbus_de
    1.21  	evtchn_op_t op = {
    1.22  		.cmd = EVTCHNOP_alloc_unbound,
    1.23  		.u.alloc_unbound.dom = DOMID_SELF,
    1.24 -		.u.alloc_unbound.remote_dom = dev->otherend_id };
    1.25 +		.u.alloc_unbound.remote_dom = dev->otherend_id
    1.26 +	};
    1.27  
    1.28  	int err = HYPERVISOR_event_channel_op(&op);
    1.29  	if (err)
    1.30 @@ -214,6 +218,167 @@ int xenbus_alloc_evtchn(struct xenbus_de
    1.31  EXPORT_SYMBOL(xenbus_alloc_evtchn);
    1.32  
    1.33  
    1.34 +int xenbus_bind_evtchn(struct xenbus_device *dev, int remote_port, int *port)
    1.35 +{
    1.36 +	evtchn_op_t op = {
    1.37 +		.cmd = EVTCHNOP_bind_interdomain,
    1.38 +		.u.bind_interdomain.remote_dom = dev->otherend_id,
    1.39 +		.u.bind_interdomain.remote_port = remote_port,
    1.40 +	};
    1.41 +
    1.42 +	int err = HYPERVISOR_event_channel_op(&op);
    1.43 +	if (err)
    1.44 +		xenbus_dev_fatal(dev, err,
    1.45 +				 "binding to event channel %d from domain %d",
    1.46 +				 remote_port, dev->otherend_id);
    1.47 +	else
    1.48 +		*port = op.u.bind_interdomain.local_port;
    1.49 +	return err;
    1.50 +}
    1.51 +EXPORT_SYMBOL(xenbus_bind_evtchn);
    1.52 +
    1.53 +
    1.54 +int xenbus_free_evtchn(struct xenbus_device *dev, int port)
    1.55 +{
    1.56 +	evtchn_op_t op = {
    1.57 +		.cmd = EVTCHNOP_close,
    1.58 +		.u.close.port = port,
    1.59 +	};
    1.60 +	int err = HYPERVISOR_event_channel_op(&op);
    1.61 +	if (err)
    1.62 +		xenbus_dev_error(dev, err, "freeing event channel %d", port);
    1.63 +	return err;
    1.64 +}
    1.65 +
    1.66 +
    1.67 +/* Based on Rusty Russell's skeleton driver's map_page */
    1.68 +int xenbus_map_ring_valloc(struct xenbus_device *dev, int gnt_ref, void **vaddr)
    1.69 +{
    1.70 +	struct gnttab_map_grant_ref op = {
    1.71 +		.flags = GNTMAP_host_map,
    1.72 +		.ref   = gnt_ref,
    1.73 +		.dom   = dev->otherend_id,
    1.74 +	};
    1.75 +	struct vm_struct *area;
    1.76 +
    1.77 +	*vaddr = NULL;
    1.78 +
    1.79 +	area = alloc_vm_area(PAGE_SIZE);
    1.80 +	if (!area)
    1.81 +		return -ENOMEM;
    1.82 +
    1.83 +	op.host_addr = (unsigned long)area->addr;
    1.84 +
    1.85 +	lock_vm_area(area);
    1.86 +	BUG_ON(HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1));
    1.87 +	unlock_vm_area(area);
    1.88 +
    1.89 +	if (op.status != GNTST_okay) {
    1.90 +		free_vm_area(area);
    1.91 +		xenbus_dev_fatal(dev, op.status,
    1.92 +				 "mapping in shared page %d from domain %d",
    1.93 +				 gnt_ref, dev->otherend_id);
    1.94 +		return op.status;
    1.95 +	}
    1.96 +
    1.97 +	/* Stuff the handle in an unused field */
    1.98 +	area->phys_addr = (unsigned long)op.handle;
    1.99 +
   1.100 +	*vaddr = area->addr;
   1.101 +	return 0;
   1.102 +}
   1.103 +EXPORT_SYMBOL(xenbus_map_ring_valloc);
   1.104 +
   1.105 +
   1.106 +int xenbus_map_ring(struct xenbus_device *dev, int gnt_ref,
   1.107 +		   grant_handle_t *handle, void *vaddr)
   1.108 +{
   1.109 +	struct gnttab_map_grant_ref op = {
   1.110 +		.host_addr = (unsigned long)vaddr,
   1.111 +		.flags     = GNTMAP_host_map,
   1.112 +		.ref       = gnt_ref,
   1.113 +		.dom       = dev->otherend_id,
   1.114 +	};
   1.115 +
   1.116 +	BUG_ON(HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1));
   1.117 +
   1.118 +	if (op.status != GNTST_okay) {
   1.119 +		xenbus_dev_fatal(dev, op.status,
   1.120 +				 "mapping in shared page %d from domain %d",
   1.121 +				 gnt_ref, dev->otherend_id);
   1.122 +	} else
   1.123 +		*handle = op.handle;
   1.124 +
   1.125 +	return op.status;
   1.126 +}
   1.127 +EXPORT_SYMBOL(xenbus_map_ring);
   1.128 +
   1.129 +
   1.130 +/* Based on Rusty Russell's skeleton driver's unmap_page */
   1.131 +int xenbus_unmap_ring_vfree(struct xenbus_device *dev, void *vaddr)
   1.132 +{
   1.133 +	struct vm_struct *area;
   1.134 +	struct gnttab_unmap_grant_ref op = {
   1.135 +		.host_addr = (unsigned long)vaddr,
   1.136 +	};
   1.137 +
   1.138 +	/* It'd be nice if linux/vmalloc.h provided a find_vm_area(void *addr)
   1.139 +	 * method so that we don't have to muck with vmalloc internals here.
   1.140 +	 * We could force the user to hang on to their struct vm_struct from
   1.141 +	 * xenbus_map_ring_valloc, but these 6 lines considerably simplify
   1.142 +	 * this API.
   1.143 +	 */
   1.144 +	read_lock(&vmlist_lock);
   1.145 +	for (area = vmlist; area != NULL; area = area->next) {
   1.146 +		if (area->addr == vaddr)
   1.147 +			break;
   1.148 +	}
   1.149 +	read_unlock(&vmlist_lock);
   1.150 +
   1.151 +	if (!area) {
   1.152 +		xenbus_dev_error(dev, -ENOENT,
   1.153 +				 "can't find mapped virtual address %p", vaddr);
   1.154 +		return GNTST_bad_virt_addr;
   1.155 +	}
   1.156 +
   1.157 +	op.handle = (grant_handle_t)area->phys_addr;
   1.158 +
   1.159 +	lock_vm_area(area);
   1.160 +	BUG_ON(HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1));
   1.161 +	unlock_vm_area(area);
   1.162 +
   1.163 +	if (op.status == GNTST_okay)
   1.164 +		free_vm_area(area);
   1.165 +	else
   1.166 +		xenbus_dev_error(dev, op.status,
   1.167 +				 "unmapping page at handle %d error %d",
   1.168 +				 (int16_t)area->phys_addr, op.status);
   1.169 +
   1.170 +	return op.status;
   1.171 +}
   1.172 +EXPORT_SYMBOL(xenbus_unmap_ring_vfree);
   1.173 +
   1.174 +
   1.175 +int xenbus_unmap_ring(struct xenbus_device *dev,
   1.176 +		     grant_handle_t handle, void *vaddr)
   1.177 +{
   1.178 +	struct gnttab_unmap_grant_ref op = {
   1.179 +		.host_addr = (unsigned long)vaddr,
   1.180 +		.handle    = handle,
   1.181 +	};
   1.182 +
   1.183 +	BUG_ON(HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1));
   1.184 +
   1.185 +	if (op.status != GNTST_okay)
   1.186 +		xenbus_dev_error(dev, op.status,
   1.187 +				 "unmapping page at handle %d error %d",
   1.188 +				 handle, op.status);
   1.189 +
   1.190 +	return op.status;
   1.191 +}
   1.192 +EXPORT_SYMBOL(xenbus_unmap_ring);
   1.193 +
   1.194 +
   1.195  XenbusState xenbus_read_driver_state(const char *path)
   1.196  {
   1.197  	XenbusState result;
     2.1 --- a/linux-2.6-xen-sparse/include/xen/xenbus.h	Thu Feb 16 23:00:00 2006 +0100
     2.2 +++ b/linux-2.6-xen-sparse/include/xen/xenbus.h	Thu Feb 16 23:37:40 2006 +0100
     2.3 @@ -34,6 +34,7 @@
     2.4  #include <linux/device.h>
     2.5  #include <linux/notifier.h>
     2.6  #include <asm/semaphore.h>
     2.7 +#include <xen/interface/grant_table.h>
     2.8  #include <xen/interface/io/xenbus.h>
     2.9  #include <xen/interface/io/xs_wire.h>
    2.10  
    2.11 @@ -209,6 +210,34 @@ int xenbus_grant_ring(struct xenbus_devi
    2.12  
    2.13  
    2.14  /**
    2.15 + * Map a page of memory into this domain from another domain's grant table.
    2.16 + * xenbus_map_ring_valloc allocates a page of virtual address space, maps the
    2.17 + * page to that address, and sets *vaddr to that address.
    2.18 + * xenbus_map_ring does not allocate the virtual address space (you must do
    2.19 + * this yourself!). It only maps in the page to the specified address.
    2.20 + * Returns 0 on success, and GNTST_* (see xen/include/public/grant_table.h) or
    2.21 + * -ENOMEM on error. If an error is returned, device will switch to
    2.22 + * XenbusStateClosing and the error message will be saved in XenStore.
    2.23 + */
    2.24 +int xenbus_map_ring_valloc(struct xenbus_device *dev,
    2.25 +			   int gnt_ref, void **vaddr);
    2.26 +int xenbus_map_ring(struct xenbus_device *dev, int gnt_ref,
    2.27 +			   grant_handle_t *handle, void *vaddr);
    2.28 +
    2.29 +
    2.30 +/**
    2.31 + * Unmap a page of memory in this domain that was imported from another domain.
    2.32 + * Use xenbus_unmap_ring_vfree if you mapped in your memory with
    2.33 + * xenbus_map_ring_valloc (it will free the virtual address space).
    2.34 + * Returns 0 on success and returns GNTST_* on error
    2.35 + * (see xen/include/public/grant_table.h).
    2.36 + */
    2.37 +int xenbus_unmap_ring_vfree(struct xenbus_device *dev, void *vaddr);
    2.38 +int xenbus_unmap_ring(struct xenbus_device *dev,
    2.39 +		      grant_handle_t handle, void *vaddr);
    2.40 +
    2.41 +
    2.42 +/**
    2.43   * Allocate an event channel for the given xenbus_device, assigning the newly
    2.44   * created local port to *port.  Return 0 on success, or -errno on error.  On
    2.45   * error, the device will switch to XenbusStateClosing, and the error will be
    2.46 @@ -218,6 +247,20 @@ int xenbus_alloc_evtchn(struct xenbus_de
    2.47  
    2.48  
    2.49  /**
    2.50 + * Bind to an existing interdomain event channel in another domain. Returns 0
    2.51 + * on success and stores the local port in *port. On error, returns -errno,
    2.52 + * switches the device to XenbusStateClosing, and saves the error in XenStore.
    2.53 + */
    2.54 +int xenbus_bind_evtchn(struct xenbus_device *dev, int remote_port, int *port);
    2.55 +
    2.56 +
    2.57 +/**
    2.58 + * Free an existing event channel. Returns 0 on success or -errno on error.
    2.59 + */
    2.60 +int xenbus_free_evtchn(struct xenbus_device *dev, int port);
    2.61 +
    2.62 +
    2.63 +/**
    2.64   * Return the state of the driver rooted at the given store path, or
    2.65   * XenbusStateClosed if no state can be read.
    2.66   */