Home | History | Annotate | Line # | Download | only in xenbus
xenbus_comms.c revision 1.9
      1  1.9       jym /* $NetBSD: xenbus_comms.c,v 1.9 2008/10/24 18:02:58 jym Exp $ */
      2  1.1    bouyer /******************************************************************************
      3  1.1    bouyer  * xenbus_comms.c
      4  1.1    bouyer  *
      5  1.1    bouyer  * Low level code to talks to Xen Store: ringbuffer and event channel.
      6  1.1    bouyer  *
      7  1.1    bouyer  * Copyright (C) 2005 Rusty Russell, IBM Corporation
      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.9       jym __KERNEL_RCSID(0, "$NetBSD: xenbus_comms.c,v 1.9 2008/10/24 18:02:58 jym Exp $");
     33  1.2    bouyer 
     34  1.2    bouyer #include <sys/types.h>
     35  1.2    bouyer #include <sys/null.h>
     36  1.2    bouyer #include <sys/errno.h>
     37  1.2    bouyer #include <sys/malloc.h>
     38  1.2    bouyer #include <sys/param.h>
     39  1.2    bouyer #include <sys/proc.h>
     40  1.2    bouyer #include <sys/systm.h>
     41  1.2    bouyer 
     42  1.5    bouyer #include <xen/hypervisor.h>
     43  1.5    bouyer #include <xen/evtchn.h>
     44  1.5    bouyer #include <xen/xenbus.h>
     45  1.1    bouyer #include "xenbus_comms.h"
     46  1.1    bouyer 
     47  1.2    bouyer #undef XENDEBUG
     48  1.2    bouyer #ifdef XENDEBUG
     49  1.2    bouyer #define XENPRINTF(x) printf x
     50  1.2    bouyer #else
     51  1.2    bouyer #define XENPRINTF(x)
     52  1.2    bouyer #endif
     53  1.2    bouyer 
     54  1.2    bouyer struct xenstore_domain_interface *xenstore_interface;
     55  1.2    bouyer 
     56  1.2    bouyer static int xenbus_irq = 0;
     57  1.1    bouyer 
     58  1.1    bouyer extern int xenstored_ready;
     59  1.2    bouyer // static DECLARE_WORK(probe_work, xenbus_probe, NULL);
     60  1.2    bouyer 
     61  1.2    bouyer static int wake_waiting(void *);
     62  1.2    bouyer static int check_indexes(XENSTORE_RING_IDX, XENSTORE_RING_IDX);
     63  1.4  christos static void *get_output_chunk(XENSTORE_RING_IDX, XENSTORE_RING_IDX,
     64  1.2    bouyer     char *, uint32_t *);
     65  1.4  christos static const void *get_input_chunk(XENSTORE_RING_IDX, XENSTORE_RING_IDX,
     66  1.2    bouyer     const char *, uint32_t *);
     67  1.1    bouyer 
     68  1.1    bouyer 
     69  1.2    bouyer static inline struct xenstore_domain_interface *
     70  1.2    bouyer xenstore_domain_interface(void)
     71  1.1    bouyer {
     72  1.2    bouyer 	return xenstore_interface;
     73  1.1    bouyer }
     74  1.1    bouyer 
     75  1.2    bouyer static int
     76  1.2    bouyer wake_waiting(void *arg)
     77  1.1    bouyer {
     78  1.8    cegger 	if (__predict_false(xenstored_ready == 0 && xendomain_is_dom0())) {
     79  1.1    bouyer 		xenstored_ready = 1;
     80  1.3    bouyer 		wakeup(&xenstored_ready);
     81  1.1    bouyer 	}
     82  1.1    bouyer 
     83  1.2    bouyer 	wakeup(&xenstore_interface);
     84  1.2    bouyer 	return 1;
     85  1.1    bouyer }
     86  1.1    bouyer 
     87  1.2    bouyer static int
     88  1.2    bouyer check_indexes(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod)
     89  1.1    bouyer {
     90  1.1    bouyer 	return ((prod - cons) <= XENSTORE_RING_SIZE);
     91  1.1    bouyer }
     92  1.1    bouyer 
     93  1.2    bouyer static void *
     94  1.2    bouyer get_output_chunk(XENSTORE_RING_IDX cons,
     95  1.1    bouyer 			      XENSTORE_RING_IDX prod,
     96  1.1    bouyer 			      char *buf, uint32_t *len)
     97  1.1    bouyer {
     98  1.1    bouyer 	*len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(prod);
     99  1.1    bouyer 	if ((XENSTORE_RING_SIZE - (prod - cons)) < *len)
    100  1.1    bouyer 		*len = XENSTORE_RING_SIZE - (prod - cons);
    101  1.1    bouyer 	return buf + MASK_XENSTORE_IDX(prod);
    102  1.1    bouyer }
    103  1.1    bouyer 
    104  1.2    bouyer static const void *
    105  1.2    bouyer get_input_chunk(XENSTORE_RING_IDX cons,
    106  1.1    bouyer 				   XENSTORE_RING_IDX prod,
    107  1.1    bouyer 				   const char *buf, uint32_t *len)
    108  1.1    bouyer {
    109  1.1    bouyer 	*len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(cons);
    110  1.1    bouyer 	if ((prod - cons) < *len)
    111  1.1    bouyer 		*len = prod - cons;
    112  1.1    bouyer 	return buf + MASK_XENSTORE_IDX(cons);
    113  1.1    bouyer }
    114  1.1    bouyer 
    115  1.2    bouyer int
    116  1.2    bouyer xb_write(const void *data, unsigned len)
    117  1.1    bouyer {
    118  1.1    bouyer 	struct xenstore_domain_interface *intf = xenstore_domain_interface();
    119  1.1    bouyer 	XENSTORE_RING_IDX cons, prod;
    120  1.1    bouyer 
    121  1.2    bouyer 	int s = spltty();
    122  1.2    bouyer 
    123  1.1    bouyer 	while (len != 0) {
    124  1.1    bouyer 		void *dst;
    125  1.1    bouyer 		unsigned int avail;
    126  1.1    bouyer 
    127  1.2    bouyer 		while ((intf->req_prod - intf->req_cons) == XENSTORE_RING_SIZE) {
    128  1.2    bouyer 			XENPRINTF(("xb_write tsleep\n"));
    129  1.2    bouyer 			tsleep(&xenstore_interface, PRIBIO, "wrst", 0);
    130  1.2    bouyer 			XENPRINTF(("xb_write tsleep done\n"));
    131  1.2    bouyer 		}
    132  1.1    bouyer 
    133  1.1    bouyer 		/* Read indexes, then verify. */
    134  1.1    bouyer 		cons = intf->req_cons;
    135  1.1    bouyer 		prod = intf->req_prod;
    136  1.2    bouyer 		x86_lfence();
    137  1.2    bouyer 		if (!check_indexes(cons, prod)) {
    138  1.2    bouyer 			splx(s);
    139  1.2    bouyer 			return EIO;
    140  1.2    bouyer 		}
    141  1.1    bouyer 
    142  1.1    bouyer 		dst = get_output_chunk(cons, prod, intf->req, &avail);
    143  1.1    bouyer 		if (avail == 0)
    144  1.1    bouyer 			continue;
    145  1.1    bouyer 		if (avail > len)
    146  1.1    bouyer 			avail = len;
    147  1.1    bouyer 
    148  1.1    bouyer 		memcpy(dst, data, avail);
    149  1.2    bouyer 		data = (const char *)data + avail;
    150  1.1    bouyer 		len -= avail;
    151  1.1    bouyer 
    152  1.1    bouyer 		/* Other side must not see new header until data is there. */
    153  1.2    bouyer 		x86_lfence();
    154  1.1    bouyer 		intf->req_prod += avail;
    155  1.2    bouyer 		x86_lfence();
    156  1.1    bouyer 
    157  1.2    bouyer 		hypervisor_notify_via_evtchn(xen_start_info.store_evtchn);
    158  1.1    bouyer 	}
    159  1.1    bouyer 
    160  1.2    bouyer 	splx(s);
    161  1.1    bouyer 	return 0;
    162  1.1    bouyer }
    163  1.1    bouyer 
    164  1.2    bouyer int
    165  1.2    bouyer xb_read(void *data, unsigned len)
    166  1.1    bouyer {
    167  1.1    bouyer 	struct xenstore_domain_interface *intf = xenstore_domain_interface();
    168  1.1    bouyer 	XENSTORE_RING_IDX cons, prod;
    169  1.1    bouyer 
    170  1.2    bouyer 	int s = spltty();
    171  1.2    bouyer 
    172  1.1    bouyer 	while (len != 0) {
    173  1.1    bouyer 		unsigned int avail;
    174  1.1    bouyer 		const char *src;
    175  1.1    bouyer 
    176  1.2    bouyer 		while (intf->rsp_cons == intf->rsp_prod)
    177  1.2    bouyer 			tsleep(&xenstore_interface, PRIBIO, "rdst", 0);
    178  1.1    bouyer 
    179  1.1    bouyer 		/* Read indexes, then verify. */
    180  1.1    bouyer 		cons = intf->rsp_cons;
    181  1.1    bouyer 		prod = intf->rsp_prod;
    182  1.2    bouyer 		x86_lfence();
    183  1.2    bouyer 		if (!check_indexes(cons, prod)) {
    184  1.2    bouyer 			XENPRINTF(("xb_read EIO\n"));
    185  1.2    bouyer 			splx(s);
    186  1.2    bouyer 			return EIO;
    187  1.2    bouyer 		}
    188  1.1    bouyer 
    189  1.1    bouyer 		src = get_input_chunk(cons, prod, intf->rsp, &avail);
    190  1.1    bouyer 		if (avail == 0)
    191  1.1    bouyer 			continue;
    192  1.1    bouyer 		if (avail > len)
    193  1.1    bouyer 			avail = len;
    194  1.1    bouyer 
    195  1.1    bouyer 		/* We must read header before we read data. */
    196  1.2    bouyer 		x86_lfence();
    197  1.1    bouyer 
    198  1.1    bouyer 		memcpy(data, src, avail);
    199  1.2    bouyer 		data = (char *)data + avail;
    200  1.1    bouyer 		len -= avail;
    201  1.1    bouyer 
    202  1.1    bouyer 		/* Other side must not see free space until we've copied out */
    203  1.2    bouyer 		x86_lfence();
    204  1.1    bouyer 		intf->rsp_cons += avail;
    205  1.2    bouyer 		x86_lfence();
    206  1.1    bouyer 
    207  1.2    bouyer 		XENPRINTF(("Finished read of %i bytes (%i to go)\n",
    208  1.2    bouyer 		    avail, len));
    209  1.1    bouyer 
    210  1.2    bouyer 		hypervisor_notify_via_evtchn(xen_start_info.store_evtchn);
    211  1.1    bouyer 	}
    212  1.1    bouyer 
    213  1.2    bouyer 	splx(s);
    214  1.1    bouyer 	return 0;
    215  1.1    bouyer }
    216  1.1    bouyer 
    217  1.9       jym /* Set up interrupt handler of store event channel. */
    218  1.2    bouyer int
    219  1.7    cegger xb_init_comms(device_t dev)
    220  1.1    bouyer {
    221  1.1    bouyer 	int err;
    222  1.1    bouyer 
    223  1.1    bouyer 	if (xenbus_irq)
    224  1.2    bouyer 		event_remove_handler(xenbus_irq, wake_waiting, NULL);
    225  1.1    bouyer 
    226  1.2    bouyer 	err = event_set_handler(xen_start_info.store_evtchn, wake_waiting,
    227  1.2    bouyer 	    NULL, IPL_TTY, "xenbus");
    228  1.2    bouyer 	if (err) {
    229  1.9       jym 		aprint_error_dev(dev, "request irq failed %i\n", err);
    230  1.1    bouyer 		return err;
    231  1.1    bouyer 	}
    232  1.2    bouyer 	xenbus_irq = xen_start_info.store_evtchn;
    233  1.9       jym 	aprint_verbose_dev(dev, "using event channel %d\n", xenbus_irq);
    234  1.2    bouyer 	hypervisor_enable_event(xenbus_irq);
    235  1.1    bouyer 	return 0;
    236  1.1    bouyer }
    237  1.1    bouyer 
    238  1.1    bouyer /*
    239  1.1    bouyer  * Local variables:
    240  1.1    bouyer  *  c-file-style: "linux"
    241  1.1    bouyer  *  indent-tabs-mode: t
    242  1.1    bouyer  *  c-indent-level: 8
    243  1.1    bouyer  *  c-basic-offset: 8
    244  1.1    bouyer  *  tab-width: 8
    245  1.1    bouyer  * End:
    246  1.1    bouyer  */
    247