list_add(&np->accel_vif_state.link, &accelerator->vif_states);
} else {
/*
- * May get here legitimately if reconnecting to the
- * same accelerator, eg. after resume, so check that
- * is the case
+ * May get here legitimately if suspend_cancel is
+ * called, but in that case configuration should not
+ * have changed
*/
BUG_ON(np->accelerator != accelerator);
}
static void
accelerator_probe_vifs(struct netfront_accelerator *accelerator,
struct netfront_accel_hooks *hooks,
- unsigned lock_flags)
+ unsigned *lock_flags)
{
struct netfront_accel_vif_state *vif_state, *tmp;
* protected by the kref
*/
spin_unlock_irqrestore(&accelerator->vif_states_lock,
- lock_flags);
+ (*lock_flags));
hooks->new_device(np->netdev, vif_state->dev);
kref_put(&accelerator->accel_kref, accel_kref_release);
/* Retake lock for next go round the loop */
- spin_lock_irqsave(&accelerator->vif_states_lock, lock_flags);
+ spin_lock_irqsave(&accelerator->vif_states_lock,
+ (*lock_flags));
/*
* Hooks will get linked into vif_state by a call to
if (accelerator->ready_for_probe) {
accelerator->ready_for_probe = 0;
- accelerator_probe_vifs(accelerator, hooks, flags);
+ accelerator_probe_vifs(accelerator, hooks, &flags);
} else {
if (accelerator->need_probe)
DPRINTK("Probe request on accelerator awaiting probe\n");
/*
* Safely remove the accelerator function hooks from a netfront state.
*/
-static void accelerator_remove_hooks(struct netfront_accelerator *accelerator,
- int remove_master)
+static void accelerator_remove_hooks(struct netfront_accelerator *accelerator)
{
struct netfront_accel_hooks *hooks;
struct netfront_accel_vif_state *vif_state, *tmp;
list_for_each_entry_safe(vif_state, tmp,
&accelerator->vif_states,
link) {
+ BUG_ON(vif_state->hooks == NULL);
hooks = vif_state->hooks;
accelerator_remove_single_hook(accelerator, vif_state);
- /*
- * Remove the reference taken when the vif_state hooks
- * were set, must be called without lock held
- */
+ /*
+ * Tell accelerator that this device is being removed,
+ * and remove the reference taken when the vif_state
+ * hooks were set; both must be called without lock
+ * held
+ */
spin_unlock_irqrestore(&accelerator->vif_states_lock, flags);
/* Last chance to get statistics from the accelerator */
hooks->get_stats(vif_state->np->netdev, &vif_state->np->stats);
+ hooks->remove(vif_state->dev);
kref_put(&vif_state->vif_kref, vif_kref_release);
spin_lock_irqsave(&accelerator->vif_states_lock, flags);
}
- if(remove_master)
- accelerator->hooks = NULL;
+ accelerator->hooks = NULL;
spin_unlock_irqrestore(&accelerator->vif_states_lock, flags);
- if(remove_master)
- /* Remove the reference taken when module loaded */
- kref_put(&accelerator->accel_kref, accel_kref_release);
+ /* Remove the reference taken when module loaded */
+ kref_put(&accelerator->accel_kref, accel_kref_release);
}
* removes the hooks into the plugin and blocks until all devices have
* finished using it, so on return it is safe to unload.
*/
-void netfront_accelerator_stop(const char *frontend, int unloading)
+void netfront_accelerator_stop(const char *frontend)
{
struct netfront_accelerator *accelerator;
unsigned flags;
*/
sema_init(&accelerator->exit_semaphore, 0);
- accelerator_remove_hooks(accelerator, unloading);
+ accelerator_remove_hooks(accelerator);
- if (unloading)
- /* Wait for hooks to be unused, then return */
- down(&accelerator->exit_semaphore);
+ /* Wait for hooks to be unused, then return */
+ down(&accelerator->exit_semaphore);
return;
}
int netfront_check_accelerator_queue_busy(struct net_device *dev,
struct netfront_info *np)
{
+ struct netfront_accelerator *accelerator;
struct netfront_accel_hooks *hooks;
int rc = 1;
unsigned flags;
+ accelerator = np->accelerator;
+
/*
* Call the check busy accelerator hook. The use count for the
* accelerator's hooks is incremented for the duration of the
* call to prevent the accelerator being able to modify the
* hooks in the middle (by, for example, unloading)
*/
- if (np->accel_vif_state.hooks) {
- spin_lock_irqsave(&np->accelerator->vif_states_lock, flags);
+ if (np->accel_vif_state.hooks && accelerator) {
+ spin_lock_irqsave(&accelerator->vif_states_lock, flags);
hooks = np->accel_vif_state.hooks;
- if (hooks) {
+ if (hooks && np->accelerator == accelerator) {
kref_get(&np->accel_vif_state.vif_kref);
spin_unlock_irqrestore
- (&np->accelerator->vif_states_lock, flags);
+ (&accelerator->vif_states_lock, flags);
rc = np->accel_vif_state.hooks->check_busy(dev);
vif_kref_release);
} else {
spin_unlock_irqrestore
- (&np->accelerator->vif_states_lock, flags);
+ (&accelerator->vif_states_lock, flags);
}
}
}
-int netfront_accelerator_call_remove(struct netfront_info *np,
- struct xenbus_device *dev)
+/* Helper for call_remove and do_suspend */
+static int do_remove(struct netfront_info *np, struct xenbus_device *dev,
+ unsigned lock_flags, int clear_accelerator)
{
struct netfront_accelerator *accelerator = np->accelerator;
- struct netfront_accel_vif_state *tmp_vif_state;
- struct netfront_accel_hooks *hooks;
+ struct netfront_accel_hooks *hooks;
unsigned flags;
- int rc = 0;
-
- /*
- * Call the remove accelerator hook. The use count for the
- * accelerator's hooks is incremented for the duration of the
- * call to prevent the accelerator being able to modify the
- * hooks in the middle (by, for example, unloading)
- */
- spin_lock_irqsave(&np->accelerator->vif_states_lock, flags);
- hooks = np->accel_vif_state.hooks;
+ int rc = 0;
+
+ if(clear_accelerator)
+ np->accelerator = NULL;
- /*
- * Remove this vif_state from the accelerator's list
- */
- list_for_each_entry(tmp_vif_state, &accelerator->vif_states, link) {
- if (tmp_vif_state == &np->accel_vif_state) {
- list_del(&np->accel_vif_state.link);
- break;
- }
- }
-
- if (hooks) {
- kref_get(&np->accel_vif_state.vif_kref);
- spin_unlock_irqrestore
- (&np->accelerator->vif_states_lock, flags);
- /* Last chance to get statistics from the accelerator */
- vif_state->hooks->get_stats(np->netdev, &np->stats);
- rc = np->accel_vif_state.hooks->remove(dev);
-
- kref_put(&np->accel_vif_state.vif_kref,
- vif_kref_release);
-
- spin_lock_irqsave(&np->accelerator->vif_states_lock,
- flags);
+ if (np->accel_vif_state.hooks) {
+ hooks = np->accel_vif_state.hooks;
- /*
- * Try and do the opposite of accelerator_probe_new_vif
- * to ensure there's no state pointing back at the
- * netdev
- */
+ /*
+ * Try and do the opposite of accelerator_probe_new_vif
+ * to ensure there's no state pointing back at the
+ * netdev
+ */
accelerator_remove_single_hook(accelerator,
- &np->accel_vif_state);
-
+ &np->accel_vif_state);
+
+ spin_unlock_irqrestore(&accelerator->vif_states_lock,
+ lock_flags);
+
/*
- * Remove the reference taken when the vif_state hooks
- * were set, must be called without lock held
- */
- spin_unlock_irqrestore(&accelerator->vif_states_lock,
- flags);
- kref_put(&np->accel_vif_state.vif_kref,
- vif_kref_release);
+ * No need to do kref_get before calling these hooks as we
+ * can borrow the one we have to drop after this call
+ */
+
+ /* Last chance to get statistics from the accelerator */
+ hooks->get_stats(np->netdev, &np->stats);
+
+ rc = hooks->remove(dev);
+
+ /*
+ * Remove the reference taken when the vif_state hooks
+ * were set, must be called without lock held
+ */
+ kref_put(&np->accel_vif_state.vif_kref, vif_kref_release);
} else {
- spin_unlock_irqrestore(&np->accelerator->vif_states_lock,
- flags);
+ spin_unlock_irqrestore(&accelerator->vif_states_lock,
+ lock_flags);
}
- return rc;
+
+ return rc;
}
-
-
-int netfront_accelerator_call_suspend(struct netfront_info *np,
- struct xenbus_device *dev)
+
+
+int netfront_accelerator_call_remove(struct netfront_info *np,
+ struct xenbus_device *dev)
{
- struct netfront_accel_hooks *hooks;
- unsigned flags;
- int rc = 0;
-
- IPRINTK("netfront_accelerator_call_suspend\n");
+ struct netfront_accel_vif_state *tmp_vif_state;
+ unsigned flags;
- /*
- * Call the suspend accelerator hook. The use count for the
- * accelerator's hooks is incremented for the duration of
- * the call to prevent the accelerator being able to modify
- * the hooks in the middle (by, for example, unloading)
- */
- if (np->accel_vif_state.hooks) {
- spin_lock_irqsave(&np->accelerator->vif_states_lock, flags);
- hooks = np->accel_vif_state.hooks;
- if (hooks) {
- kref_get(&np->accel_vif_state.vif_kref);
- spin_unlock_irqrestore
- (&np->accelerator->vif_states_lock, flags);
+ /* Check that we've got a device that was accelerated */
+ if (np->accelerator == NULL)
+ return 0;
- /* Last chance to get stats from the accelerator */
- np->accel_vif_state.hooks->get_stats(dev, &np->stats);
-
- rc = np->accel_vif_state.hooks->suspend(dev);
+ spin_lock_irqsave(&np->accelerator->vif_states_lock, flags);
- kref_put(&np->accel_vif_state.vif_kref,
- vif_kref_release);
- } else {
- spin_unlock_irqrestore
- (&np->accelerator->vif_states_lock, flags);
+ list_for_each_entry(tmp_vif_state, &np->accelerator->vif_states,
+ link) {
+ if (tmp_vif_state == &np->accel_vif_state) {
+ list_del(&np->accel_vif_state.link);
+ break;
}
}
- return rc;
-}
-
-int netfront_accelerator_call_suspend_cancel(struct netfront_info *np,
- struct xenbus_device *dev)
+ /* do_remove drops the lock for us */
+ return do_remove(np, dev, flags, 1);
+}
+
+
+int netfront_accelerator_suspend(struct netfront_info *np,
+ struct xenbus_device *dev)
{
- struct netfront_accel_hooks *hooks;
unsigned flags;
- int rc = 0;
- IPRINTK(" netfront_accelerator_call_suspend_cancel\n");
+
+ /* Check that we've got a device that was accelerated */
+ if (np->accelerator == NULL)
+ return 0;
/*
- * Call the suspend_cancel accelerator hook. The use count
- * for the accelerator's hooks is incremented for the
- * duration of the call to prevent the accelerator being able
- * to modify the hooks in the middle (by, for example,
- * unloading)
+ * Call the remove accelerator hook, but leave the vif_state
+ * on the accelerator's list in case there is a suspend_cancel.
*/
- if (np->accel_vif_state.hooks) {
- spin_lock_irqsave(&np->accelerator->vif_states_lock, flags);
- hooks = np->accel_vif_state.hooks;
- if (hooks) {
- kref_get(&np->accel_vif_state.vif_kref);
- spin_unlock_irqrestore
- (&np->accelerator->vif_states_lock, flags);
-
- rc = np->accel_vif_state.hooks->suspend_cancel(dev);
-
- kref_put(&np->accel_vif_state.vif_kref,
- vif_kref_release);
- } else {
- spin_unlock_irqrestore
- (&np->accelerator->vif_states_lock, flags);
- }
- }
- return rc;
+ spin_lock_irqsave(&np->accelerator->vif_states_lock,
+ flags);
+
+ /* do_remove drops the lock for us */
+ return do_remove(np, dev, flags, 0);
}
-
-
-int netfront_accelerator_call_resume(struct netfront_info *np,
- struct xenbus_device *dev)
+
+
+int netfront_accelerator_suspend_cancel(struct netfront_info *np,
+ struct xenbus_device *dev)
{
- struct netfront_accel_hooks *hooks;
- unsigned flags;
- int rc = 0;
-
- /*
- * Call the resume accelerator hook. The use count for the
- * accelerator's hooks is incremented for the duration of
- * the call to prevent the accelerator being able to modify
- * the hooks in the middle (by, for example, unloading)
- */
- if (np->accel_vif_state.hooks) {
- spin_lock_irqsave(&np->accelerator->vif_states_lock, flags);
- hooks = np->accel_vif_state.hooks;
- if (hooks) {
- kref_get(&np->accel_vif_state.vif_kref);
- spin_unlock_irqrestore
- (&np->accelerator->vif_states_lock, flags);
-
- rc = np->accel_vif_state.hooks->resume(dev);
-
- kref_put(&np->accel_vif_state.vif_kref,
- vif_kref_release);
- } else {
- spin_unlock_irqrestore
- (&np->accelerator->vif_states_lock, flags);
- }
- }
- return rc;
+ struct netfront_accel_vif_state *accel_vif_state = NULL;
+ unsigned flags1, flags2;
+
+ /* Check that we've got a device that was accelerated */
+ if (np->accelerator == NULL)
+ return 0;
+
+ spin_lock_irqsave(&np->accelerator->vif_states_lock, flags);
+ /* Find the vif_state from the accelerator's list */
+ list_for_each_entry(accel_vif_state, &np->accelerator->vif_states,
+ link) {
+ if (accel_vif_state->dev == dev) {
+ BUG_ON(accel_vif_state != &np->accel_vif_state);
+
+ spin_unlock_irqrestore(&np->accelerator->vif_states_lock,
+ flags);
+
+ /*
+ * Kick things off again to restore
+ * acceleration as it was before suspend
+ */
+ accelerator_probe_new_vif(np, dev, np->accelerator);
+
+ return 0;
+ }
+ }
+
+ spin_unlock_irqrestore(&np->accelerator->vif_states_lock, flags);
+
+ return 0;
+}
+
+
+void netfront_accelerator_resume(struct netfront_info *np,
+ struct xenbus_device *dev)
+{
+ struct netfront_accel_vif_state *accel_vif_state = NULL;
+ spinlock_t *vif_states_lock;
+ unsigned flags;
+
+ /* Check that we've got a device that was accelerated */
+ if(np->accelerator == NULL)
+ return;
+
+ spin_lock_irqsave(&np->accelerator->vif_states_lock, flags);
+
+ /* Find the vif_state from the accelerator's list */
+ list_for_each_entry(accel_vif_state, &np->accelerator->vif_states,
+ link) {
+ if (accel_vif_state->dev == dev) {
+ BUG_ON(accel_vif_state != &np->accel_vif_state);
+
+ /*
+ * Remove it from the accelerator's list so
+ * state is consistent for probing new vifs
+ * when they get connected
+ */
+ list_del(&accel_vif_state->link);
+ vif_states_lock = &np->accelerator->vif_states_lock;
+ np->accelerator = NULL;
+
+ spin_unlock_irqrestore(vif_states_lock, flags);
+
+ return;
+ }
+ }
+ spin_unlock_irqrestore(&np->accelerator->vif_states_lock, flags);
}
void netfront_accelerator_call_stop_napi_irq(struct netfront_info *np,
struct net_device *dev)
{
+ struct netfront_accelerator *accelerator;
struct netfront_accel_hooks *hooks;
unsigned flags;
+ accelerator = np->accelerator;
+
/*
* Call the stop_napi_interrupts accelerator hook. The use
* count for the accelerator's hooks is incremented for the
* unloading)
*/
- if (np->accel_vif_state.hooks) {
- spin_lock_irqsave(&np->accelerator->vif_states_lock, flags);
+ if (np->accel_vif_state.hooks && accelerator != NULL) {
+ spin_lock_irqsave(&accelerator->vif_states_lock, flags);
hooks = np->accel_vif_state.hooks;
- if (hooks) {
+ if (hooks && np->accelerator == accelerator) {
kref_get(&np->accel_vif_state.vif_kref);
spin_unlock_irqrestore
- (&np->accelerator->vif_states_lock, flags);
+ (&accelerator->vif_states_lock, flags);
np->accel_vif_state.hooks->stop_napi_irq(dev);
vif_kref_release);
} else {
spin_unlock_irqrestore
- (&np->accelerator->vif_states_lock, flags);
+ (&accelerator->vif_states_lock, flags);
}
}
}
int netfront_accelerator_call_get_stats(struct netfront_info *np,
struct net_device *dev)
{
+ struct netfront_accelerator *accelerator;
struct netfront_accel_hooks *hooks;
unsigned flags;
int rc = 0;
+ accelerator = np->accelerator;
+
/*
* Call the get_stats accelerator hook. The use count for the
* accelerator's hooks is incremented for the duration of the
* hooks in the middle (by, for example, unloading)
*/
- if (np->accel_vif_state.hooks) {
- spin_lock_irqsave(&np->accelerator->vif_states_lock, flags);
+ if (np->accel_vif_state.hooks && accelerator != NULL) {
+ spin_lock_irqsave(accelerator->vif_states_lock, flags);
hooks = np->accel_vif_state.hooks;
- if (hooks) {
+ if (hooks && np->accelerator == accelerator) {
kref_get(&np->accel_vif_state.vif_kref);
spin_unlock_irqrestore
- (&np->accelerator->vif_states_lock, flags);
+ (&accelerator->vif_states_lock, flags);
rc = np->accel_vif_state.hooks->get_stats(dev,
&np->stats);
vif_kref_release);
} else {
spin_unlock_irqrestore
- (&np->accelerator->vif_states_lock, flags);
+ (&accelerator->vif_states_lock, flags);
}
}
return rc;
if (accelerator->need_probe) {
hooks = accelerator->need_probe;
accelerator->need_probe = NULL;
- accelerator_probe_vifs(accelerator, hooks, flags);
+ accelerator_probe_vifs(accelerator, hooks, &flags);
}
else
accelerator->ready_for_probe = 1;