ia64/linux-2.6.18-xen.hg

view drivers/xen/sfc_netfront/accel_msg.c @ 847:ad4d307bf9ce

net sfc: Update sfc and sfc_resource driver to latest release

...and update sfc_netfront, sfc_netback, sfc_netutil for any API changes

sfc_netback: Fix asymmetric use of SFC buffer table alloc and free
sfc_netback: Clean up if no SFC accel device found
sfc_netback: Gracefully handle case where page grant fails
sfc_netback: Disable net acceleration if the physical link goes down
sfc_netfront: Less verbose error messages, more verbose counters for
rx discard errors
sfc_netfront: Gracefully handle case where SFC netfront fails during
initialisation

Signed-off-by: Kieran Mansley <kmansley@solarflare.com>
author Keir Fraser <keir.fraser@citrix.com>
date Tue Mar 31 11:59:10 2009 +0100 (2009-03-31)
parents 8c8a097cae69
children
line source
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 */
25 #include <linux/stddef.h>
26 #include <linux/errno.h>
28 #include <xen/xenbus.h>
30 #include "accel.h"
31 #include "accel_msg_iface.h"
32 #include "accel_util.h"
33 #include "accel_bufs.h"
35 #include "netfront.h" /* drivers/xen/netfront/netfront.h */
37 static void vnic_start_interrupts(netfront_accel_vnic *vnic)
38 {
39 unsigned long flags;
41 /* Prime our interrupt */
42 spin_lock_irqsave(&vnic->irq_enabled_lock, flags);
43 if (!netfront_accel_vi_enable_interrupts(vnic)) {
44 /* Cripes, that was quick, better pass it up */
45 netfront_accel_disable_net_interrupts(vnic);
46 vnic->irq_enabled = 0;
47 NETFRONT_ACCEL_STATS_OP(vnic->stats.poll_schedule_count++);
48 netif_rx_schedule(vnic->net_dev);
49 } else {
50 /*
51 * Nothing yet, make sure we get interrupts through
52 * back end
53 */
54 vnic->irq_enabled = 1;
55 netfront_accel_enable_net_interrupts(vnic);
56 }
57 spin_unlock_irqrestore(&vnic->irq_enabled_lock, flags);
58 }
61 static void vnic_stop_interrupts(netfront_accel_vnic *vnic)
62 {
63 unsigned long flags;
65 spin_lock_irqsave(&vnic->irq_enabled_lock, flags);
66 netfront_accel_disable_net_interrupts(vnic);
67 vnic->irq_enabled = 0;
68 spin_unlock_irqrestore(&vnic->irq_enabled_lock, flags);
69 }
72 static void vnic_start_fastpath(netfront_accel_vnic *vnic)
73 {
74 struct net_device *net_dev = vnic->net_dev;
75 unsigned long flags;
77 DPRINTK("%s\n", __FUNCTION__);
79 spin_lock_irqsave(&vnic->tx_lock, flags);
80 vnic->tx_enabled = 1;
81 spin_unlock_irqrestore(&vnic->tx_lock, flags);
83 netif_poll_disable(net_dev);
84 vnic->poll_enabled = 1;
85 netif_poll_enable(net_dev);
87 vnic_start_interrupts(vnic);
88 }
91 void vnic_stop_fastpath(netfront_accel_vnic *vnic)
92 {
93 struct net_device *net_dev = vnic->net_dev;
94 struct netfront_info *np = (struct netfront_info *)netdev_priv(net_dev);
95 unsigned long flags1, flags2;
97 DPRINTK("%s\n", __FUNCTION__);
99 vnic_stop_interrupts(vnic);
101 spin_lock_irqsave(&vnic->tx_lock, flags1);
102 vnic->tx_enabled = 0;
103 spin_lock_irqsave(&np->tx_lock, flags2);
104 if (vnic->tx_skb != NULL) {
105 dev_kfree_skb_any(vnic->tx_skb);
106 vnic->tx_skb = NULL;
107 if (netfront_check_queue_ready(net_dev)) {
108 netif_wake_queue(net_dev);
109 NETFRONT_ACCEL_STATS_OP
110 (vnic->stats.queue_wakes++);
111 }
112 }
113 spin_unlock_irqrestore(&np->tx_lock, flags2);
114 spin_unlock_irqrestore(&vnic->tx_lock, flags1);
116 /* Must prevent polls and hold lock to modify poll_enabled */
117 netif_poll_disable(net_dev);
118 spin_lock_irqsave(&vnic->irq_enabled_lock, flags1);
119 vnic->poll_enabled = 0;
120 spin_unlock_irqrestore(&vnic->irq_enabled_lock, flags1);
121 netif_poll_enable(net_dev);
122 }
125 static void netfront_accel_interface_up(netfront_accel_vnic *vnic)
126 {
127 if (!vnic->backend_netdev_up) {
128 vnic->backend_netdev_up = 1;
130 if (vnic->frontend_ready)
131 vnic_start_fastpath(vnic);
132 }
133 }
136 static void netfront_accel_interface_down(netfront_accel_vnic *vnic)
137 {
138 if (vnic->backend_netdev_up) {
139 vnic->backend_netdev_up = 0;
141 if (vnic->frontend_ready)
142 vnic_stop_fastpath(vnic);
143 }
144 }
147 static int vnic_add_bufs(netfront_accel_vnic *vnic,
148 struct net_accel_msg *msg)
149 {
150 int rc, offset;
151 struct netfront_accel_bufinfo *bufinfo;
153 BUG_ON(msg->u.mapbufs.pages > NET_ACCEL_MSG_MAX_PAGE_REQ);
155 offset = msg->u.mapbufs.reqid;
157 if (offset < vnic->bufpages.max_pages -
158 (vnic->bufpages.max_pages / sfc_netfront_buffer_split)) {
159 bufinfo = vnic->rx_bufs;
160 } else
161 bufinfo = vnic->tx_bufs;
163 /* Queue up some Rx buffers to start things off. */
164 if ((rc = netfront_accel_add_bufs(&vnic->bufpages, bufinfo, msg)) == 0) {
165 netfront_accel_vi_add_bufs(vnic, bufinfo == vnic->rx_bufs);
167 if (offset + msg->u.mapbufs.pages == vnic->bufpages.max_pages) {
168 VPRINTK("%s: got all buffers back\n", __FUNCTION__);
169 vnic->frontend_ready = 1;
170 if (vnic->backend_netdev_up)
171 vnic_start_fastpath(vnic);
172 } else {
173 VPRINTK("%s: got buffers back %d %d\n", __FUNCTION__,
174 offset, msg->u.mapbufs.pages);
175 }
176 }
178 return rc;
179 }
182 /* The largest [o] such that (1u << o) <= n. Requires n > 0. */
184 inline unsigned log2_le(unsigned long n) {
185 unsigned order = 1;
186 while ((1ul << order) <= n) ++order;
187 return (order - 1);
188 }
190 static int vnic_send_buffer_requests(netfront_accel_vnic *vnic,
191 struct netfront_accel_bufpages *bufpages)
192 {
193 int pages, offset, rc = 0, sent = 0;
194 struct net_accel_msg msg;
196 while (bufpages->page_reqs < bufpages->max_pages) {
197 offset = bufpages->page_reqs;
199 pages = pow2(log2_le(bufpages->max_pages -
200 bufpages->page_reqs));
201 pages = pages < NET_ACCEL_MSG_MAX_PAGE_REQ ?
202 pages : NET_ACCEL_MSG_MAX_PAGE_REQ;
204 BUG_ON(offset < 0);
205 BUG_ON(pages <= 0);
207 rc = netfront_accel_buf_map_request(vnic->dev, bufpages,
208 &msg, pages, offset);
209 if (rc == 0) {
210 rc = net_accel_msg_send(vnic->shared_page,
211 &vnic->to_dom0, &msg);
212 if (rc < 0) {
213 VPRINTK("%s: queue full, stopping for now\n",
214 __FUNCTION__);
215 break;
216 }
217 sent++;
218 } else {
219 EPRINTK("%s: problem with grant, stopping for now\n",
220 __FUNCTION__);
221 break;
222 }
224 bufpages->page_reqs += pages;
225 }
227 if (sent)
228 net_accel_msg_notify(vnic->msg_channel_irq);
230 return rc;
231 }
234 /*
235 * In response to dom0 saying "my queue is full", we reply with this
236 * when it is no longer full
237 */
238 inline void vnic_set_queue_not_full(netfront_accel_vnic *vnic)
239 {
241 if (test_and_set_bit(NET_ACCEL_MSG_AFLAGS_QUEUE0NOTFULL_B,
242 (unsigned long *)&vnic->shared_page->aflags))
243 notify_remote_via_irq(vnic->msg_channel_irq);
244 else
245 VPRINTK("queue not full bit already set, not signalling\n");
246 }
248 /*
249 * Notify dom0 that the queue we want to use is full, it should
250 * respond by setting MSG_AFLAGS_QUEUEUNOTFULL in due course
251 */
252 inline void vnic_set_queue_full(netfront_accel_vnic *vnic)
253 {
255 if (!test_and_set_bit(NET_ACCEL_MSG_AFLAGS_QUEUEUFULL_B,
256 (unsigned long *)&vnic->shared_page->aflags))
257 notify_remote_via_irq(vnic->msg_channel_irq);
258 else
259 VPRINTK("queue full bit already set, not signalling\n");
260 }
263 static int vnic_check_hello_version(unsigned version)
264 {
265 if (version > NET_ACCEL_MSG_VERSION) {
266 /* Newer protocol, we must refuse */
267 return -EPROTO;
268 }
270 if (version < NET_ACCEL_MSG_VERSION) {
271 /*
272 * We are newer, so have discretion to accept if we
273 * wish. For now however, just reject
274 */
275 return -EPROTO;
276 }
278 BUG_ON(version != NET_ACCEL_MSG_VERSION);
279 return 0;
280 }
283 static int vnic_process_hello_msg(netfront_accel_vnic *vnic,
284 struct net_accel_msg *msg)
285 {
286 int err = 0;
287 unsigned pages = sfc_netfront_max_pages;
289 if (vnic_check_hello_version(msg->u.hello.version) < 0) {
290 msg->id = NET_ACCEL_MSG_HELLO | NET_ACCEL_MSG_REPLY
291 | NET_ACCEL_MSG_ERROR;
292 msg->u.hello.version = NET_ACCEL_MSG_VERSION;
293 } else {
294 vnic->backend_netdev_up
295 = vnic->shared_page->net_dev_up;
297 msg->id = NET_ACCEL_MSG_HELLO | NET_ACCEL_MSG_REPLY;
298 msg->u.hello.version = NET_ACCEL_MSG_VERSION;
299 if (msg->u.hello.max_pages &&
300 msg->u.hello.max_pages < pages)
301 pages = msg->u.hello.max_pages;
302 msg->u.hello.max_pages = pages;
304 /* Half of pages for rx, half for tx */
305 err = netfront_accel_alloc_buffer_mem(&vnic->bufpages,
306 vnic->rx_bufs,
307 vnic->tx_bufs,
308 pages);
309 if (err)
310 msg->id |= NET_ACCEL_MSG_ERROR;
311 }
313 /* Send reply */
314 net_accel_msg_reply_notify(vnic->shared_page, vnic->msg_channel_irq,
315 &vnic->to_dom0, msg);
316 return err;
317 }
320 static int vnic_process_localmac_msg(netfront_accel_vnic *vnic,
321 struct net_accel_msg *msg)
322 {
323 unsigned long flags;
324 cuckoo_hash_mac_key key;
326 if (msg->u.localmac.flags & NET_ACCEL_MSG_ADD) {
327 DPRINTK("MAC has moved, could be local: " MAC_FMT "\n",
328 MAC_ARG(msg->u.localmac.mac));
329 key = cuckoo_mac_to_key(msg->u.localmac.mac);
330 spin_lock_irqsave(&vnic->table_lock, flags);
331 /* Try to remove it, not a big deal if not there */
332 cuckoo_hash_remove(&vnic->fastpath_table,
333 (cuckoo_hash_key *)&key);
334 spin_unlock_irqrestore(&vnic->table_lock, flags);
335 }
337 return 0;
338 }
341 static
342 int vnic_process_rx_msg(netfront_accel_vnic *vnic,
343 struct net_accel_msg *msg)
344 {
345 int err;
347 switch (msg->id) {
348 case NET_ACCEL_MSG_HELLO:
349 /* Hello, reply with Reply */
350 DPRINTK("got Hello, with version %.8x\n",
351 msg->u.hello.version);
352 BUG_ON(vnic->msg_state != NETFRONT_ACCEL_MSG_NONE);
353 err = vnic_process_hello_msg(vnic, msg);
354 if (err == 0)
355 vnic->msg_state = NETFRONT_ACCEL_MSG_HELLO;
356 break;
357 case NET_ACCEL_MSG_SETHW:
358 /* Hardware info message */
359 DPRINTK("got H/W info\n");
360 BUG_ON(vnic->msg_state != NETFRONT_ACCEL_MSG_HELLO);
361 err = netfront_accel_vi_init(vnic, &msg->u.hw);
362 if (err == 0)
363 vnic->msg_state = NETFRONT_ACCEL_MSG_HW;
364 break;
365 case NET_ACCEL_MSG_MAPBUF | NET_ACCEL_MSG_REPLY:
366 VPRINTK("Got mapped buffers back\n");
367 BUG_ON(vnic->msg_state != NETFRONT_ACCEL_MSG_HW);
368 err = vnic_add_bufs(vnic, msg);
369 break;
370 case NET_ACCEL_MSG_MAPBUF | NET_ACCEL_MSG_REPLY | NET_ACCEL_MSG_ERROR:
371 /* No buffers. Can't use the fast path. */
372 EPRINTK("Got mapped buffers error. Cannot accelerate.\n");
373 BUG_ON(vnic->msg_state != NETFRONT_ACCEL_MSG_HW);
374 err = -EIO;
375 break;
376 case NET_ACCEL_MSG_LOCALMAC:
377 /* Should be add, remove not currently used */
378 EPRINTK_ON(!(msg->u.localmac.flags & NET_ACCEL_MSG_ADD));
379 BUG_ON(vnic->msg_state != NETFRONT_ACCEL_MSG_HW);
380 err = vnic_process_localmac_msg(vnic, msg);
381 break;
382 default:
383 EPRINTK("Huh? Message code is 0x%x\n", msg->id);
384 err = -EPROTO;
385 break;
386 }
388 return err;
389 }
392 /* Process an IRQ received from back end driver */
393 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
394 void netfront_accel_msg_from_bend(struct work_struct *context)
395 #else
396 void netfront_accel_msg_from_bend(void *context)
397 #endif
398 {
399 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
400 netfront_accel_vnic *vnic =
401 container_of(context, netfront_accel_vnic, msg_from_bend);
402 #else
403 netfront_accel_vnic *vnic = (netfront_accel_vnic *)context;
404 #endif
405 struct net_accel_msg msg;
406 int err, queue_was_full = 0;
408 mutex_lock(&vnic->vnic_mutex);
410 /*
411 * This happens when the shared pages have been unmapped but
412 * the workqueue has yet to be flushed
413 */
414 if (!vnic->dom0_state_is_setup)
415 goto unlock_out;
417 while ((vnic->shared_page->aflags & NET_ACCEL_MSG_AFLAGS_TO_DOMU_MASK)
418 != 0) {
419 if (vnic->shared_page->aflags &
420 NET_ACCEL_MSG_AFLAGS_QUEUEUNOTFULL) {
421 /* We've been told there may now be space. */
422 clear_bit(NET_ACCEL_MSG_AFLAGS_QUEUEUNOTFULL_B,
423 (unsigned long *)&vnic->shared_page->aflags);
424 }
426 if (vnic->shared_page->aflags &
427 NET_ACCEL_MSG_AFLAGS_QUEUE0FULL) {
428 /*
429 * There will be space at the end of this
430 * function if we can make any.
431 */
432 clear_bit(NET_ACCEL_MSG_AFLAGS_QUEUE0FULL_B,
433 (unsigned long *)&vnic->shared_page->aflags);
434 queue_was_full = 1;
435 }
437 if (vnic->shared_page->aflags &
438 NET_ACCEL_MSG_AFLAGS_NETUPDOWN) {
439 DPRINTK("%s: net interface change\n", __FUNCTION__);
440 clear_bit(NET_ACCEL_MSG_AFLAGS_NETUPDOWN_B,
441 (unsigned long *)&vnic->shared_page->aflags);
442 if (vnic->shared_page->net_dev_up)
443 netfront_accel_interface_up(vnic);
444 else
445 netfront_accel_interface_down(vnic);
446 }
447 }
449 /* Pull msg out of shared memory */
450 while ((err = net_accel_msg_recv(vnic->shared_page, &vnic->from_dom0,
451 &msg)) == 0) {
452 err = vnic_process_rx_msg(vnic, &msg);
454 if (err != 0)
455 goto done;
456 }
458 /*
459 * Send any pending buffer map request messages that we can,
460 * and mark domU->dom0 as full if necessary.
461 */
462 if (vnic->msg_state == NETFRONT_ACCEL_MSG_HW &&
463 vnic->bufpages.page_reqs < vnic->bufpages.max_pages) {
464 if (vnic_send_buffer_requests(vnic, &vnic->bufpages) == -ENOSPC)
465 vnic_set_queue_full(vnic);
466 }
468 /*
469 * If there are no messages then this is not an error. It
470 * just means that we've finished processing the queue.
471 */
472 if (err == -ENOENT)
473 err = 0;
474 done:
475 /* We will now have made space in the dom0->domU queue if we can */
476 if (queue_was_full)
477 vnic_set_queue_not_full(vnic);
479 if (err != 0) {
480 EPRINTK("%s returned %d\n", __FUNCTION__, err);
481 netfront_accel_set_closing(vnic);
482 }
484 unlock_out:
485 mutex_unlock(&vnic->vnic_mutex);
487 return;
488 }
491 irqreturn_t netfront_accel_msg_channel_irq_from_bend(int irq, void *context,
492 struct pt_regs *unused)
493 {
494 netfront_accel_vnic *vnic = (netfront_accel_vnic *)context;
495 VPRINTK("irq %d from device %s\n", irq, vnic->dev->nodename);
497 queue_work(netfront_accel_workqueue, &vnic->msg_from_bend);
499 return IRQ_HANDLED;
500 }
502 /* Process an interrupt received from the NIC via backend */
503 irqreturn_t netfront_accel_net_channel_irq_from_bend(int irq, void *context,
504 struct pt_regs *unused)
505 {
506 netfront_accel_vnic *vnic = (netfront_accel_vnic *)context;
507 struct net_device *net_dev = vnic->net_dev;
508 unsigned long flags;
510 VPRINTK("net irq %d from device %s\n", irq, vnic->dev->nodename);
512 NETFRONT_ACCEL_STATS_OP(vnic->stats.irq_count++);
514 BUG_ON(net_dev==NULL);
516 spin_lock_irqsave(&vnic->irq_enabled_lock, flags);
517 if (vnic->irq_enabled) {
518 netfront_accel_disable_net_interrupts(vnic);
519 vnic->irq_enabled = 0;
520 spin_unlock_irqrestore(&vnic->irq_enabled_lock, flags);
522 #if NETFRONT_ACCEL_STATS
523 vnic->stats.poll_schedule_count++;
524 if (vnic->stats.event_count_since_irq >
525 vnic->stats.events_per_irq_max)
526 vnic->stats.events_per_irq_max =
527 vnic->stats.event_count_since_irq;
528 vnic->stats.event_count_since_irq = 0;
529 #endif
530 netif_rx_schedule(net_dev);
531 }
532 else {
533 spin_unlock_irqrestore(&vnic->irq_enabled_lock, flags);
534 NETFRONT_ACCEL_STATS_OP(vnic->stats.useless_irq_count++);
535 DPRINTK("%s: irq when disabled\n", __FUNCTION__);
536 }
538 return IRQ_HANDLED;
539 }
542 void netfront_accel_msg_tx_fastpath(netfront_accel_vnic *vnic, const void *mac,
543 u32 ip, u16 port, u8 protocol)
544 {
545 unsigned long lock_state;
546 struct net_accel_msg *msg;
548 msg = net_accel_msg_start_send(vnic->shared_page, &vnic->to_dom0,
549 &lock_state);
551 if (msg == NULL)
552 return;
554 net_accel_msg_init(msg, NET_ACCEL_MSG_FASTPATH);
555 msg->u.fastpath.flags = NET_ACCEL_MSG_REMOVE;
556 memcpy(msg->u.fastpath.mac, mac, ETH_ALEN);
558 msg->u.fastpath.port = port;
559 msg->u.fastpath.ip = ip;
560 msg->u.fastpath.proto = protocol;
562 net_accel_msg_complete_send_notify(vnic->shared_page, &vnic->to_dom0,
563 &lock_state, vnic->msg_channel_irq);
564 }