Home | History | Annotate | Line # | Download | only in xenbus
xenbus_comms.c revision 1.1
      1 /******************************************************************************
      2  * xenbus_comms.c
      3  *
      4  * Low level code to talks to Xen Store: ringbuffer and event channel.
      5  *
      6  * Copyright (C) 2005 Rusty Russell, IBM Corporation
      7  *
      8  * This file may be distributed separately from the Linux kernel, or
      9  * incorporated into other software packages, subject to the following license:
     10  *
     11  * Permission is hereby granted, free of charge, to any person obtaining a copy
     12  * of this source file (the "Software"), to deal in the Software without
     13  * restriction, including without limitation the rights to use, copy, modify,
     14  * merge, publish, distribute, sublicense, and/or sell copies of the Software,
     15  * and to permit persons to whom the Software is furnished to do so, subject to
     16  * the following conditions:
     17  *
     18  * The above copyright notice and this permission notice shall be included in
     19  * all copies or substantial portions of the Software.
     20  *
     21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     22  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     23  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     24  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     25  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     26  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
     27  * IN THE SOFTWARE.
     28  */
     29 
     30 #include <asm/hypervisor.h>
     31 #include <asm-xen/evtchn.h>
     32 #include <linux/wait.h>
     33 #include <linux/interrupt.h>
     34 #include <linux/sched.h>
     35 #include <linux/err.h>
     36 #include <asm-xen/xenbus.h>
     37 #include "xenbus_comms.h"
     38 
     39 static int xenbus_irq;
     40 
     41 extern void xenbus_probe(void *);
     42 extern int xenstored_ready;
     43 static DECLARE_WORK(probe_work, xenbus_probe, NULL);
     44 
     45 DECLARE_WAIT_QUEUE_HEAD(xb_waitq);
     46 
     47 static inline struct xenstore_domain_interface *xenstore_domain_interface(void)
     48 {
     49 	return mfn_to_virt(xen_start_info->store_mfn);
     50 }
     51 
     52 static irqreturn_t wake_waiting(int irq, void *unused, struct pt_regs *regs)
     53 {
     54 	if (unlikely(xenstored_ready == 0)) {
     55 		xenstored_ready = 1;
     56 		schedule_work(&probe_work);
     57 	}
     58 
     59 	wake_up(&xb_waitq);
     60 	return IRQ_HANDLED;
     61 }
     62 
     63 static int check_indexes(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod)
     64 {
     65 	return ((prod - cons) <= XENSTORE_RING_SIZE);
     66 }
     67 
     68 static void *get_output_chunk(XENSTORE_RING_IDX cons,
     69 			      XENSTORE_RING_IDX prod,
     70 			      char *buf, uint32_t *len)
     71 {
     72 	*len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(prod);
     73 	if ((XENSTORE_RING_SIZE - (prod - cons)) < *len)
     74 		*len = XENSTORE_RING_SIZE - (prod - cons);
     75 	return buf + MASK_XENSTORE_IDX(prod);
     76 }
     77 
     78 static const void *get_input_chunk(XENSTORE_RING_IDX cons,
     79 				   XENSTORE_RING_IDX prod,
     80 				   const char *buf, uint32_t *len)
     81 {
     82 	*len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(cons);
     83 	if ((prod - cons) < *len)
     84 		*len = prod - cons;
     85 	return buf + MASK_XENSTORE_IDX(cons);
     86 }
     87 
     88 int xb_write(const void *data, unsigned len)
     89 {
     90 	struct xenstore_domain_interface *intf = xenstore_domain_interface();
     91 	XENSTORE_RING_IDX cons, prod;
     92 
     93 	while (len != 0) {
     94 		void *dst;
     95 		unsigned int avail;
     96 
     97 		wait_event_interruptible(xb_waitq,
     98 					 (intf->req_prod - intf->req_cons) !=
     99 					 XENSTORE_RING_SIZE);
    100 
    101 		/* Read indexes, then verify. */
    102 		cons = intf->req_cons;
    103 		prod = intf->req_prod;
    104 		mb();
    105 		if (!check_indexes(cons, prod))
    106 			return -EIO;
    107 
    108 		dst = get_output_chunk(cons, prod, intf->req, &avail);
    109 		if (avail == 0)
    110 			continue;
    111 		if (avail > len)
    112 			avail = len;
    113 
    114 		memcpy(dst, data, avail);
    115 		data += avail;
    116 		len -= avail;
    117 
    118 		/* Other side must not see new header until data is there. */
    119 		wmb();
    120 		intf->req_prod += avail;
    121 
    122 		/* This implies mb() before other side sees interrupt. */
    123 		notify_remote_via_evtchn(xen_start_info->store_evtchn);
    124 	}
    125 
    126 	return 0;
    127 }
    128 
    129 int xb_read(void *data, unsigned len)
    130 {
    131 	struct xenstore_domain_interface *intf = xenstore_domain_interface();
    132 	XENSTORE_RING_IDX cons, prod;
    133 
    134 	while (len != 0) {
    135 		unsigned int avail;
    136 		const char *src;
    137 
    138 		wait_event_interruptible(xb_waitq,
    139 					 intf->rsp_cons != intf->rsp_prod);
    140 
    141 		/* Read indexes, then verify. */
    142 		cons = intf->rsp_cons;
    143 		prod = intf->rsp_prod;
    144 		mb();
    145 		if (!check_indexes(cons, prod))
    146 			return -EIO;
    147 
    148 		src = get_input_chunk(cons, prod, intf->rsp, &avail);
    149 		if (avail == 0)
    150 			continue;
    151 		if (avail > len)
    152 			avail = len;
    153 
    154 		/* We must read header before we read data. */
    155 		rmb();
    156 
    157 		memcpy(data, src, avail);
    158 		data += avail;
    159 		len -= avail;
    160 
    161 		/* Other side must not see free space until we've copied out */
    162 		mb();
    163 		intf->rsp_cons += avail;
    164 
    165 		pr_debug("Finished read of %i bytes (%i to go)\n", avail, len);
    166 
    167 		/* Implies mb(): they will see new header. */
    168 		notify_remote_via_evtchn(xen_start_info->store_evtchn);
    169 	}
    170 
    171 	return 0;
    172 }
    173 
    174 /* Set up interrupt handler off store event channel. */
    175 int xb_init_comms(void)
    176 {
    177 	int err;
    178 
    179 	if (xenbus_irq)
    180 		unbind_from_irqhandler(xenbus_irq, &xb_waitq);
    181 
    182 	err = bind_evtchn_to_irqhandler(
    183 		xen_start_info->store_evtchn, wake_waiting,
    184 		0, "xenbus", &xb_waitq);
    185 	if (err <= 0) {
    186 		printk(KERN_ERR "XENBUS request irq failed %i\n", err);
    187 		return err;
    188 	}
    189 
    190 	xenbus_irq = err;
    191 
    192 	return 0;
    193 }
    194 
    195 /*
    196  * Local variables:
    197  *  c-file-style: "linux"
    198  *  indent-tabs-mode: t
    199  *  c-indent-level: 8
    200  *  c-basic-offset: 8
    201  *  tab-width: 8
    202  * End:
    203  */
    204