ia64/linux-2.6.18-xen.hg

view drivers/xen/netfront/accel.c @ 856:e5d3f2fa3428

netfront accel: Better watch handling across suspend/resume

Signed-off-by: Kieran Mansley <kmansley@solarflare.com>
author Keir Fraser <keir.fraser@citrix.com>
date Tue Apr 07 10:29:30 2009 +0100 (2009-04-07)
parents ab1d4fbbe4bf
children
line source
1 /******************************************************************************
2 * Virtual network driver for conversing with remote driver backends.
3 *
4 * Copyright (C) 2007 Solarflare Communications, Inc.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License version 2
8 * as published by the Free Software Foundation; or, when distributed
9 * separately from the Linux kernel or incorporated into other
10 * software packages, subject to the following license:
11 *
12 * Permission is hereby granted, free of charge, to any person obtaining a copy
13 * of this source file (the "Software"), to deal in the Software without
14 * restriction, including without limitation the rights to use, copy, modify,
15 * merge, publish, distribute, sublicense, and/or sell copies of the Software,
16 * and to permit persons to whom the Software is furnished to do so, subject to
17 * the following conditions:
18 *
19 * The above copyright notice and this permission notice shall be included in
20 * all copies or substantial portions of the Software.
21 *
22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
28 * IN THE SOFTWARE.
29 */
31 #include <linux/netdevice.h>
32 #include <linux/skbuff.h>
33 #include <linux/list.h>
34 #include <linux/mutex.h>
35 #include <asm/hypervisor.h>
36 #include <xen/xenbus.h>
38 #include "netfront.h"
40 #define DPRINTK(fmt, args...) \
41 pr_debug("netfront/accel (%s:%d) " fmt, \
42 __FUNCTION__, __LINE__, ##args)
43 #define IPRINTK(fmt, args...) \
44 printk(KERN_INFO "netfront/accel: " fmt, ##args)
45 #define WPRINTK(fmt, args...) \
46 printk(KERN_WARNING "netfront/accel: " fmt, ##args)
48 static int netfront_remove_accelerator(struct netfront_info *np,
49 struct xenbus_device *dev);
50 static int netfront_load_accelerator(struct netfront_info *np,
51 struct xenbus_device *dev,
52 const char *frontend);
54 static void netfront_accelerator_remove_watch(struct netfront_info *np);
56 /*
57 * List of all netfront accelerator plugin modules available. Each
58 * list entry is of type struct netfront_accelerator.
59 */
60 static struct list_head accelerators_list;
62 /* Workqueue to process acceleration configuration changes */
63 struct workqueue_struct *accel_watch_workqueue;
65 /* Mutex to prevent concurrent loads and suspends, etc. */
66 DEFINE_MUTEX(accelerator_mutex);
68 void netif_init_accel(void)
69 {
70 INIT_LIST_HEAD(&accelerators_list);
72 accel_watch_workqueue = create_workqueue("net_accel");
73 }
75 void netif_exit_accel(void)
76 {
77 struct netfront_accelerator *accelerator, *tmp;
79 flush_workqueue(accel_watch_workqueue);
80 destroy_workqueue(accel_watch_workqueue);
82 /* No lock required as everything else should be quiet by now */
83 list_for_each_entry_safe(accelerator, tmp, &accelerators_list, link) {
84 BUG_ON(!list_empty(&accelerator->vif_states));
86 list_del(&accelerator->link);
87 kfree(accelerator->frontend);
88 kfree(accelerator);
89 }
90 }
93 /*
94 * Watch the configured accelerator and change plugin if it's modified
95 */
96 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
97 static void accel_watch_work(struct work_struct *context)
98 #else
99 static void accel_watch_work(void *context)
100 #endif
101 {
102 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
103 struct netfront_accel_vif_state *vif_state =
104 container_of(context, struct netfront_accel_vif_state,
105 accel_work);
106 #else
107 struct netfront_accel_vif_state *vif_state =
108 (struct netfront_accel_vif_state *)context;
109 #endif
110 struct netfront_info *np = vif_state->np;
111 char *accel_frontend;
112 int accel_len, rc = -1;
114 mutex_lock(&accelerator_mutex);
116 accel_frontend = xenbus_read(XBT_NIL, np->xbdev->otherend,
117 "accel-frontend", &accel_len);
118 if (IS_ERR(accel_frontend)) {
119 accel_frontend = NULL;
120 netfront_remove_accelerator(np, np->xbdev);
121 } else {
122 /* If this is the first time, request the accelerator,
123 otherwise only request one if it has changed */
124 if (vif_state->accel_frontend == NULL) {
125 rc = netfront_load_accelerator(np, np->xbdev,
126 accel_frontend);
127 } else {
128 if (strncmp(vif_state->accel_frontend, accel_frontend,
129 accel_len)) {
130 netfront_remove_accelerator(np, np->xbdev);
131 rc = netfront_load_accelerator(np, np->xbdev,
132 accel_frontend);
133 }
134 }
135 }
137 /* Get rid of previous state and replace with the new name */
138 if (vif_state->accel_frontend != NULL)
139 kfree(vif_state->accel_frontend);
140 vif_state->accel_frontend = accel_frontend;
142 mutex_unlock(&accelerator_mutex);
144 if (rc == 0) {
145 DPRINTK("requesting module %s\n", accel_frontend);
146 request_module("%s", accel_frontend);
147 /*
148 * Module should now call netfront_accelerator_loaded() once
149 * it's up and running, and we can continue from there
150 */
151 }
152 }
155 static void accel_watch_changed(struct xenbus_watch *watch,
156 const char **vec, unsigned int len)
157 {
158 struct netfront_accel_vif_state *vif_state =
159 container_of(watch, struct netfront_accel_vif_state,
160 accel_watch);
161 queue_work(accel_watch_workqueue, &vif_state->accel_work);
162 }
165 void netfront_accelerator_add_watch(struct netfront_info *np)
166 {
167 int err;
169 /*
170 * If old watch exists, e.g. from before suspend/resume,
171 * remove it now
172 */
173 netfront_accelerator_remove_watch(np);
175 /* Get a watch on the accelerator plugin */
176 err = xenbus_watch_path2(np->xbdev, np->xbdev->otherend,
177 "accel-frontend",
178 &np->accel_vif_state.accel_watch,
179 accel_watch_changed);
180 if (err) {
181 DPRINTK("%s: Failed to register accel watch: %d\n",
182 __FUNCTION__, err);
183 np->accel_vif_state.accel_watch.node = NULL;
184 }
185 }
188 static void
189 netfront_accelerator_purge_watch(struct netfront_accel_vif_state *vif_state)
190 {
191 flush_workqueue(accel_watch_workqueue);
193 /* Clean up any state left from watch */
194 if (vif_state->accel_frontend != NULL) {
195 kfree(vif_state->accel_frontend);
196 vif_state->accel_frontend = NULL;
197 }
198 }
201 static
202 void netfront_accelerator_remove_watch(struct netfront_info *np)
203 {
204 struct netfront_accel_vif_state *vif_state = &np->accel_vif_state;
206 /* Get rid of watch on accelerator plugin */
207 if (vif_state->accel_watch.node != NULL) {
208 unregister_xenbus_watch(&vif_state->accel_watch);
209 kfree(vif_state->accel_watch.node);
210 vif_state->accel_watch.node = NULL;
212 netfront_accelerator_purge_watch(vif_state);
213 }
214 }
217 /*
218 * Initialise the accel_vif_state field in the netfront state
219 */
220 void init_accelerator_vif(struct netfront_info *np,
221 struct xenbus_device *dev)
222 {
223 np->accelerator = NULL;
225 /* It's assumed that these things don't change */
226 np->accel_vif_state.np = np;
227 np->accel_vif_state.dev = dev;
229 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
230 INIT_WORK(&np->accel_vif_state.accel_work, accel_watch_work);
231 #else
232 INIT_WORK(&np->accel_vif_state.accel_work, accel_watch_work,
233 &np->accel_vif_state);
234 #endif
235 }
238 /*
239 * Compare a frontend description string against an accelerator to see
240 * if they match. Would ultimately be nice to replace the string with
241 * a unique numeric identifier for each accelerator.
242 */
243 static int match_accelerator(const char *frontend,
244 struct netfront_accelerator *accelerator)
245 {
246 return strcmp(frontend, accelerator->frontend) == 0;
247 }
250 /*
251 * Add a frontend vif to the list of vifs that is using a netfront
252 * accelerator plugin module. Must be called with the accelerator
253 * mutex held.
254 */
255 static void add_accelerator_vif(struct netfront_accelerator *accelerator,
256 struct netfront_info *np)
257 {
258 if (np->accelerator == NULL) {
259 np->accelerator = accelerator;
261 list_add(&np->accel_vif_state.link, &accelerator->vif_states);
262 } else {
263 /*
264 * May get here legitimately if suspend_cancel is
265 * called, but in that case configuration should not
266 * have changed
267 */
268 BUG_ON(np->accelerator != accelerator);
269 }
270 }
273 /*
274 * Initialise the state to track an accelerator plugin module.
275 *
276 * Must be called with the accelerator mutex held.
277 */
278 static int init_accelerator(const char *frontend,
279 struct netfront_accelerator **result,
280 struct netfront_accel_hooks *hooks)
281 {
282 struct netfront_accelerator *accelerator =
283 kmalloc(sizeof(struct netfront_accelerator), GFP_KERNEL);
284 int frontend_len;
286 if (!accelerator) {
287 DPRINTK("no memory for accelerator\n");
288 return -ENOMEM;
289 }
291 frontend_len = strlen(frontend) + 1;
292 accelerator->frontend = kmalloc(frontend_len, GFP_KERNEL);
293 if (!accelerator->frontend) {
294 DPRINTK("no memory for accelerator\n");
295 kfree(accelerator);
296 return -ENOMEM;
297 }
298 strlcpy(accelerator->frontend, frontend, frontend_len);
300 INIT_LIST_HEAD(&accelerator->vif_states);
301 spin_lock_init(&accelerator->vif_states_lock);
303 accelerator->hooks = hooks;
305 list_add(&accelerator->link, &accelerators_list);
307 *result = accelerator;
309 return 0;
310 }
313 /*
314 * Modify the hooks stored in the per-vif state to match that in the
315 * netfront accelerator's state.
316 *
317 * Takes the vif_states_lock spinlock and may sleep.
318 */
319 static void
320 accelerator_set_vif_state_hooks(struct netfront_accel_vif_state *vif_state)
321 {
322 struct netfront_accelerator *accelerator;
323 unsigned long flags;
325 DPRINTK("%p\n",vif_state);
327 /* Make sure there are no data path operations going on */
328 netif_poll_disable(vif_state->np->netdev);
329 netif_tx_lock_bh(vif_state->np->netdev);
331 accelerator = vif_state->np->accelerator;
332 spin_lock_irqsave(&accelerator->vif_states_lock, flags);
333 vif_state->hooks = accelerator->hooks;
334 spin_unlock_irqrestore(&accelerator->vif_states_lock, flags);
336 netif_tx_unlock_bh(vif_state->np->netdev);
337 netif_poll_enable(vif_state->np->netdev);
338 }
341 /*
342 * Must be called with the accelerator mutex held. Takes the
343 * vif_states_lock spinlock.
344 */
345 static void accelerator_probe_new_vif(struct netfront_info *np,
346 struct xenbus_device *dev,
347 struct netfront_accelerator *accelerator)
348 {
349 struct netfront_accel_hooks *hooks;
351 DPRINTK("\n");
353 /* Include this frontend device on the accelerator's list */
354 add_accelerator_vif(accelerator, np);
356 hooks = accelerator->hooks;
358 if (hooks && hooks->new_device(np->netdev, dev) == 0)
359 accelerator_set_vif_state_hooks(&np->accel_vif_state);
361 return;
362 }
365 /*
366 * Request that a particular netfront accelerator plugin is loaded.
367 * Usually called as a result of the vif configuration specifying
368 * which one to use.
369 *
370 * Must be called with accelerator_mutex held. Takes the
371 * vif_states_lock spinlock.
372 */
373 static int netfront_load_accelerator(struct netfront_info *np,
374 struct xenbus_device *dev,
375 const char *frontend)
376 {
377 struct netfront_accelerator *accelerator;
378 int rc = 0;
380 DPRINTK(" %s\n", frontend);
382 /*
383 * Look at list of loaded accelerators to see if the requested
384 * one is already there
385 */
386 list_for_each_entry(accelerator, &accelerators_list, link) {
387 if (match_accelerator(frontend, accelerator)) {
388 accelerator_probe_new_vif(np, dev, accelerator);
389 return 0;
390 }
391 }
393 /* Couldn't find it, so create a new one and load the module */
394 if ((rc = init_accelerator(frontend, &accelerator, NULL)) < 0) {
395 return rc;
396 }
398 /* Include this frontend device on the accelerator's list */
399 add_accelerator_vif(accelerator, np);
401 return rc;
402 }
405 /*
406 * Go through all the netfront vifs and see if they have requested
407 * this accelerator. Notify the accelerator plugin of the relevant
408 * device if so. Called when an accelerator plugin module is first
409 * loaded and connects to netfront.
410 *
411 * Must be called with accelerator_mutex held. Takes the
412 * vif_states_lock spinlock.
413 */
414 static void
415 accelerator_probe_vifs(struct netfront_accelerator *accelerator,
416 struct netfront_accel_hooks *hooks)
417 {
418 struct netfront_accel_vif_state *vif_state, *tmp;
420 DPRINTK("%p\n", accelerator);
422 /*
423 * Store the hooks for future calls to probe a new device, and
424 * to wire into the vif_state once the accelerator plugin is
425 * ready to accelerate each vif
426 */
427 BUG_ON(hooks == NULL);
428 accelerator->hooks = hooks;
430 /* Holds accelerator_mutex to iterate list */
431 list_for_each_entry_safe(vif_state, tmp, &accelerator->vif_states,
432 link) {
433 struct netfront_info *np = vif_state->np;
435 if (hooks->new_device(np->netdev, vif_state->dev) == 0)
436 accelerator_set_vif_state_hooks(vif_state);
437 }
438 }
441 /*
442 * Called by the netfront accelerator plugin module when it has
443 * loaded.
444 *
445 * Takes the accelerator_mutex and vif_states_lock spinlock.
446 */
447 int netfront_accelerator_loaded(int version, const char *frontend,
448 struct netfront_accel_hooks *hooks)
449 {
450 struct netfront_accelerator *accelerator;
452 if (is_initial_xendomain())
453 return -EINVAL;
455 if (version != NETFRONT_ACCEL_VERSION) {
456 if (version > NETFRONT_ACCEL_VERSION) {
457 /* Caller has higher version number, leave it
458 up to them to decide whether to continue.
459 They can re-call with a lower number if
460 they're happy to be compatible with us */
461 return NETFRONT_ACCEL_VERSION;
462 } else {
463 /* We have a more recent version than caller.
464 Currently reject, but may in future be able
465 to be backwardly compatible */
466 return -EPROTO;
467 }
468 }
470 mutex_lock(&accelerator_mutex);
472 /*
473 * Look through list of accelerators to see if it has already
474 * been requested
475 */
476 list_for_each_entry(accelerator, &accelerators_list, link) {
477 if (match_accelerator(frontend, accelerator)) {
478 accelerator_probe_vifs(accelerator, hooks);
479 goto out;
480 }
481 }
483 /*
484 * If it wasn't in the list, add it now so that when it is
485 * requested the caller will find it
486 */
487 DPRINTK("Couldn't find matching accelerator (%s)\n",
488 frontend);
490 init_accelerator(frontend, &accelerator, hooks);
492 out:
493 mutex_unlock(&accelerator_mutex);
494 return 0;
495 }
496 EXPORT_SYMBOL_GPL(netfront_accelerator_loaded);
499 /*
500 * Remove the hooks from a single vif state.
501 *
502 * Takes the vif_states_lock spinlock and may sleep.
503 */
504 static void
505 accelerator_remove_single_hook(struct netfront_accelerator *accelerator,
506 struct netfront_accel_vif_state *vif_state)
507 {
508 unsigned long flags;
510 /* Make sure there are no data path operations going on */
511 netif_poll_disable(vif_state->np->netdev);
512 netif_tx_lock_bh(vif_state->np->netdev);
514 spin_lock_irqsave(&accelerator->vif_states_lock, flags);
516 /*
517 * Remove the hooks, but leave the vif_state on the
518 * accelerator's list as that signifies this vif is
519 * interested in using that accelerator if it becomes
520 * available again
521 */
522 vif_state->hooks = NULL;
524 spin_unlock_irqrestore(&accelerator->vif_states_lock, flags);
526 netif_tx_unlock_bh(vif_state->np->netdev);
527 netif_poll_enable(vif_state->np->netdev);
528 }
531 /*
532 * Safely remove the accelerator function hooks from a netfront state.
533 *
534 * Must be called with the accelerator mutex held. Takes the
535 * vif_states_lock spinlock.
536 */
537 static void accelerator_remove_hooks(struct netfront_accelerator *accelerator)
538 {
539 struct netfront_accel_vif_state *vif_state, *tmp;
540 unsigned long flags;
542 /* Mutex is held to iterate list */
543 list_for_each_entry_safe(vif_state, tmp,
544 &accelerator->vif_states,
545 link) {
546 if(vif_state->hooks) {
547 spin_lock_irqsave(&accelerator->vif_states_lock, flags);
549 /* Last chance to get statistics from the accelerator */
550 vif_state->hooks->get_stats(vif_state->np->netdev,
551 &vif_state->np->stats);
553 spin_unlock_irqrestore(&accelerator->vif_states_lock,
554 flags);
556 accelerator_remove_single_hook(accelerator, vif_state);
558 accelerator->hooks->remove(vif_state->dev);
559 }
560 }
562 accelerator->hooks = NULL;
563 }
566 /*
567 * Called by a netfront accelerator when it is unloaded. This safely
568 * removes the hooks into the plugin and blocks until all devices have
569 * finished using it, so on return it is safe to unload.
570 *
571 * Takes the accelerator mutex, and vif_states_lock spinlock.
572 */
573 void netfront_accelerator_stop(const char *frontend)
574 {
575 struct netfront_accelerator *accelerator;
577 mutex_lock(&accelerator_mutex);
579 list_for_each_entry(accelerator, &accelerators_list, link) {
580 if (match_accelerator(frontend, accelerator)) {
581 accelerator_remove_hooks(accelerator);
582 goto out;
583 }
584 }
585 out:
586 mutex_unlock(&accelerator_mutex);
587 }
588 EXPORT_SYMBOL_GPL(netfront_accelerator_stop);
591 /*
592 * Helper for call_remove and do_suspend
593 *
594 * Must be called with the accelerator mutex held. Takes the
595 * vif_states_lock spinlock.
596 */
597 static int do_remove(struct netfront_info *np, struct xenbus_device *dev)
598 {
599 struct netfront_accelerator *accelerator = np->accelerator;
600 unsigned long flags;
601 int rc = 0;
603 if (np->accel_vif_state.hooks) {
604 spin_lock_irqsave(&accelerator->vif_states_lock, flags);
606 /* Last chance to get statistics from the accelerator */
607 np->accel_vif_state.hooks->get_stats(np->netdev, &np->stats);
609 spin_unlock_irqrestore(&accelerator->vif_states_lock,
610 flags);
612 /*
613 * Try and do the opposite of accelerator_probe_new_vif
614 * to ensure there's no state pointing back at the
615 * netdev
616 */
617 accelerator_remove_single_hook(accelerator,
618 &np->accel_vif_state);
620 rc = accelerator->hooks->remove(dev);
621 }
623 return rc;
624 }
627 /*
628 * Must be called with the accelerator mutex held. Takes the
629 * vif_states_lock spinlock
630 */
631 static int netfront_remove_accelerator(struct netfront_info *np,
632 struct xenbus_device *dev)
633 {
634 struct netfront_accelerator *accelerator;
635 struct netfront_accel_vif_state *tmp_vif_state;
636 int rc = 0;
638 /* Check that we've got a device that was accelerated */
639 if (np->accelerator == NULL)
640 return rc;
642 accelerator = np->accelerator;
644 list_for_each_entry(tmp_vif_state, &accelerator->vif_states,
645 link) {
646 if (tmp_vif_state == &np->accel_vif_state) {
647 list_del(&np->accel_vif_state.link);
648 break;
649 }
650 }
652 rc = do_remove(np, dev);
654 np->accelerator = NULL;
656 return rc;
657 }
660 /*
661 * No lock pre-requisites. Takes the accelerator mutex and the
662 * vif_states_lock spinlock.
663 */
664 int netfront_accelerator_call_remove(struct netfront_info *np,
665 struct xenbus_device *dev)
666 {
667 int rc;
668 netfront_accelerator_remove_watch(np);
669 mutex_lock(&accelerator_mutex);
670 rc = netfront_remove_accelerator(np, dev);
671 mutex_unlock(&accelerator_mutex);
672 return rc;
673 }
676 /*
677 * No lock pre-requisites. Takes the accelerator mutex and the
678 * vif_states_lock spinlock.
679 */
680 int netfront_accelerator_suspend(struct netfront_info *np,
681 struct xenbus_device *dev)
682 {
683 int rc = 0;
685 mutex_lock(&accelerator_mutex);
687 /* Check that we've got a device that was accelerated */
688 if (np->accelerator == NULL)
689 goto out;
691 /*
692 * Call the remove accelerator hook, but leave the vif_state
693 * on the accelerator's list in case there is a suspend_cancel.
694 */
695 rc = do_remove(np, dev);
696 out:
697 mutex_unlock(&accelerator_mutex);
698 return rc;
699 }
702 int netfront_accelerator_suspend_cancel(struct netfront_info *np,
703 struct xenbus_device *dev)
704 {
705 netfront_accelerator_purge_watch(&np->accel_vif_state);
707 /*
708 * Gratuitously fire the watch handler to reinstate the
709 * configured accelerator
710 */
711 if (dev->state == XenbusStateConnected)
712 queue_work(accel_watch_workqueue,
713 &np->accel_vif_state.accel_work);
715 return 0;
716 }
719 /*
720 * No lock pre-requisites. Takes the accelerator mutex
721 */
722 void netfront_accelerator_resume(struct netfront_info *np,
723 struct xenbus_device *dev)
724 {
725 struct netfront_accel_vif_state *accel_vif_state = NULL;
727 mutex_lock(&accelerator_mutex);
729 /* Check that we've got a device that was accelerated */
730 if(np->accelerator == NULL)
731 goto out;
733 /* Find the vif_state from the accelerator's list */
734 list_for_each_entry(accel_vif_state, &np->accelerator->vif_states,
735 link) {
736 if (accel_vif_state->dev == dev) {
737 BUG_ON(accel_vif_state != &np->accel_vif_state);
739 /*
740 * Remove it from the accelerator's list so
741 * state is consistent for probing new vifs
742 * when they get connected
743 */
744 list_del(&accel_vif_state->link);
745 np->accelerator = NULL;
747 break;
748 }
749 }
751 out:
752 mutex_unlock(&accelerator_mutex);
753 return;
754 }
757 /*
758 * No lock pre-requisites. Takes the vif_states_lock spinlock
759 */
760 int netfront_check_accelerator_queue_ready(struct net_device *dev,
761 struct netfront_info *np)
762 {
763 struct netfront_accelerator *accelerator;
764 int rc = 1;
765 unsigned long flags;
767 accelerator = np->accelerator;
769 /* Call the check_ready accelerator hook. */
770 if (np->accel_vif_state.hooks && accelerator) {
771 spin_lock_irqsave(&accelerator->vif_states_lock, flags);
772 if (np->accel_vif_state.hooks &&
773 np->accelerator == accelerator)
774 rc = np->accel_vif_state.hooks->check_ready(dev);
775 spin_unlock_irqrestore(&accelerator->vif_states_lock, flags);
776 }
778 return rc;
779 }
782 /*
783 * No lock pre-requisites. Takes the vif_states_lock spinlock
784 */
785 void netfront_accelerator_call_stop_napi_irq(struct netfront_info *np,
786 struct net_device *dev)
787 {
788 struct netfront_accelerator *accelerator;
789 unsigned long flags;
791 accelerator = np->accelerator;
793 /* Call the stop_napi_interrupts accelerator hook. */
794 if (np->accel_vif_state.hooks && accelerator != NULL) {
795 spin_lock_irqsave(&accelerator->vif_states_lock, flags);
796 if (np->accel_vif_state.hooks &&
797 np->accelerator == accelerator)
798 np->accel_vif_state.hooks->stop_napi_irq(dev);
799 spin_unlock_irqrestore(&accelerator->vif_states_lock, flags);
800 }
801 }
804 /*
805 * No lock pre-requisites. Takes the vif_states_lock spinlock
806 */
807 int netfront_accelerator_call_get_stats(struct netfront_info *np,
808 struct net_device *dev)
809 {
810 struct netfront_accelerator *accelerator;
811 unsigned long flags;
812 int rc = 0;
814 accelerator = np->accelerator;
816 /* Call the get_stats accelerator hook. */
817 if (np->accel_vif_state.hooks && accelerator != NULL) {
818 spin_lock_irqsave(&accelerator->vif_states_lock, flags);
819 if (np->accel_vif_state.hooks &&
820 np->accelerator == accelerator)
821 rc = np->accel_vif_state.hooks->get_stats(dev,
822 &np->stats);
823 spin_unlock_irqrestore(&accelerator->vif_states_lock, flags);
824 }
825 return rc;
826 }