- Update Xen patches to 3.3-rc5 and c/s 1157.
[linux-flexiantxendom0-3.2.10.git] / drivers / xen / sfc_netutil / accel_msg_iface.c
1 /****************************************************************************
2  * Solarflare driver for Xen network acceleration
3  *
4  * Copyright 2006-2008: Solarflare Communications Inc,
5  *                      9501 Jeronimo Road, Suite 250,
6  *                      Irvine, CA 92618, USA
7  *
8  * Maintained by Solarflare Communications <linux-xen-drivers@solarflare.com>
9  *
10  * This program is free software; you can redistribute it and/or modify it
11  * under the terms of the GNU General Public License version 2 as published
12  * by the Free Software Foundation, incorporated herein by reference.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
22  ****************************************************************************
23  */
24
25 #include <xen/evtchn.h>
26
27 #include "accel_util.h"
28 #include "accel_msg_iface.h"
29
30 #define NET_ACCEL_MSG_Q_SIZE (1024)
31 #define NET_ACCEL_MSG_Q_MASK (NET_ACCEL_MSG_Q_SIZE - 1)
32
33 #ifdef NDEBUG
34 #define NET_ACCEL_CHECK_MAGIC(_p, _errval)
35 #define NET_ACCEL_SHOW_QUEUE(_t, _q, _id)
36 #else
37 #define NET_ACCEL_CHECK_MAGIC(_p, _errval)                              \
38         if (_p->magic != NET_ACCEL_MSG_MAGIC) {                         \
39                 pr_err("%s: passed invalid shared page %p!\n",          \
40                        __FUNCTION__, _p);                               \
41                 return _errval;                                         \
42         }
43 #define NET_ACCEL_SHOW_QUEUE(_t, _q, _id)                               \
44         printk(_t ": queue %d write %x read %x base %x limit %x\n",     \
45                _id, _q->write, _q->read, _q->base, _q->limit);
46 #endif
47
48 /*
49  * We've been passed at least 2 pages. 1 control page and 1 or more
50  * data pages.
51  */
52 int net_accel_msg_init_page(void *mem, int len, int up)
53 {
54         struct net_accel_shared_page *shared_page = 
55                 (struct net_accel_shared_page*)mem;
56
57         if ((unsigned long)shared_page & NET_ACCEL_MSG_Q_MASK)
58                 return -EINVAL;
59
60         shared_page->magic = NET_ACCEL_MSG_MAGIC;
61
62         shared_page->aflags = 0;
63
64         shared_page->net_dev_up = up;
65
66         return 0;
67 }
68 EXPORT_SYMBOL_GPL(net_accel_msg_init_page);
69
70
71 void net_accel_msg_init_queue(sh_msg_fifo2 *queue,
72                               struct net_accel_msg_queue *indices,
73                               struct net_accel_msg *base, int size)
74 {
75         queue->fifo = base;
76         spin_lock_init(&queue->lock);
77         sh_fifo2_init(queue, size-1, &indices->read, &indices->write);
78 }
79 EXPORT_SYMBOL_GPL(net_accel_msg_init_queue);
80
81
82 static inline int _net_accel_msg_send(struct net_accel_shared_page *sp,
83                                       sh_msg_fifo2 *queue,
84                                       struct net_accel_msg *msg,
85                                       int is_reply)
86 {
87         int rc = 0;
88         NET_ACCEL_CHECK_MAGIC(sp, -EINVAL);
89         rmb();
90         if (is_reply) {
91                 EPRINTK_ON(sh_fifo2_is_full(queue));
92                 sh_fifo2_put(queue, *msg);
93         } else {
94                 if (sh_fifo2_not_half_full(queue)) {
95                         sh_fifo2_put(queue, *msg);
96                 } else {
97                         rc = -ENOSPC;
98                 }
99         }
100         wmb();
101         return rc;
102 }
103
104 /* Notify after a batch of messages have been sent */
105 void net_accel_msg_notify(int irq)
106 {
107         notify_remote_via_irq(irq);
108 }
109 EXPORT_SYMBOL_GPL(net_accel_msg_notify);
110
111 /* 
112  * Send a message on the specified FIFO. Returns 0 on success, -errno
113  * on failure. The message in msg is copied to the current slot of the
114  * FIFO.
115  */
116 int net_accel_msg_send(struct net_accel_shared_page *sp, sh_msg_fifo2 *q, 
117                        struct net_accel_msg *msg)
118 {
119         unsigned long flags;
120         int rc;
121         net_accel_msg_lock_queue(q, &flags);
122         rc = _net_accel_msg_send(sp, q, msg, 0);
123         net_accel_msg_unlock_queue(q, &flags);
124         return rc;
125 }
126 EXPORT_SYMBOL_GPL(net_accel_msg_send);
127
128
129 /* As net_accel_msg_send but also posts a notification to the far end. */
130 int net_accel_msg_send_notify(struct net_accel_shared_page *sp, int irq, 
131                               sh_msg_fifo2 *q, struct net_accel_msg *msg)
132 {
133         unsigned long flags;
134         int rc;
135         net_accel_msg_lock_queue(q, &flags);
136         rc = _net_accel_msg_send(sp, q, msg, 0);
137         net_accel_msg_unlock_queue(q, &flags);
138         if (rc >= 0)
139                 notify_remote_via_irq(irq);
140         return rc;
141 }
142 EXPORT_SYMBOL_GPL(net_accel_msg_send_notify);
143
144
145 int net_accel_msg_reply(struct net_accel_shared_page *sp, sh_msg_fifo2 *q, 
146                        struct net_accel_msg *msg)
147 {
148         unsigned long flags;
149         int rc;
150         net_accel_msg_lock_queue(q, &flags);
151         rc = _net_accel_msg_send(sp, q, msg, 1);
152         net_accel_msg_unlock_queue(q, &flags);
153         return rc;
154 }
155 EXPORT_SYMBOL_GPL(net_accel_msg_reply);
156
157
158 /* As net_accel_msg_send but also posts a notification to the far end. */
159 int net_accel_msg_reply_notify(struct net_accel_shared_page *sp, int irq, 
160                               sh_msg_fifo2 *q, struct net_accel_msg *msg)
161 {
162         unsigned long flags;
163         int rc;
164         net_accel_msg_lock_queue(q, &flags);
165         rc = _net_accel_msg_send(sp, q, msg, 1);
166         net_accel_msg_unlock_queue(q, &flags);
167         if (rc >= 0)
168                 notify_remote_via_irq(irq);
169         return rc;
170 }
171 EXPORT_SYMBOL_GPL(net_accel_msg_reply_notify);
172
173
174 /*
175  * Look at a received message, if any, so a decision can be made about
176  * whether to read it now or not.  Cookie is a bit of debug which is
177  * set here and checked when passed to net_accel_msg_recv_next()
178  */
179 int net_accel_msg_peek(struct net_accel_shared_page *sp, 
180                        sh_msg_fifo2 *queue, 
181                        struct net_accel_msg *msg, int *cookie)
182 {
183         unsigned long flags;
184         int rc = 0;
185         NET_ACCEL_CHECK_MAGIC(sp, -EINVAL);
186         net_accel_msg_lock_queue(queue, &flags);
187         rmb();
188         if (sh_fifo2_is_empty(queue)) {
189                 rc = -ENOENT;
190         } else {
191                 *msg = sh_fifo2_peek(queue);
192                 *cookie = *(queue->fifo_rd_i);
193         }
194         net_accel_msg_unlock_queue(queue, &flags);
195         return rc;
196 }
197 EXPORT_SYMBOL_GPL(net_accel_msg_peek);
198
199
200 /*
201  * Move the queue onto the next element, used after finished with a
202  * peeked msg 
203  */
204 int net_accel_msg_recv_next(struct net_accel_shared_page *sp, 
205                             sh_msg_fifo2 *queue, int cookie)
206 {
207         unsigned long flags;
208         NET_ACCEL_CHECK_MAGIC(sp, -EINVAL);
209         net_accel_msg_lock_queue(queue, &flags);
210         rmb();
211         /* Mustn't be empty */
212         BUG_ON(sh_fifo2_is_empty(queue));
213         /* 
214          * Check cookie matches, i.e. we're advancing over the same message
215          * as was got using peek 
216          */
217         BUG_ON(cookie != *(queue->fifo_rd_i));
218         sh_fifo2_rd_next(queue);
219         wmb();
220         net_accel_msg_unlock_queue(queue, &flags);
221         return 0;
222 }
223 EXPORT_SYMBOL_GPL(net_accel_msg_recv_next);
224
225
226 /* 
227  * Receive a message on the specified FIFO. Returns 0 on success,
228  * -errno on failure.
229  */
230 int net_accel_msg_recv(struct net_accel_shared_page *sp, sh_msg_fifo2 *queue, 
231                        struct net_accel_msg *msg)
232 {
233         unsigned long flags;
234         int rc = 0;
235         NET_ACCEL_CHECK_MAGIC(sp, -EINVAL);
236         net_accel_msg_lock_queue(queue, &flags);
237         rmb();
238         if (sh_fifo2_is_empty(queue)) {
239                 rc = -ENOENT;
240         } else {
241                 sh_fifo2_get(queue, msg);
242         }
243         wmb();
244         net_accel_msg_unlock_queue(queue, &flags);
245         return rc;
246 }
247 EXPORT_SYMBOL_GPL(net_accel_msg_recv);
248
249
250 /* 
251  * Start sending a message without copying. returns a pointer to a message
252  * that will be filled out in place. The queue is locked until the message 
253  * is sent.
254  */
255 struct net_accel_msg *net_accel_msg_start_send(struct net_accel_shared_page *sp,
256                                                sh_msg_fifo2 *queue, unsigned long *flags)
257 {
258         struct net_accel_msg *msg;
259         NET_ACCEL_CHECK_MAGIC(sp, NULL);
260         net_accel_msg_lock_queue(queue, flags);
261         rmb();
262         if (sh_fifo2_not_half_full(queue)) {
263                 msg = sh_fifo2_pokep(queue);
264         } else {
265                 net_accel_msg_unlock_queue(queue, flags);
266                 msg = NULL;
267         }
268         return msg;
269 }
270 EXPORT_SYMBOL_GPL(net_accel_msg_start_send);
271
272
273 static inline void _msg_complete(struct net_accel_shared_page *sp,
274                                  sh_msg_fifo2 *queue,
275                                  unsigned long *flags)
276 {
277         sh_fifo2_wr_next(queue);
278         net_accel_msg_unlock_queue(queue, flags);
279 }
280
281 /*
282  * Complete the sending of a message started with net_accel_msg_start_send. The 
283  * message is implicit since the queue was locked by _start
284  */
285 void net_accel_msg_complete_send(struct net_accel_shared_page *sp,
286                                  sh_msg_fifo2 *queue,
287                                  unsigned long *flags)
288 {
289         _msg_complete(sp, queue, flags);
290 }
291 EXPORT_SYMBOL_GPL(net_accel_msg_complete_send);
292
293 /* As net_accel_msg_complete_send but does the notify. */
294 void net_accel_msg_complete_send_notify(struct net_accel_shared_page *sp, 
295                                         sh_msg_fifo2 *queue, 
296                                         unsigned long *flags, int irq)
297 {
298         _msg_complete(sp, queue, flags);
299         notify_remote_via_irq(irq);
300 }
301 EXPORT_SYMBOL_GPL(net_accel_msg_complete_send_notify);