Update to 3.4-final.
[linux-flexiantxendom0-3.2.10.git] / drivers / xen / netfront / accel.c
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  */
30
31 #include <linux/version.h>
32 #include <linux/netdevice.h>
33 #include <linux/skbuff.h>
34 #include <linux/list.h>
35 #include <linux/module.h>
36 #include <linux/mutex.h>
37 #include <asm/hypervisor.h>
38 #include <xen/xenbus.h>
39
40 #include "netfront.h"
41
42 #define DPRINTK(fmt, args...)                           \
43         pr_debug("netfront/accel (%s:%d) " fmt,         \
44                __FUNCTION__, __LINE__, ##args)
45 #define IPRINTK(fmt, args...) pr_info("netfront/accel: " fmt, ##args)
46 #define WPRINTK(fmt, args...) pr_warning("netfront/accel: " fmt, ##args)
47
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);
53
54 static void netfront_accelerator_remove_watch(struct netfront_info *np);
55
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;
61
62 /* Workqueue to process acceleration configuration changes */
63 struct workqueue_struct *accel_watch_workqueue;
64
65 /* Mutex to prevent concurrent loads and suspends, etc. */
66 DEFINE_MUTEX(accelerator_mutex);
67
68 void netif_init_accel(void)
69 {
70         INIT_LIST_HEAD(&accelerators_list);
71
72         accel_watch_workqueue = create_workqueue("net_accel");
73 }
74
75 void netif_exit_accel(void)
76 {
77         struct netfront_accelerator *accelerator, *tmp;
78
79         flush_workqueue(accel_watch_workqueue);
80         destroy_workqueue(accel_watch_workqueue);
81
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));
85
86                 list_del(&accelerator->link);
87                 kfree(accelerator->frontend);
88                 kfree(accelerator);
89         }
90 }
91
92
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;
113
114         mutex_lock(&accelerator_mutex);
115
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         }
136
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;
141
142         mutex_unlock(&accelerator_mutex);
143
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 }
153
154
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 }
163
164
165 void netfront_accelerator_add_watch(struct netfront_info *np)
166 {
167         int err;
168         
169         /* 
170          * If old watch exists, e.g. from before suspend/resume,
171          * remove it now 
172          */
173         netfront_accelerator_remove_watch(np);
174
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 }
186
187
188 static void 
189 netfront_accelerator_purge_watch(struct netfront_accel_vif_state *vif_state)
190 {
191         flush_workqueue(accel_watch_workqueue);
192
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 }
199
200
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;
205
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;
211
212                 netfront_accelerator_purge_watch(vif_state);
213         }       
214 }
215
216
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;
224
225         /* It's assumed that these things don't change */
226         np->accel_vif_state.np = np;
227         np->accel_vif_state.dev = dev;
228
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 }
236
237
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 }
248
249
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;
260                 
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 }
271
272
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;
285
286         if (!accelerator) {
287                 DPRINTK("no memory for accelerator\n");
288                 return -ENOMEM;
289         }
290
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);
299         
300         INIT_LIST_HEAD(&accelerator->vif_states);
301         spin_lock_init(&accelerator->vif_states_lock);
302
303         accelerator->hooks = hooks;
304
305         list_add(&accelerator->link, &accelerators_list);
306
307         *result = accelerator;
308
309         return 0;
310 }                                       
311
312
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;
324
325         DPRINTK("%p\n",vif_state);
326
327         /* Make sure there are no data path operations going on */
328         napi_disable(&vif_state->np->napi);
329         netif_tx_lock_bh(vif_state->np->netdev);
330
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);
335
336         netif_tx_unlock_bh(vif_state->np->netdev);
337         napi_enable(&vif_state->np->napi);
338 }
339
340
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;
350
351         DPRINTK("\n");
352
353         /* Include this frontend device on the accelerator's list */
354         add_accelerator_vif(accelerator, np);
355         
356         hooks = accelerator->hooks;
357         
358         if (hooks && hooks->new_device(np->netdev, dev) == 0)
359                 accelerator_set_vif_state_hooks(&np->accel_vif_state);
360
361         return;
362 }
363
364
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;
379
380         DPRINTK(" %s\n", frontend);
381
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         }
392
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         }
397
398         /* Include this frontend device on the accelerator's list */
399         add_accelerator_vif(accelerator, np);
400
401         return rc;
402 }
403
404
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;
419
420         DPRINTK("%p\n", accelerator);
421
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;
429
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;
434                 
435                 if (hooks->new_device(np->netdev, vif_state->dev) == 0)
436                         accelerator_set_vif_state_hooks(vif_state);
437         }
438 }
439
440
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;
451
452         if (is_initial_xendomain())
453                 return -EINVAL;
454
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         }
469
470         mutex_lock(&accelerator_mutex);
471
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         }
482
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);
489
490         init_accelerator(frontend, &accelerator, hooks);
491
492  out:
493         mutex_unlock(&accelerator_mutex);
494         return 0;
495 }
496 EXPORT_SYMBOL_GPL(netfront_accelerator_loaded);
497
498
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;
509
510         /* Make sure there are no data path operations going on */
511         napi_disable(&vif_state->np->napi);
512         netif_tx_lock_bh(vif_state->np->netdev);
513
514         spin_lock_irqsave(&accelerator->vif_states_lock, flags);
515
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;
523         
524         spin_unlock_irqrestore(&accelerator->vif_states_lock, flags);
525
526         netif_tx_unlock_bh(vif_state->np->netdev);
527         napi_enable(&vif_state->np->napi);
528 }
529
530
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;
541
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);
548
549                         /* Last chance to get statistics from the accelerator */
550                         vif_state->hooks->get_stats(vif_state->np->netdev,
551                                                     &vif_state->np->netdev->stats,
552                                                     this_cpu_ptr(vif_state->np->stats));
553
554                         spin_unlock_irqrestore(&accelerator->vif_states_lock,
555                                                flags);
556
557                         accelerator_remove_single_hook(accelerator, vif_state);
558
559                         accelerator->hooks->remove(vif_state->dev);
560                 }
561         }
562         
563         accelerator->hooks = NULL;
564 }
565
566
567 /* 
568  * Called by a netfront accelerator when it is unloaded.  This safely
569  * removes the hooks into the plugin and blocks until all devices have
570  * finished using it, so on return it is safe to unload.
571  *
572  * Takes the accelerator mutex, and vif_states_lock spinlock.
573  */
574 void netfront_accelerator_stop(const char *frontend)
575 {
576         struct netfront_accelerator *accelerator;
577
578         mutex_lock(&accelerator_mutex);
579
580         list_for_each_entry(accelerator, &accelerators_list, link) {
581                 if (match_accelerator(frontend, accelerator)) {
582                         accelerator_remove_hooks(accelerator);
583                         goto out;
584                 }
585         }
586  out:
587         mutex_unlock(&accelerator_mutex);
588 }
589 EXPORT_SYMBOL_GPL(netfront_accelerator_stop);
590
591
592 /* 
593  * Helper for call_remove and do_suspend
594  * 
595  * Must be called with the accelerator mutex held.  Takes the
596  * vif_states_lock spinlock.
597  */
598 static int do_remove(struct netfront_info *np, struct xenbus_device *dev)
599 {
600         struct netfront_accelerator *accelerator = np->accelerator;
601         unsigned long flags;
602         int rc = 0;
603  
604         if (np->accel_vif_state.hooks) {
605                 spin_lock_irqsave(&accelerator->vif_states_lock, flags);
606
607                 /* Last chance to get statistics from the accelerator */
608                 np->accel_vif_state.hooks->get_stats(np->netdev,
609                                                      &np->netdev->stats,
610                                                      this_cpu_ptr(np->stats));
611
612                 spin_unlock_irqrestore(&accelerator->vif_states_lock, 
613                                        flags);
614
615                 /* 
616                  * Try and do the opposite of accelerator_probe_new_vif
617                  * to ensure there's no state pointing back at the 
618                  * netdev 
619                  */
620                 accelerator_remove_single_hook(accelerator, 
621                                                &np->accel_vif_state);
622
623                 rc = accelerator->hooks->remove(dev);
624         }
625  
626         return rc;
627 }
628
629
630 /*
631  * Must be called with the accelerator mutex held.  Takes the
632  * vif_states_lock spinlock
633  */
634 static int netfront_remove_accelerator(struct netfront_info *np,
635                                        struct xenbus_device *dev)
636 {
637         struct netfront_accelerator *accelerator;
638         struct netfront_accel_vif_state *tmp_vif_state;
639         int rc = 0; 
640
641         /* Check that we've got a device that was accelerated */
642         if (np->accelerator == NULL)
643                 return rc;
644
645         accelerator = np->accelerator;
646
647         list_for_each_entry(tmp_vif_state, &accelerator->vif_states,
648                             link) {
649                 if (tmp_vif_state == &np->accel_vif_state) {
650                         list_del(&np->accel_vif_state.link);
651                         break;
652                 }
653         }
654
655         rc = do_remove(np, dev);
656
657         np->accelerator = NULL;
658
659         return rc;
660 }
661
662
663 /*
664  * No lock pre-requisites.  Takes the accelerator mutex and the
665  * vif_states_lock spinlock.
666  */
667 int netfront_accelerator_call_remove(struct netfront_info *np,
668                                      struct xenbus_device *dev)
669 {
670         int rc;
671         netfront_accelerator_remove_watch(np);
672         mutex_lock(&accelerator_mutex);
673         rc = netfront_remove_accelerator(np, dev);
674         mutex_unlock(&accelerator_mutex);
675         return rc;
676 }
677
678
679 /*
680  * No lock pre-requisites.  Takes the accelerator mutex and the
681  * vif_states_lock spinlock.
682  */
683 int netfront_accelerator_suspend(struct netfront_info *np,
684                                  struct xenbus_device *dev)
685 {
686         int rc = 0;
687         
688         mutex_lock(&accelerator_mutex);
689
690         /* Check that we've got a device that was accelerated */
691         if (np->accelerator == NULL)
692                 goto out;
693
694         /* 
695          * Call the remove accelerator hook, but leave the vif_state
696          * on the accelerator's list in case there is a suspend_cancel.
697          */
698         rc = do_remove(np, dev);
699  out:
700         mutex_unlock(&accelerator_mutex);
701         return rc;
702 }
703   
704   
705 int netfront_accelerator_suspend_cancel(struct netfront_info *np,
706                                         struct xenbus_device *dev)
707 {
708         netfront_accelerator_purge_watch(&np->accel_vif_state);
709
710         /* 
711          * Gratuitously fire the watch handler to reinstate the
712          * configured accelerator
713          */
714         if (dev->state == XenbusStateConnected)
715                 queue_work(accel_watch_workqueue, 
716                            &np->accel_vif_state.accel_work);
717
718         return 0;
719 }
720
721
722 /*
723  * No lock pre-requisites.  Takes the accelerator mutex
724  */
725 void netfront_accelerator_resume(struct netfront_info *np,
726                                  struct xenbus_device *dev)
727 {
728         struct netfront_accel_vif_state *accel_vif_state = NULL;
729
730         mutex_lock(&accelerator_mutex);
731
732         /* Check that we've got a device that was accelerated */
733         if(np->accelerator == NULL)
734                 goto out;
735
736         /* Find the vif_state from the accelerator's list */
737         list_for_each_entry(accel_vif_state, &np->accelerator->vif_states, 
738                             link) {
739                 if (accel_vif_state->dev == dev) {
740                         BUG_ON(accel_vif_state != &np->accel_vif_state);
741  
742                         /* 
743                          * Remove it from the accelerator's list so
744                          * state is consistent for probing new vifs
745                          * when they get connected
746                          */
747                         list_del(&accel_vif_state->link);
748                         np->accelerator = NULL;
749
750                         break;
751                 }
752         }
753
754  out:
755         mutex_unlock(&accelerator_mutex);
756         return;
757 }
758
759
760 /*
761  * No lock pre-requisites.  Takes the vif_states_lock spinlock
762  */
763 int netfront_check_accelerator_queue_ready(struct net_device *dev,
764                                            struct netfront_info *np)
765 {
766         struct netfront_accelerator *accelerator;
767         int rc = 1;
768         unsigned long flags;
769
770         accelerator = np->accelerator;
771
772         /* Call the check_ready accelerator hook. */ 
773         if (np->accel_vif_state.hooks && accelerator) {
774                 spin_lock_irqsave(&accelerator->vif_states_lock, flags); 
775                 if (np->accel_vif_state.hooks &&
776                     np->accelerator == accelerator)
777                         rc = np->accel_vif_state.hooks->check_ready(dev);
778                 spin_unlock_irqrestore(&accelerator->vif_states_lock, flags);
779         }
780
781         return rc;
782 }
783
784
785 /*
786  * No lock pre-requisites.  Takes the vif_states_lock spinlock
787  */
788 void netfront_accelerator_call_stop_napi_irq(struct netfront_info *np,
789                                              struct net_device *dev)
790 {
791         struct netfront_accelerator *accelerator;
792         unsigned long flags;
793
794         accelerator = np->accelerator;
795
796         /* Call the stop_napi_interrupts accelerator hook. */
797         if (np->accel_vif_state.hooks && accelerator != NULL) {
798                 spin_lock_irqsave(&accelerator->vif_states_lock, flags); 
799                 if (np->accel_vif_state.hooks &&
800                     np->accelerator == accelerator)
801                         np->accel_vif_state.hooks->stop_napi_irq(dev);
802                 spin_unlock_irqrestore(&accelerator->vif_states_lock, flags);
803         }
804 }
805
806
807 /*
808  * No lock pre-requisites.  Takes the vif_states_lock spinlock
809  */
810 int netfront_accelerator_call_get_stats(struct netfront_info *np,
811                                         struct net_device *dev)
812 {
813         struct netfront_accelerator *accelerator;
814         unsigned long flags;
815         int rc = 0;
816
817         accelerator = np->accelerator;
818
819         /* Call the get_stats accelerator hook. */
820         if (np->accel_vif_state.hooks && accelerator != NULL) {
821                 spin_lock_irqsave(&accelerator->vif_states_lock, flags); 
822                 if (np->accel_vif_state.hooks && 
823                     np->accelerator == accelerator)
824                         rc = np->accel_vif_state.hooks->get_stats(dev, &dev->stats,
825                                                                   this_cpu_ptr(np->stats));
826                 spin_unlock_irqrestore(&accelerator->vif_states_lock, flags);
827         }
828         return rc;
829 }
830