Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  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 program is free software; you can redistribute it and/or
  9  * modify it under the terms of the GNU General Public License version 2
 10  * as published by the Free Software Foundation; or, when distributed
 11  * separately from the Linux kernel or incorporated into other
 12  * software packages, subject to the following license:
 13  *
 14  * Permission is hereby granted, free of charge, to any person obtaining a copy
 15  * of this source file (the "Software"), to deal in the Software without
 16  * restriction, including without limitation the rights to use, copy, modify,
 17  * merge, publish, distribute, sublicense, and/or sell copies of the Software,
 18  * and to permit persons to whom the Software is furnished to do so, subject to
 19  * the following conditions:
 20  *
 21  * The above copyright notice and this permission notice shall be included in
 22  * all copies or substantial portions of the Software.
 23  *
 24  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 25  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 26  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 27  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 28  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 29  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 30  * IN THE SOFTWARE.
 31  */
 32 
 33 #include <linux/wait.h>
 34 #include <linux/interrupt.h>
 35 #include <linux/sched.h>
 36 #include <linux/err.h>
 37 #include <xen/xenbus.h>
 38 #include <asm/xen/hypervisor.h>
 39 #include <xen/events.h>
 40 #include <xen/page.h>
 41 #include "xenbus_comms.h"
 42 
 43 static int xenbus_irq;
 44 
 45 static DECLARE_WORK(probe_work, xenbus_probe);
 46 
 47 static DECLARE_WAIT_QUEUE_HEAD(xb_waitq);
 48 
 49 static irqreturn_t wake_waiting(int irq, void *unused)
 50 {
 51         if (unlikely(xenstored_ready == 0)) {
 52                 xenstored_ready = 1;
 53                 schedule_work(&probe_work);
 54         }
 55 
 56         wake_up(&xb_waitq);
 57         return IRQ_HANDLED;
 58 }
 59 
 60 static int check_indexes(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod)
 61 {
 62         return ((prod - cons) <= XENSTORE_RING_SIZE);
 63 }
 64 
 65 static void *get_output_chunk(XENSTORE_RING_IDX cons,
 66                               XENSTORE_RING_IDX prod,
 67                               char *buf, uint32_t *len)
 68 {
 69         *len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(prod);
 70         if ((XENSTORE_RING_SIZE - (prod - cons)) < *len)
 71                 *len = XENSTORE_RING_SIZE - (prod - cons);
 72         return buf + MASK_XENSTORE_IDX(prod);
 73 }
 74 
 75 static const void *get_input_chunk(XENSTORE_RING_IDX cons,
 76                                    XENSTORE_RING_IDX prod,
 77                                    const char *buf, uint32_t *len)
 78 {
 79         *len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(cons);
 80         if ((prod - cons) < *len)
 81                 *len = prod - cons;
 82         return buf + MASK_XENSTORE_IDX(cons);
 83 }
 84 
 85 /**
 86  * xb_write - low level write
 87  * @data: buffer to send
 88  * @len: length of buffer
 89  *
 90  * Returns 0 on success, error otherwise.
 91  */
 92 int xb_write(const void *data, unsigned len)
 93 {
 94         struct xenstore_domain_interface *intf = xen_store_interface;
 95         XENSTORE_RING_IDX cons, prod;
 96         int rc;
 97 
 98         while (len != 0) {
 99                 void *dst;
100                 unsigned int avail;
101 
102                 rc = wait_event_interruptible(
103                         xb_waitq,
104                         (intf->req_prod - intf->req_cons) !=
105                         XENSTORE_RING_SIZE);
106                 if (rc < 0)
107                         return rc;
108 
109                 /* Read indexes, then verify. */
110                 cons = intf->req_cons;
111                 prod = intf->req_prod;
112                 if (!check_indexes(cons, prod)) {
113                         intf->req_cons = intf->req_prod = 0;
114                         return -EIO;
115                 }
116 
117                 dst = get_output_chunk(cons, prod, intf->req, &avail);
118                 if (avail == 0)
119                         continue;
120                 if (avail > len)
121                         avail = len;
122 
123                 /* Must write data /after/ reading the consumer index. */
124                 mb();
125 
126                 memcpy(dst, data, avail);
127                 data += avail;
128                 len -= avail;
129 
130                 /* Other side must not see new producer until data is there. */
131                 wmb();
132                 intf->req_prod += avail;
133 
134                 /* Implies mb(): other side will see the updated producer. */
135                 notify_remote_via_evtchn(xen_store_evtchn);
136         }
137 
138         return 0;
139 }
140 
141 int xb_data_to_read(void)
142 {
143         struct xenstore_domain_interface *intf = xen_store_interface;
144         return (intf->rsp_cons != intf->rsp_prod);
145 }
146 
147 int xb_wait_for_data_to_read(void)
148 {
149         return wait_event_interruptible(xb_waitq, xb_data_to_read());
150 }
151 
152 int xb_read(void *data, unsigned len)
153 {
154         struct xenstore_domain_interface *intf = xen_store_interface;
155         XENSTORE_RING_IDX cons, prod;
156         int rc;
157 
158         while (len != 0) {
159                 unsigned int avail;
160                 const char *src;
161 
162                 rc = xb_wait_for_data_to_read();
163                 if (rc < 0)
164                         return rc;
165 
166                 /* Read indexes, then verify. */
167                 cons = intf->rsp_cons;
168                 prod = intf->rsp_prod;
169                 if (!check_indexes(cons, prod)) {
170                         intf->rsp_cons = intf->rsp_prod = 0;
171                         return -EIO;
172                 }
173 
174                 src = get_input_chunk(cons, prod, intf->rsp, &avail);
175                 if (avail == 0)
176                         continue;
177                 if (avail > len)
178                         avail = len;
179 
180                 /* Must read data /after/ reading the producer index. */
181                 rmb();
182 
183                 memcpy(data, src, avail);
184                 data += avail;
185                 len -= avail;
186 
187                 /* Other side must not see free space until we've copied out */
188                 mb();
189                 intf->rsp_cons += avail;
190 
191                 pr_debug("Finished read of %i bytes (%i to go)\n", avail, len);
192 
193                 /* Implies mb(): other side will see the updated consumer. */
194                 notify_remote_via_evtchn(xen_store_evtchn);
195         }
196 
197         return 0;
198 }
199 
200 /**
201  * xb_init_comms - Set up interrupt handler off store event channel.
202  */
203 int xb_init_comms(void)
204 {
205         struct xenstore_domain_interface *intf = xen_store_interface;
206         int err;
207 
208         if (intf->req_prod != intf->req_cons)
209                 printk(KERN_ERR "XENBUS request ring is not quiescent "
210                        "(%08x:%08x)!\n", intf->req_cons, intf->req_prod);
211 
212         if (intf->rsp_prod != intf->rsp_cons) {
213                 printk(KERN_WARNING "XENBUS response ring is not quiescent "
214                        "(%08x:%08x): fixing up\n",
215                        intf->rsp_cons, intf->rsp_prod);
216                 intf->rsp_cons = intf->rsp_prod;
217         }
218 
219         if (xenbus_irq)
220                 unbind_from_irqhandler(xenbus_irq, &xb_waitq);
221 
222         err = bind_evtchn_to_irqhandler(
223                 xen_store_evtchn, wake_waiting,
224                 0, "xenbus", &xb_waitq);
225         if (err <= 0) {
226                 printk(KERN_ERR "XENBUS request irq failed %i\n", err);
227                 return err;
228         }
229 
230         xenbus_irq = err;
231 
232         return 0;
233 }
234 
  This page was automatically generated by the LXR engine.