1 /****************************************************************************
2 * Solarflare driver for Xen network acceleration
4 * Copyright 2006-2008: Solarflare Communications Inc,
5 * 9501 Jeronimo Road, Suite 250,
6 * Irvine, CA 92618, USA
8 * Maintained by Solarflare Communications <linux-xen-drivers@solarflare.com>
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.
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.
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 ****************************************************************************
25 #include <xen/evtchn.h>
27 #include "accel_util.h"
28 #include "accel_msg_iface.h"
30 #define NET_ACCEL_MSG_Q_SIZE (1024)
31 #define NET_ACCEL_MSG_Q_MASK (NET_ACCEL_MSG_Q_SIZE - 1)
34 #define NET_ACCEL_CHECK_MAGIC(_p, _errval)
35 #define NET_ACCEL_SHOW_QUEUE(_t, _q, _id)
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", \
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);
49 * We've been passed at least 2 pages. 1 control page and 1 or more
52 int net_accel_msg_init_page(void *mem, int len, int up)
54 struct net_accel_shared_page *shared_page =
55 (struct net_accel_shared_page*)mem;
57 if ((unsigned long)shared_page & NET_ACCEL_MSG_Q_MASK)
60 shared_page->magic = NET_ACCEL_MSG_MAGIC;
62 shared_page->aflags = 0;
64 shared_page->net_dev_up = up;
68 EXPORT_SYMBOL_GPL(net_accel_msg_init_page);
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)
76 spin_lock_init(&queue->lock);
77 sh_fifo2_init(queue, size-1, &indices->read, &indices->write);
79 EXPORT_SYMBOL_GPL(net_accel_msg_init_queue);
82 static inline int _net_accel_msg_send(struct net_accel_shared_page *sp,
84 struct net_accel_msg *msg,
88 NET_ACCEL_CHECK_MAGIC(sp, -EINVAL);
91 EPRINTK_ON(sh_fifo2_is_full(queue));
92 sh_fifo2_put(queue, *msg);
94 if (sh_fifo2_not_half_full(queue)) {
95 sh_fifo2_put(queue, *msg);
104 /* Notify after a batch of messages have been sent */
105 void net_accel_msg_notify(int irq)
107 notify_remote_via_irq(irq);
109 EXPORT_SYMBOL_GPL(net_accel_msg_notify);
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
116 int net_accel_msg_send(struct net_accel_shared_page *sp, sh_msg_fifo2 *q,
117 struct net_accel_msg *msg)
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);
126 EXPORT_SYMBOL_GPL(net_accel_msg_send);
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)
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);
139 notify_remote_via_irq(irq);
142 EXPORT_SYMBOL_GPL(net_accel_msg_send_notify);
145 int net_accel_msg_reply(struct net_accel_shared_page *sp, sh_msg_fifo2 *q,
146 struct net_accel_msg *msg)
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);
155 EXPORT_SYMBOL_GPL(net_accel_msg_reply);
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)
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);
168 notify_remote_via_irq(irq);
171 EXPORT_SYMBOL_GPL(net_accel_msg_reply_notify);
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()
179 int net_accel_msg_peek(struct net_accel_shared_page *sp,
181 struct net_accel_msg *msg, int *cookie)
185 NET_ACCEL_CHECK_MAGIC(sp, -EINVAL);
186 net_accel_msg_lock_queue(queue, &flags);
188 if (sh_fifo2_is_empty(queue)) {
191 *msg = sh_fifo2_peek(queue);
192 *cookie = *(queue->fifo_rd_i);
194 net_accel_msg_unlock_queue(queue, &flags);
197 EXPORT_SYMBOL_GPL(net_accel_msg_peek);
201 * Move the queue onto the next element, used after finished with a
204 int net_accel_msg_recv_next(struct net_accel_shared_page *sp,
205 sh_msg_fifo2 *queue, int cookie)
208 NET_ACCEL_CHECK_MAGIC(sp, -EINVAL);
209 net_accel_msg_lock_queue(queue, &flags);
211 /* Mustn't be empty */
212 BUG_ON(sh_fifo2_is_empty(queue));
214 * Check cookie matches, i.e. we're advancing over the same message
215 * as was got using peek
217 BUG_ON(cookie != *(queue->fifo_rd_i));
218 sh_fifo2_rd_next(queue);
220 net_accel_msg_unlock_queue(queue, &flags);
223 EXPORT_SYMBOL_GPL(net_accel_msg_recv_next);
227 * Receive a message on the specified FIFO. Returns 0 on success,
230 int net_accel_msg_recv(struct net_accel_shared_page *sp, sh_msg_fifo2 *queue,
231 struct net_accel_msg *msg)
235 NET_ACCEL_CHECK_MAGIC(sp, -EINVAL);
236 net_accel_msg_lock_queue(queue, &flags);
238 if (sh_fifo2_is_empty(queue)) {
241 sh_fifo2_get(queue, msg);
244 net_accel_msg_unlock_queue(queue, &flags);
247 EXPORT_SYMBOL_GPL(net_accel_msg_recv);
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
255 struct net_accel_msg *net_accel_msg_start_send(struct net_accel_shared_page *sp,
256 sh_msg_fifo2 *queue, unsigned long *flags)
258 struct net_accel_msg *msg;
259 NET_ACCEL_CHECK_MAGIC(sp, NULL);
260 net_accel_msg_lock_queue(queue, flags);
262 if (sh_fifo2_not_half_full(queue)) {
263 msg = sh_fifo2_pokep(queue);
265 net_accel_msg_unlock_queue(queue, flags);
270 EXPORT_SYMBOL_GPL(net_accel_msg_start_send);
273 static inline void _msg_complete(struct net_accel_shared_page *sp,
275 unsigned long *flags)
277 sh_fifo2_wr_next(queue);
278 net_accel_msg_unlock_queue(queue, flags);
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
285 void net_accel_msg_complete_send(struct net_accel_shared_page *sp,
287 unsigned long *flags)
289 _msg_complete(sp, queue, flags);
291 EXPORT_SYMBOL_GPL(net_accel_msg_complete_send);
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,
296 unsigned long *flags, int irq)
298 _msg_complete(sp, queue, flags);
299 notify_remote_via_irq(irq);
301 EXPORT_SYMBOL_GPL(net_accel_msg_complete_send_notify);