Home | History | Annotate | Line # | Download | only in xenbus
xenbus_comms.c revision 1.2.10.3
      1  1.2.10.3  kardel /* $NetBSD: xenbus_comms.c,v 1.2.10.3 2006/06/01 22:35:39 kardel Exp $ */
      2  1.2.10.2  simonb /******************************************************************************
      3  1.2.10.2  simonb  * xenbus_comms.c
      4  1.2.10.2  simonb  *
      5  1.2.10.2  simonb  * Low level code to talks to Xen Store: ringbuffer and event channel.
      6  1.2.10.2  simonb  *
      7  1.2.10.2  simonb  * Copyright (C) 2005 Rusty Russell, IBM Corporation
      8  1.2.10.2  simonb  *
      9  1.2.10.2  simonb  * This file may be distributed separately from the Linux kernel, or
     10  1.2.10.2  simonb  * incorporated into other software packages, subject to the following license:
     11  1.2.10.2  simonb  *
     12  1.2.10.2  simonb  * Permission is hereby granted, free of charge, to any person obtaining a copy
     13  1.2.10.2  simonb  * of this source file (the "Software"), to deal in the Software without
     14  1.2.10.2  simonb  * restriction, including without limitation the rights to use, copy, modify,
     15  1.2.10.2  simonb  * merge, publish, distribute, sublicense, and/or sell copies of the Software,
     16  1.2.10.2  simonb  * and to permit persons to whom the Software is furnished to do so, subject to
     17  1.2.10.2  simonb  * the following conditions:
     18  1.2.10.2  simonb  *
     19  1.2.10.2  simonb  * The above copyright notice and this permission notice shall be included in
     20  1.2.10.2  simonb  * all copies or substantial portions of the Software.
     21  1.2.10.2  simonb  *
     22  1.2.10.2  simonb  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     23  1.2.10.2  simonb  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     24  1.2.10.2  simonb  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     25  1.2.10.2  simonb  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     26  1.2.10.2  simonb  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     27  1.2.10.2  simonb  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
     28  1.2.10.2  simonb  * IN THE SOFTWARE.
     29  1.2.10.2  simonb  */
     30  1.2.10.2  simonb 
     31  1.2.10.2  simonb #include <sys/cdefs.h>
     32  1.2.10.3  kardel __KERNEL_RCSID(0, "$NetBSD: xenbus_comms.c,v 1.2.10.3 2006/06/01 22:35:39 kardel Exp $");
     33  1.2.10.2  simonb 
     34  1.2.10.2  simonb #include <sys/types.h>
     35  1.2.10.2  simonb #include <sys/null.h>
     36  1.2.10.2  simonb #include <sys/errno.h>
     37  1.2.10.2  simonb #include <sys/malloc.h>
     38  1.2.10.2  simonb #include <sys/param.h>
     39  1.2.10.2  simonb #include <sys/proc.h>
     40  1.2.10.2  simonb #include <sys/systm.h>
     41  1.2.10.2  simonb 
     42  1.2.10.2  simonb #include <machine/hypervisor.h>
     43  1.2.10.2  simonb #include <machine/evtchn.h>
     44  1.2.10.2  simonb #include <machine/xenbus.h>
     45  1.2.10.2  simonb #include "xenbus_comms.h"
     46  1.2.10.2  simonb 
     47  1.2.10.2  simonb #undef XENDEBUG
     48  1.2.10.2  simonb #ifdef XENDEBUG
     49  1.2.10.2  simonb #define XENPRINTF(x) printf x
     50  1.2.10.2  simonb #else
     51  1.2.10.2  simonb #define XENPRINTF(x)
     52  1.2.10.2  simonb #endif
     53  1.2.10.2  simonb 
     54  1.2.10.2  simonb struct xenstore_domain_interface *xenstore_interface;
     55  1.2.10.2  simonb 
     56  1.2.10.2  simonb static int xenbus_irq = 0;
     57  1.2.10.2  simonb 
     58  1.2.10.2  simonb extern int xenstored_ready;
     59  1.2.10.2  simonb // static DECLARE_WORK(probe_work, xenbus_probe, NULL);
     60  1.2.10.2  simonb 
     61  1.2.10.2  simonb static int wake_waiting(void *);
     62  1.2.10.2  simonb static int check_indexes(XENSTORE_RING_IDX, XENSTORE_RING_IDX);
     63  1.2.10.2  simonb static void * get_output_chunk(XENSTORE_RING_IDX, XENSTORE_RING_IDX,
     64  1.2.10.2  simonb     char *, uint32_t *);
     65  1.2.10.2  simonb static const void * get_input_chunk(XENSTORE_RING_IDX, XENSTORE_RING_IDX,
     66  1.2.10.2  simonb     const char *, uint32_t *);
     67  1.2.10.2  simonb 
     68  1.2.10.2  simonb 
     69  1.2.10.2  simonb static inline struct xenstore_domain_interface *
     70  1.2.10.2  simonb xenstore_domain_interface(void)
     71  1.2.10.2  simonb {
     72  1.2.10.2  simonb 	return xenstore_interface;
     73  1.2.10.2  simonb }
     74  1.2.10.2  simonb 
     75  1.2.10.2  simonb static int
     76  1.2.10.2  simonb wake_waiting(void *arg)
     77  1.2.10.2  simonb {
     78  1.2.10.3  kardel 	if (__predict_false(xenstored_ready == 0 &&
     79  1.2.10.3  kardel 	    xen_start_info.flags & SIF_INITDOMAIN)) {
     80  1.2.10.2  simonb 		xenstored_ready = 1;
     81  1.2.10.3  kardel 		wakeup(&xenstored_ready);
     82  1.2.10.2  simonb 	}
     83  1.2.10.2  simonb 
     84  1.2.10.2  simonb 	wakeup(&xenstore_interface);
     85  1.2.10.2  simonb 	return 1;
     86  1.2.10.2  simonb }
     87  1.2.10.2  simonb 
     88  1.2.10.2  simonb static int
     89  1.2.10.2  simonb check_indexes(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod)
     90  1.2.10.2  simonb {
     91  1.2.10.2  simonb 	return ((prod - cons) <= XENSTORE_RING_SIZE);
     92  1.2.10.2  simonb }
     93  1.2.10.2  simonb 
     94  1.2.10.2  simonb static void *
     95  1.2.10.2  simonb get_output_chunk(XENSTORE_RING_IDX cons,
     96  1.2.10.2  simonb 			      XENSTORE_RING_IDX prod,
     97  1.2.10.2  simonb 			      char *buf, uint32_t *len)
     98  1.2.10.2  simonb {
     99  1.2.10.2  simonb 	*len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(prod);
    100  1.2.10.2  simonb 	if ((XENSTORE_RING_SIZE - (prod - cons)) < *len)
    101  1.2.10.2  simonb 		*len = XENSTORE_RING_SIZE - (prod - cons);
    102  1.2.10.2  simonb 	return buf + MASK_XENSTORE_IDX(prod);
    103  1.2.10.2  simonb }
    104  1.2.10.2  simonb 
    105  1.2.10.2  simonb static const void *
    106  1.2.10.2  simonb get_input_chunk(XENSTORE_RING_IDX cons,
    107  1.2.10.2  simonb 				   XENSTORE_RING_IDX prod,
    108  1.2.10.2  simonb 				   const char *buf, uint32_t *len)
    109  1.2.10.2  simonb {
    110  1.2.10.2  simonb 	*len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(cons);
    111  1.2.10.2  simonb 	if ((prod - cons) < *len)
    112  1.2.10.2  simonb 		*len = prod - cons;
    113  1.2.10.2  simonb 	return buf + MASK_XENSTORE_IDX(cons);
    114  1.2.10.2  simonb }
    115  1.2.10.2  simonb 
    116  1.2.10.2  simonb int
    117  1.2.10.2  simonb xb_write(const void *data, unsigned len)
    118  1.2.10.2  simonb {
    119  1.2.10.2  simonb 	struct xenstore_domain_interface *intf = xenstore_domain_interface();
    120  1.2.10.2  simonb 	XENSTORE_RING_IDX cons, prod;
    121  1.2.10.2  simonb 
    122  1.2.10.2  simonb 	int s = spltty();
    123  1.2.10.2  simonb 
    124  1.2.10.2  simonb 	while (len != 0) {
    125  1.2.10.2  simonb 		void *dst;
    126  1.2.10.2  simonb 		unsigned int avail;
    127  1.2.10.2  simonb 
    128  1.2.10.2  simonb 		while ((intf->req_prod - intf->req_cons) == XENSTORE_RING_SIZE) {
    129  1.2.10.2  simonb 			XENPRINTF(("xb_write tsleep\n"));
    130  1.2.10.2  simonb 			tsleep(&xenstore_interface, PRIBIO, "wrst", 0);
    131  1.2.10.2  simonb 			XENPRINTF(("xb_write tsleep done\n"));
    132  1.2.10.2  simonb 		}
    133  1.2.10.2  simonb 
    134  1.2.10.2  simonb 		/* Read indexes, then verify. */
    135  1.2.10.2  simonb 		cons = intf->req_cons;
    136  1.2.10.2  simonb 		prod = intf->req_prod;
    137  1.2.10.2  simonb 		x86_lfence();
    138  1.2.10.2  simonb 		if (!check_indexes(cons, prod)) {
    139  1.2.10.2  simonb 			splx(s);
    140  1.2.10.2  simonb 			return EIO;
    141  1.2.10.2  simonb 		}
    142  1.2.10.2  simonb 
    143  1.2.10.2  simonb 		dst = get_output_chunk(cons, prod, intf->req, &avail);
    144  1.2.10.2  simonb 		if (avail == 0)
    145  1.2.10.2  simonb 			continue;
    146  1.2.10.2  simonb 		if (avail > len)
    147  1.2.10.2  simonb 			avail = len;
    148  1.2.10.2  simonb 
    149  1.2.10.2  simonb 		memcpy(dst, data, avail);
    150  1.2.10.2  simonb 		data = (const char *)data + avail;
    151  1.2.10.2  simonb 		len -= avail;
    152  1.2.10.2  simonb 
    153  1.2.10.2  simonb 		/* Other side must not see new header until data is there. */
    154  1.2.10.2  simonb 		x86_lfence();
    155  1.2.10.2  simonb 		intf->req_prod += avail;
    156  1.2.10.2  simonb 		x86_lfence();
    157  1.2.10.2  simonb 
    158  1.2.10.2  simonb 		hypervisor_notify_via_evtchn(xen_start_info.store_evtchn);
    159  1.2.10.2  simonb 	}
    160  1.2.10.2  simonb 
    161  1.2.10.2  simonb 	splx(s);
    162  1.2.10.2  simonb 	return 0;
    163  1.2.10.2  simonb }
    164  1.2.10.2  simonb 
    165  1.2.10.2  simonb int
    166  1.2.10.2  simonb xb_read(void *data, unsigned len)
    167  1.2.10.2  simonb {
    168  1.2.10.2  simonb 	struct xenstore_domain_interface *intf = xenstore_domain_interface();
    169  1.2.10.2  simonb 	XENSTORE_RING_IDX cons, prod;
    170  1.2.10.2  simonb 
    171  1.2.10.2  simonb 	int s = spltty();
    172  1.2.10.2  simonb 
    173  1.2.10.2  simonb 	while (len != 0) {
    174  1.2.10.2  simonb 		unsigned int avail;
    175  1.2.10.2  simonb 		const char *src;
    176  1.2.10.2  simonb 
    177  1.2.10.2  simonb 		while (intf->rsp_cons == intf->rsp_prod)
    178  1.2.10.2  simonb 			tsleep(&xenstore_interface, PRIBIO, "rdst", 0);
    179  1.2.10.2  simonb 
    180  1.2.10.2  simonb 		/* Read indexes, then verify. */
    181  1.2.10.2  simonb 		cons = intf->rsp_cons;
    182  1.2.10.2  simonb 		prod = intf->rsp_prod;
    183  1.2.10.2  simonb 		x86_lfence();
    184  1.2.10.2  simonb 		if (!check_indexes(cons, prod)) {
    185  1.2.10.2  simonb 			XENPRINTF(("xb_read EIO\n"));
    186  1.2.10.2  simonb 			splx(s);
    187  1.2.10.2  simonb 			return EIO;
    188  1.2.10.2  simonb 		}
    189  1.2.10.2  simonb 
    190  1.2.10.2  simonb 		src = get_input_chunk(cons, prod, intf->rsp, &avail);
    191  1.2.10.2  simonb 		if (avail == 0)
    192  1.2.10.2  simonb 			continue;
    193  1.2.10.2  simonb 		if (avail > len)
    194  1.2.10.2  simonb 			avail = len;
    195  1.2.10.2  simonb 
    196  1.2.10.2  simonb 		/* We must read header before we read data. */
    197  1.2.10.2  simonb 		x86_lfence();
    198  1.2.10.2  simonb 
    199  1.2.10.2  simonb 		memcpy(data, src, avail);
    200  1.2.10.2  simonb 		data = (char *)data + avail;
    201  1.2.10.2  simonb 		len -= avail;
    202  1.2.10.2  simonb 
    203  1.2.10.2  simonb 		/* Other side must not see free space until we've copied out */
    204  1.2.10.2  simonb 		x86_lfence();
    205  1.2.10.2  simonb 		intf->rsp_cons += avail;
    206  1.2.10.2  simonb 		x86_lfence();
    207  1.2.10.2  simonb 
    208  1.2.10.2  simonb 		XENPRINTF(("Finished read of %i bytes (%i to go)\n",
    209  1.2.10.2  simonb 		    avail, len));
    210  1.2.10.2  simonb 
    211  1.2.10.2  simonb 		hypervisor_notify_via_evtchn(xen_start_info.store_evtchn);
    212  1.2.10.2  simonb 	}
    213  1.2.10.2  simonb 
    214  1.2.10.2  simonb 	splx(s);
    215  1.2.10.2  simonb 	return 0;
    216  1.2.10.2  simonb }
    217  1.2.10.2  simonb 
    218  1.2.10.2  simonb /* Set up interrupt handler off store event channel. */
    219  1.2.10.2  simonb int
    220  1.2.10.2  simonb xb_init_comms(struct device *dev)
    221  1.2.10.2  simonb {
    222  1.2.10.2  simonb 	int err;
    223  1.2.10.2  simonb 
    224  1.2.10.2  simonb 	if (xenbus_irq)
    225  1.2.10.2  simonb 		event_remove_handler(xenbus_irq, wake_waiting, NULL);
    226  1.2.10.2  simonb 
    227  1.2.10.2  simonb 	err = event_set_handler(xen_start_info.store_evtchn, wake_waiting,
    228  1.2.10.2  simonb 	    NULL, IPL_TTY, "xenbus");
    229  1.2.10.2  simonb 	if (err) {
    230  1.2.10.2  simonb 		printf("XENBUS request irq failed %i\n", err);
    231  1.2.10.2  simonb 		return err;
    232  1.2.10.2  simonb 	}
    233  1.2.10.2  simonb 	xenbus_irq = xen_start_info.store_evtchn;
    234  1.2.10.2  simonb 	printf("%s: using event channel %d\n", dev->dv_xname, xenbus_irq);
    235  1.2.10.2  simonb 	hypervisor_enable_event(xenbus_irq);
    236  1.2.10.2  simonb 	return 0;
    237  1.2.10.2  simonb }
    238  1.2.10.2  simonb 
    239  1.2.10.2  simonb /*
    240  1.2.10.2  simonb  * Local variables:
    241  1.2.10.2  simonb  *  c-file-style: "linux"
    242  1.2.10.2  simonb  *  indent-tabs-mode: t
    243  1.2.10.2  simonb  *  c-indent-level: 8
    244  1.2.10.2  simonb  *  c-basic-offset: 8
    245  1.2.10.2  simonb  *  tab-width: 8
    246  1.2.10.2  simonb  * End:
    247  1.2.10.2  simonb  */
    248