ia64/linux-2.6.18-xen.hg

changeset 370:41e34ec8d249

net accel: Allow network accelerators to deal with hot-plug/unplug on
physical devices. Add watch for acceleration configuration in frontend.

Signed-off-by: Kieran Mansley <kmansley@solarflare.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Dec 19 14:47:41 2007 +0000 (2007-12-19)
parents 7db9c653b4f9
children 06b826b4f71e
files drivers/xen/netback/accel.c drivers/xen/netback/common.h drivers/xen/netfront/accel.c drivers/xen/netfront/netfront.c drivers/xen/netfront/netfront.h
line diff
     1.1 --- a/drivers/xen/netback/accel.c	Mon Dec 17 13:41:07 2007 -0700
     1.2 +++ b/drivers/xen/netback/accel.c	Wed Dec 19 14:47:41 2007 +0000
     1.3 @@ -76,12 +76,27 @@ static int match_accelerator(struct xenb
     1.4  	}
     1.5  }
     1.6  
     1.7 +
     1.8 +static void do_probe(struct backend_info *be, 
     1.9 +		     struct netback_accelerator *accelerator,
    1.10 +		     struct xenbus_device *xendev) 
    1.11 +{
    1.12 +	be->accelerator = accelerator;
    1.13 +	atomic_inc(&be->accelerator->use_count);
    1.14 +	if (be->accelerator->hooks->probe(xendev) != 0) {
    1.15 +		atomic_dec(&be->accelerator->use_count);
    1.16 +		module_put(be->accelerator->hooks->owner);
    1.17 +		be->accelerator = NULL;
    1.18 +	}
    1.19 +}
    1.20 +
    1.21 +
    1.22  /*
    1.23 - * Notify all suitable backends that a new accelerator is available
    1.24 - * and connected.  This will also notify the accelerator plugin module
    1.25 + * Notify suitable backends that a new accelerator is available and
    1.26 + * connected.  This will also notify the accelerator plugin module
    1.27   * that it is being used for a device through the probe hook.
    1.28   */
    1.29 -static int netback_accelerator_tell_backend(struct device *dev, void *arg)
    1.30 +static int netback_accelerator_probe_backend(struct device *dev, void *arg)
    1.31  {
    1.32  	struct netback_accelerator *accelerator = 
    1.33  		(struct netback_accelerator *)arg;
    1.34 @@ -90,10 +105,9 @@ static int netback_accelerator_tell_back
    1.35  	if (!strcmp("vif", xendev->devicetype)) {
    1.36  		struct backend_info *be = xendev->dev.driver_data;
    1.37  
    1.38 -		if (match_accelerator(xendev, be, accelerator)) {
    1.39 -			be->accelerator = accelerator;
    1.40 -			atomic_inc(&be->accelerator->use_count);
    1.41 -			be->accelerator->hooks->probe(xendev);
    1.42 +		if (match_accelerator(xendev, be, accelerator) &&
    1.43 +		    try_module_get(accelerator->hooks->owner)) {
    1.44 +			do_probe(be, accelerator, xendev);
    1.45  		}
    1.46  	}
    1.47  	return 0;
    1.48 @@ -101,6 +115,30 @@ static int netback_accelerator_tell_back
    1.49  
    1.50  
    1.51  /*
    1.52 + * Notify suitable backends that an accelerator is unavailable.
    1.53 + */
    1.54 +static int netback_accelerator_remove_backend(struct device *dev, void *arg)
    1.55 +{
    1.56 +	struct xenbus_device *xendev = to_xenbus_device(dev);
    1.57 +	struct netback_accelerator *accelerator = 
    1.58 +		(struct netback_accelerator *)arg;
    1.59 +	
    1.60 +	if (!strcmp("vif", xendev->devicetype)) {
    1.61 +		struct backend_info *be = xendev->dev.driver_data;
    1.62 +
    1.63 +		if (be->accelerator == accelerator) {
    1.64 +			be->accelerator->hooks->remove(xendev);
    1.65 +			atomic_dec(&be->accelerator->use_count);
    1.66 +			module_put(be->accelerator->hooks->owner);
    1.67 +			be->accelerator = NULL;
    1.68 +		}
    1.69 +	}
    1.70 +	return 0;
    1.71 +}
    1.72 +
    1.73 +
    1.74 +
    1.75 +/*
    1.76   * Entry point for an netback accelerator plugin module.  Called to
    1.77   * advertise its presence, and connect to any suitable backends.
    1.78   */
    1.79 @@ -133,7 +171,6 @@ int netback_connect_accelerator(unsigned
    1.80  		return -ENOMEM;
    1.81  	}
    1.82  
    1.83 -
    1.84  	new_accelerator->id = id;
    1.85  	
    1.86  	eth_name_len = strlen(eth_name)+1;
    1.87 @@ -152,11 +189,12 @@ int netback_connect_accelerator(unsigned
    1.88  	
    1.89  	mutex_lock(&accelerators_mutex);
    1.90  	list_add(&new_accelerator->link, &accelerators_list);
    1.91 -	mutex_unlock(&accelerators_mutex);
    1.92  	
    1.93  	/* tell existing backends about new plugin */
    1.94  	xenbus_for_each_backend(new_accelerator, 
    1.95 -				netback_accelerator_tell_backend);
    1.96 +				netback_accelerator_probe_backend);
    1.97 +
    1.98 +	mutex_unlock(&accelerators_mutex);
    1.99  
   1.100  	return 0;
   1.101  
   1.102 @@ -165,31 +203,8 @@ EXPORT_SYMBOL_GPL(netback_connect_accele
   1.103  
   1.104  
   1.105  /* 
   1.106 - * Remove the link from backend state to a particular accelerator
   1.107 - */ 
   1.108 -static int netback_accelerator_cleanup_backend(struct device *dev, void *arg)
   1.109 -{
   1.110 -	struct netback_accelerator *accelerator = 
   1.111 -		(struct netback_accelerator *)arg;
   1.112 -	struct xenbus_device *xendev = to_xenbus_device(dev);
   1.113 -
   1.114 -	if (!strcmp("vif", xendev->devicetype)) {
   1.115 -		struct backend_info *be = xendev->dev.driver_data;
   1.116 -		if (be->accelerator == accelerator)
   1.117 -			be->accelerator = NULL;
   1.118 -	}
   1.119 -	return 0;
   1.120 -}
   1.121 -
   1.122 -
   1.123 -/* 
   1.124   * Disconnect an accelerator plugin module that has previously been
   1.125   * connected.
   1.126 - *
   1.127 - * This should only be allowed when there are no remaining users -
   1.128 - * i.e. it is not necessary to go through and clear all the hooks, as
   1.129 - * they should have already been removed.  This is enforced by taking
   1.130 - * a module reference to the plugin while the interfaces are in use
   1.131   */
   1.132  void netback_disconnect_accelerator(int id, const char *eth_name)
   1.133  {
   1.134 @@ -197,17 +212,14 @@ void netback_disconnect_accelerator(int 
   1.135  
   1.136  	mutex_lock(&accelerators_mutex);
   1.137  	list_for_each_entry_safe(accelerator, next, &accelerators_list, link) {
   1.138 -		if (strcmp(eth_name, accelerator->eth_name)) {
   1.139 +		if (!strcmp(eth_name, accelerator->eth_name)) {
   1.140 +			xenbus_for_each_backend
   1.141 +				(accelerator, netback_accelerator_remove_backend);
   1.142  			BUG_ON(atomic_read(&accelerator->use_count) != 0);
   1.143 -			list_del(&accelerator->link);
   1.144 -			mutex_unlock(&accelerators_mutex);
   1.145 -
   1.146 -			xenbus_for_each_backend(accelerator, 
   1.147 -						netback_accelerator_cleanup_backend);
   1.148 -				
   1.149 +			list_del(&accelerator->link);				
   1.150  			kfree(accelerator->eth_name);
   1.151  			kfree(accelerator);
   1.152 -			return;
   1.153 +			break;
   1.154  		}
   1.155  	}
   1.156  	mutex_unlock(&accelerators_mutex);
   1.157 @@ -228,9 +240,7 @@ void netback_probe_accelerators(struct b
   1.158  	list_for_each_entry(accelerator, &accelerators_list, link) { 
   1.159  		if (match_accelerator(dev, be, accelerator) &&
   1.160  		    try_module_get(accelerator->hooks->owner)) {
   1.161 -			be->accelerator = accelerator;
   1.162 -			atomic_inc(&be->accelerator->use_count);
   1.163 -			be->accelerator->hooks->probe(dev);
   1.164 +			do_probe(be, accelerator, dev);
   1.165  			break;
   1.166  		}
   1.167  	}
   1.168 @@ -241,13 +251,15 @@ void netback_probe_accelerators(struct b
   1.169  void netback_remove_accelerators(struct backend_info *be,
   1.170  				 struct xenbus_device *dev)
   1.171  {
   1.172 +	mutex_lock(&accelerators_mutex);
   1.173  	/* Notify the accelerator (if any) of this device's removal */
   1.174 -	if (be->accelerator) {
   1.175 +	if (be->accelerator != NULL) {
   1.176  		be->accelerator->hooks->remove(dev);
   1.177  		atomic_dec(&be->accelerator->use_count);
   1.178  		module_put(be->accelerator->hooks->owner);
   1.179 +		be->accelerator = NULL;
   1.180  	}
   1.181 -	be->accelerator = NULL;
   1.182 +	mutex_unlock(&accelerators_mutex);
   1.183  }
   1.184  
   1.185  
     2.1 --- a/drivers/xen/netback/common.h	Mon Dec 17 13:41:07 2007 -0700
     2.2 +++ b/drivers/xen/netback/common.h	Wed Dec 19 14:47:41 2007 +0000
     2.3 @@ -150,7 +150,7 @@ struct backend_info {
     2.4  	struct netback_accelerator *accelerator;
     2.5  };
     2.6  
     2.7 -#define NETBACK_ACCEL_VERSION 0x00010000
     2.8 +#define NETBACK_ACCEL_VERSION 0x00010001
     2.9  
    2.10  /* 
    2.11   * Connect an accelerator plugin module to netback.  Returns zero on
     3.1 --- a/drivers/xen/netfront/accel.c	Mon Dec 17 13:41:07 2007 -0700
     3.2 +++ b/drivers/xen/netfront/accel.c	Wed Dec 19 14:47:41 2007 +0000
     3.3 @@ -45,6 +45,12 @@
     3.4  #define WPRINTK(fmt, args...)				\
     3.5  	printk(KERN_WARNING "netfront/accel: " fmt, ##args)
     3.6  
     3.7 +static int netfront_remove_accelerator(struct netfront_info *np,
     3.8 +				       struct xenbus_device *dev);
     3.9 +static int netfront_load_accelerator(struct netfront_info *np, 
    3.10 +				     struct xenbus_device *dev, 
    3.11 +				     const char *frontend);
    3.12 +
    3.13  /*
    3.14   * List of all netfront accelerator plugin modules available.  Each
    3.15   * list entry is of type struct netfront_accelerator.
    3.16 @@ -83,6 +89,120 @@ void netif_exit_accel(void)
    3.17  
    3.18  
    3.19  /* 
    3.20 + * Watch the configured accelerator and change plugin if it's modified 
    3.21 + */
    3.22 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
    3.23 +static void accel_watch_work(struct work_struct *context)
    3.24 +#else
    3.25 +static void accel_watch_work(void *context)
    3.26 +#endif
    3.27 +{
    3.28 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
    3.29 +	struct netfront_accel_vif_state *vif_state = 
    3.30 +		container_of(context, struct netfront_accel_vif_state, 
    3.31 +			     accel_work);
    3.32 +#else
    3.33 +        struct netfront_accel_vif_state *vif_state = 
    3.34 +		(struct netfront_accel_vif_state *)context;
    3.35 +#endif
    3.36 +	struct netfront_info *np = vif_state->np;
    3.37 +	char *accel_frontend;
    3.38 +	int accel_len, rc = -1;
    3.39 +
    3.40 +	mutex_lock(&accelerator_mutex);
    3.41 +
    3.42 +	accel_frontend = xenbus_read(XBT_NIL, np->xbdev->otherend, 
    3.43 +				     "accel-frontend", &accel_len);
    3.44 +	if (IS_ERR(accel_frontend)) {
    3.45 +		accel_frontend = NULL;
    3.46 +		netfront_remove_accelerator(np, np->xbdev);
    3.47 +	} else {
    3.48 +		/* If this is the first time, request the accelerator,
    3.49 +		   otherwise only request one if it has changed */
    3.50 +		if (vif_state->accel_frontend == NULL) {
    3.51 +			rc = netfront_load_accelerator(np, np->xbdev, 
    3.52 +						       accel_frontend);
    3.53 +		} else {
    3.54 +			if (strncmp(vif_state->accel_frontend, accel_frontend,
    3.55 +				    accel_len)) {
    3.56 +				netfront_remove_accelerator(np, np->xbdev);
    3.57 +				rc = netfront_load_accelerator(np, np->xbdev, 
    3.58 +							       accel_frontend);
    3.59 +			}
    3.60 +		}
    3.61 +	}
    3.62 +
    3.63 +	/* Get rid of previous state and replace with the new name */
    3.64 +	if (vif_state->accel_frontend != NULL)
    3.65 +		kfree(vif_state->accel_frontend);
    3.66 +	vif_state->accel_frontend = accel_frontend;
    3.67 +
    3.68 +	mutex_unlock(&accelerator_mutex);
    3.69 +
    3.70 +	if (rc == 0) {
    3.71 +		DPRINTK("requesting module %s\n", accel_frontend);
    3.72 +		request_module("%s", accel_frontend);
    3.73 +		/*
    3.74 +		 * Module should now call netfront_accelerator_loaded() once
    3.75 +		 * it's up and running, and we can continue from there 
    3.76 +		 */
    3.77 +	}
    3.78 +}
    3.79 +
    3.80 +
    3.81 +static void accel_watch_changed(struct xenbus_watch *watch,
    3.82 +				const char **vec, unsigned int len)
    3.83 +{
    3.84 +	struct netfront_accel_vif_state *vif_state = 
    3.85 +		container_of(watch, struct netfront_accel_vif_state,
    3.86 +			     accel_watch);
    3.87 +	schedule_work(&vif_state->accel_work);
    3.88 +}
    3.89 +
    3.90 +
    3.91 +void netfront_accelerator_add_watch(struct netfront_info *np)
    3.92 +{
    3.93 +	int err;
    3.94 +	
    3.95 +	/* Check we're not trying to overwrite an existing watch */
    3.96 +	BUG_ON(np->accel_vif_state.accel_watch.node != NULL);
    3.97 +
    3.98 +	/* Get a watch on the accelerator plugin */
    3.99 +	err = xenbus_watch_path2(np->xbdev, np->xbdev->otherend, 
   3.100 +				 "accel-frontend", 
   3.101 +				 &np->accel_vif_state.accel_watch,
   3.102 +				 accel_watch_changed);
   3.103 +	if (err) {
   3.104 +		DPRINTK("%s: Failed to register accel watch: %d\n",
   3.105 +                        __FUNCTION__, err);
   3.106 +		np->accel_vif_state.accel_watch.node = NULL;
   3.107 +        }
   3.108 +}
   3.109 +
   3.110 +
   3.111 +static
   3.112 +void netfront_accelerator_remove_watch(struct netfront_info *np)
   3.113 +{
   3.114 +	struct netfront_accel_vif_state *vif_state = &np->accel_vif_state;
   3.115 +
   3.116 +	/* Get rid of watch on accelerator plugin */
   3.117 +	if (vif_state->accel_watch.node != NULL) {
   3.118 +		unregister_xenbus_watch(&vif_state->accel_watch);
   3.119 +		kfree(vif_state->accel_watch.node);
   3.120 +		vif_state->accel_watch.node = NULL;
   3.121 +
   3.122 +		flush_scheduled_work();
   3.123 +
   3.124 +		/* Clean up any state left from watch */
   3.125 +		if (vif_state->accel_frontend != NULL) {
   3.126 +			kfree(vif_state->accel_frontend);
   3.127 +			vif_state->accel_frontend = NULL;
   3.128 +		}
   3.129 +	}	
   3.130 +}
   3.131 +
   3.132 +
   3.133 +/* 
   3.134   * Initialise the accel_vif_state field in the netfront state
   3.135   */ 
   3.136  void init_accelerator_vif(struct netfront_info *np,
   3.137 @@ -93,6 +213,13 @@ void init_accelerator_vif(struct netfron
   3.138  	/* It's assumed that these things don't change */
   3.139  	np->accel_vif_state.np = np;
   3.140  	np->accel_vif_state.dev = dev;
   3.141 +
   3.142 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
   3.143 +	INIT_WORK(&np->accel_vif_state.accel_work, accel_watch_work);
   3.144 +#else
   3.145 +	INIT_WORK(&np->accel_vif_state.accel_work, accel_watch_work, 
   3.146 +		  &np->accel_vif_state);
   3.147 +#endif
   3.148  }
   3.149  
   3.150  
   3.151 @@ -202,6 +329,7 @@ static void accelerator_probe_new_vif(st
   3.152  				      struct netfront_accelerator *accelerator)
   3.153  {
   3.154  	struct netfront_accel_hooks *hooks;
   3.155 +	unsigned long flags;
   3.156  
   3.157  	DPRINTK("\n");
   3.158  
   3.159 @@ -211,24 +339,29 @@ static void accelerator_probe_new_vif(st
   3.160  	hooks = accelerator->hooks;
   3.161  	
   3.162  	if (hooks) {
   3.163 -		hooks->new_device(np->netdev, dev);
   3.164 -		/* 
   3.165 -		 * Hooks will get linked into vif_state by a future
   3.166 -		 * call by the accelerator to netfront_accelerator_ready()
   3.167 -		 */
   3.168 +		if (hooks->new_device(np->netdev, dev) == 0) {
   3.169 +			spin_lock_irqsave
   3.170 +				(&accelerator->vif_states_lock, flags);
   3.171 +
   3.172 +			accelerator_set_vif_state_hooks(&np->accel_vif_state);
   3.173 +
   3.174 +			spin_unlock_irqrestore
   3.175 +				(&accelerator->vif_states_lock, flags);
   3.176 +		}
   3.177  	}
   3.178  
   3.179  	return;
   3.180  }
   3.181  
   3.182 +
   3.183  /*  
   3.184   * Request that a particular netfront accelerator plugin is loaded.
   3.185   * Usually called as a result of the vif configuration specifying
   3.186 - * which one to use.
   3.187 + * which one to use. Must be called with accelerator_mutex held 
   3.188   */
   3.189 -int netfront_load_accelerator(struct netfront_info *np, 
   3.190 -			      struct xenbus_device *dev, 
   3.191 -			      const char *frontend)
   3.192 +static int netfront_load_accelerator(struct netfront_info *np, 
   3.193 +				     struct xenbus_device *dev, 
   3.194 +				     const char *frontend)
   3.195  {
   3.196  	struct netfront_accelerator *accelerator;
   3.197  	int rc = 0;
   3.198 @@ -236,8 +369,6 @@ int netfront_load_accelerator(struct net
   3.199  
   3.200  	DPRINTK(" %s\n", frontend);
   3.201  
   3.202 -	mutex_lock(&accelerator_mutex);
   3.203 -
   3.204  	spin_lock_irqsave(&accelerators_lock, flags);
   3.205  
   3.206  	/* 
   3.207 @@ -249,8 +380,6 @@ int netfront_load_accelerator(struct net
   3.208  			spin_unlock_irqrestore(&accelerators_lock, flags);
   3.209  
   3.210  			accelerator_probe_new_vif(np, dev, accelerator);
   3.211 -
   3.212 -			mutex_unlock(&accelerator_mutex);
   3.213  			return 0;
   3.214  		}
   3.215  	}
   3.216 @@ -258,7 +387,6 @@ int netfront_load_accelerator(struct net
   3.217  	/* Couldn't find it, so create a new one and load the module */
   3.218  	if ((rc = init_accelerator(frontend, &accelerator, NULL)) < 0) {
   3.219  		spin_unlock_irqrestore(&accelerators_lock, flags);
   3.220 -		mutex_unlock(&accelerator_mutex);
   3.221  		return rc;
   3.222  	}
   3.223  
   3.224 @@ -267,18 +395,6 @@ int netfront_load_accelerator(struct net
   3.225  	/* Include this frontend device on the accelerator's list */
   3.226  	add_accelerator_vif(accelerator, np);
   3.227  
   3.228 -	mutex_unlock(&accelerator_mutex);
   3.229 -
   3.230 -	DPRINTK("requesting module %s\n", frontend);
   3.231 -
   3.232 -	/* load module */
   3.233 -	request_module("%s", frontend);
   3.234 -
   3.235 -	/*
   3.236 -	 * Module should now call netfront_accelerator_loaded() once
   3.237 -	 * it's up and running, and we can continue from there 
   3.238 -	 */
   3.239 -
   3.240  	return rc;
   3.241  }
   3.242  
   3.243 @@ -294,6 +410,7 @@ accelerator_probe_vifs(struct netfront_a
   3.244  		       struct netfront_accel_hooks *hooks)
   3.245  {
   3.246  	struct netfront_accel_vif_state *vif_state, *tmp;
   3.247 +	unsigned long flags;
   3.248  
   3.249  	DPRINTK("%p\n", accelerator);
   3.250  
   3.251 @@ -313,13 +430,15 @@ accelerator_probe_vifs(struct netfront_a
   3.252  				 link) {
   3.253  		struct netfront_info *np = vif_state->np;
   3.254  		
   3.255 -		hooks->new_device(np->netdev, vif_state->dev);
   3.256 -		
   3.257 -		/*
   3.258 -		 * Hooks will get linked into vif_state by a call to
   3.259 -		 * netfront_accelerator_ready() once accelerator
   3.260 -		 * plugin is ready for action
   3.261 -		 */
   3.262 +		if (hooks->new_device(np->netdev, vif_state->dev) == 0) {
   3.263 +			spin_lock_irqsave
   3.264 +				(&accelerator->vif_states_lock, flags);
   3.265 +
   3.266 +			accelerator_set_vif_state_hooks(vif_state);
   3.267 +
   3.268 +			spin_unlock_irqrestore
   3.269 +				(&accelerator->vif_states_lock, flags);
   3.270 +		}
   3.271  	}
   3.272  }
   3.273  
   3.274 @@ -385,48 +504,6 @@ EXPORT_SYMBOL_GPL(netfront_accelerator_l
   3.275  
   3.276  
   3.277  /* 
   3.278 - * Called by the accelerator module after it has been probed with a
   3.279 - * network device to say that it is ready to start accelerating
   3.280 - * traffic on that device
   3.281 - */
   3.282 -void netfront_accelerator_ready(const char *frontend,
   3.283 -				struct xenbus_device *dev)
   3.284 -{
   3.285 -	struct netfront_accelerator *accelerator;
   3.286 -	struct netfront_accel_vif_state *accel_vif_state;
   3.287 -	unsigned long flags, flags1;
   3.288 -
   3.289 -	DPRINTK("%s %p\n", frontend, dev);
   3.290 -
   3.291 -	spin_lock_irqsave(&accelerators_lock, flags);
   3.292 -
   3.293 -	list_for_each_entry(accelerator, &accelerators_list, link) {
   3.294 -		if (match_accelerator(frontend, accelerator)) {
   3.295 -			/* 
   3.296 -			 * Mutex not held so need vif_states_lock for
   3.297 -			 * list
   3.298 -			 */
   3.299 -			spin_lock_irqsave
   3.300 -				(&accelerator->vif_states_lock, flags1);
   3.301 -
   3.302 -			list_for_each_entry(accel_vif_state,
   3.303 -					    &accelerator->vif_states, link) {
   3.304 -				if (accel_vif_state->dev == dev)
   3.305 -					accelerator_set_vif_state_hooks
   3.306 -						(accel_vif_state);
   3.307 -			}
   3.308 -
   3.309 -			spin_unlock_irqrestore
   3.310 -				(&accelerator->vif_states_lock, flags1);
   3.311 -			break;
   3.312 -		}
   3.313 -	}
   3.314 -	spin_unlock_irqrestore(&accelerators_lock, flags);
   3.315 -}
   3.316 -EXPORT_SYMBOL_GPL(netfront_accelerator_ready);
   3.317 -
   3.318 -
   3.319 -/* 
   3.320   * Remove the hooks from a single vif state.
   3.321   */
   3.322  static void 
   3.323 @@ -467,16 +544,21 @@ static void accelerator_remove_hooks(str
   3.324  
   3.325  		if(vif_state->hooks) {
   3.326  			hooks = vif_state->hooks;
   3.327 -			accelerator_remove_single_hook(accelerator, vif_state);
   3.328  			
   3.329  			/* Last chance to get statistics from the accelerator */
   3.330  			hooks->get_stats(vif_state->np->netdev,
   3.331  					 &vif_state->np->stats);
   3.332 -		}
   3.333  
   3.334 -		spin_unlock_irqrestore(&accelerator->vif_states_lock, flags);
   3.335 +			spin_unlock_irqrestore(&accelerator->vif_states_lock,
   3.336 +					       flags);
   3.337  
   3.338 -		accelerator->hooks->remove(vif_state->dev);
   3.339 +			accelerator_remove_single_hook(accelerator, vif_state);
   3.340 +
   3.341 +			accelerator->hooks->remove(vif_state->dev);
   3.342 +		} else {
   3.343 +			spin_unlock_irqrestore(&accelerator->vif_states_lock,
   3.344 +					       flags);
   3.345 +		}
   3.346  	}
   3.347  	
   3.348  	accelerator->hooks = NULL;
   3.349 @@ -523,6 +605,12 @@ static int do_remove(struct netfront_inf
   3.350  	if (np->accel_vif_state.hooks) {
   3.351  		hooks = np->accel_vif_state.hooks;
   3.352  
   3.353 +		/* Last chance to get statistics from the accelerator */
   3.354 +		hooks->get_stats(np->netdev, &np->stats);
   3.355 +
   3.356 +		spin_unlock_irqrestore(&accelerator->vif_states_lock, 
   3.357 +				       *lock_flags);
   3.358 +
   3.359   		/* 
   3.360   		 * Try and do the opposite of accelerator_probe_new_vif
   3.361   		 * to ensure there's no state pointing back at the 
   3.362 @@ -531,14 +619,6 @@ static int do_remove(struct netfront_inf
   3.363  		accelerator_remove_single_hook(accelerator, 
   3.364   					       &np->accel_vif_state);
   3.365  
   3.366 -		/* Last chance to get statistics from the accelerator */
   3.367 -		hooks->get_stats(np->netdev, &np->stats);
   3.368 -	}
   3.369 -
   3.370 -	if (accelerator->hooks) {
   3.371 -		spin_unlock_irqrestore(&accelerator->vif_states_lock, 
   3.372 -				       *lock_flags);
   3.373 -
   3.374  		rc = accelerator->hooks->remove(dev);
   3.375  
   3.376  		spin_lock_irqsave(&accelerator->vif_states_lock, *lock_flags);
   3.377 @@ -546,21 +626,19 @@ static int do_remove(struct netfront_inf
   3.378   
   3.379   	return rc;
   3.380  }
   3.381 - 
   3.382 -  
   3.383 -int netfront_accelerator_call_remove(struct netfront_info *np,
   3.384 - 				     struct xenbus_device *dev)
   3.385 +
   3.386 +
   3.387 +static int netfront_remove_accelerator(struct netfront_info *np,
   3.388 +				       struct xenbus_device *dev)
   3.389  {
   3.390  	struct netfront_accelerator *accelerator;
   3.391   	struct netfront_accel_vif_state *tmp_vif_state;
   3.392    	unsigned long flags;
   3.393  	int rc = 0; 
   3.394  
   3.395 -	mutex_lock(&accelerator_mutex);
   3.396 -
   3.397   	/* Check that we've got a device that was accelerated */
   3.398   	if (np->accelerator == NULL)
   3.399 -		goto out;
   3.400 +		return rc;
   3.401  
   3.402  	accelerator = np->accelerator;
   3.403  
   3.404 @@ -579,17 +657,30 @@ int netfront_accelerator_call_remove(str
   3.405  	np->accelerator = NULL;
   3.406  
   3.407  	spin_unlock_irqrestore(&accelerator->vif_states_lock, flags); 
   3.408 - out:
   3.409 +
   3.410 +	return rc;
   3.411 +}
   3.412 +
   3.413 +
   3.414 +int netfront_accelerator_call_remove(struct netfront_info *np,
   3.415 +				     struct xenbus_device *dev)
   3.416 +{
   3.417 +	int rc;
   3.418 +	netfront_accelerator_remove_watch(np);
   3.419 +	mutex_lock(&accelerator_mutex);
   3.420 +	rc = netfront_remove_accelerator(np, dev);
   3.421  	mutex_unlock(&accelerator_mutex);
   3.422  	return rc;
   3.423  }
   3.424 -  
   3.425 +
   3.426    
   3.427  int netfront_accelerator_suspend(struct netfront_info *np,
   3.428   				 struct xenbus_device *dev)
   3.429  {
   3.430  	unsigned long flags;
   3.431  	int rc = 0;
   3.432 +	
   3.433 +	netfront_accelerator_remove_watch(np);
   3.434  
   3.435  	mutex_lock(&accelerator_mutex);
   3.436  
   3.437 @@ -641,6 +732,7 @@ int netfront_accelerator_suspend_cancel(
   3.438   	
   3.439   out:
   3.440  	mutex_unlock(&accelerator_mutex);
   3.441 +	netfront_accelerator_add_watch(np);
   3.442   	return 0;
   3.443  }
   3.444   
     4.1 --- a/drivers/xen/netfront/netfront.c	Mon Dec 17 13:41:07 2007 -0700
     4.2 +++ b/drivers/xen/netfront/netfront.c	Wed Dec 19 14:47:41 2007 +0000
     4.3 @@ -378,6 +378,10 @@ static int talk_to_backend(struct xenbus
     4.4  	if (err)
     4.5  		goto out;
     4.6  
     4.7 +	/* This will load an accelerator if one is configured when the
     4.8 +	 * watch fires */
     4.9 +	netfront_accelerator_add_watch(info);
    4.10 +
    4.11  again:
    4.12  	err = xenbus_transaction_start(&xbt);
    4.13  	if (err) {
    4.14 @@ -452,6 +456,7 @@ again:
    4.15  	xenbus_transaction_end(xbt, 1);
    4.16  	xenbus_dev_fatal(dev, err, "%s", message);
    4.17   destroy_ring:
    4.18 +	netfront_accelerator_call_remove(info, dev);
    4.19  	netif_disconnect_backend(info);
    4.20   out:
    4.21  	return err;
    4.22 @@ -1746,9 +1751,7 @@ static int network_connect(struct net_de
    4.23  	struct sk_buff *skb;
    4.24  	grant_ref_t ref;
    4.25  	netif_rx_request_t *req;
    4.26 -	unsigned int feature_rx_copy, feature_rx_flip, feature_accel;
    4.27 -	char *accel_frontend;
    4.28 -	int accel_len;
    4.29 +	unsigned int feature_rx_copy, feature_rx_flip;
    4.30  
    4.31  	err = xenbus_scanf(XBT_NIL, np->xbdev->otherend,
    4.32  			   "feature-rx-copy", "%u", &feature_rx_copy);
    4.33 @@ -1759,12 +1762,6 @@ static int network_connect(struct net_de
    4.34  	if (err != 1)
    4.35  		feature_rx_flip = 1;
    4.36  
    4.37 -	feature_accel = 1;
    4.38 -	accel_frontend = xenbus_read(XBT_NIL, np->xbdev->otherend, 
    4.39 -				     "accel-frontend", &accel_len);
    4.40 -	if (IS_ERR(accel_frontend)) 
    4.41 -		feature_accel = 0;
    4.42 -
    4.43  	/*
    4.44  	 * Copy packets on receive path if:
    4.45  	 *  (a) This was requested by user, and the backend supports it; or
    4.46 @@ -1777,11 +1774,6 @@ static int network_connect(struct net_de
    4.47  	if (err)
    4.48  		return err;
    4.49  
    4.50 -	if (feature_accel) {
    4.51 -		netfront_load_accelerator(np, np->xbdev, accel_frontend);
    4.52 -		kfree(accel_frontend);
    4.53 -	}
    4.54 -
    4.55  	xennet_set_features(dev);
    4.56  
    4.57  	DPRINTK("device %s has %sing receive path.\n",
     5.1 --- a/drivers/xen/netfront/netfront.h	Mon Dec 17 13:41:07 2007 -0700
     5.2 +++ b/drivers/xen/netfront/netfront.h	Wed Dec 19 14:47:41 2007 +0000
     5.3 @@ -95,7 +95,7 @@ struct netfront_accel_hooks {
     5.4  
     5.5  /* Version of API/protocol for communication between netfront and
     5.6     acceleration plugin supported */
     5.7 -#define NETFRONT_ACCEL_VERSION 0x00010002
     5.8 +#define NETFRONT_ACCEL_VERSION 0x00010003
     5.9  
    5.10  /* 
    5.11   * Per-netfront device state for the accelerator.  This is used to
    5.12 @@ -108,6 +108,13 @@ struct netfront_accel_vif_state {
    5.13  	struct xenbus_device *dev;
    5.14  	struct netfront_info *np;
    5.15  	struct netfront_accel_hooks *hooks;
    5.16 +
    5.17 +	/* Watch on the accelerator configuration value */
    5.18 +	struct xenbus_watch accel_watch;
    5.19 +	/* Work item to process change in accelerator */
    5.20 +	struct work_struct accel_work;
    5.21 +	/* The string from xenbus last time accel_watch fired */
    5.22 +	char *accel_frontend;
    5.23  }; 
    5.24  
    5.25  /* 
    5.26 @@ -210,18 +217,6 @@ extern int netfront_accelerator_loaded(i
    5.27  				       struct netfront_accel_hooks *hooks);
    5.28  
    5.29  /* 
    5.30 - * Called when an accelerator plugin is ready to accelerate a device *
    5.31 - * that has been passed to it from netfront using the "new_device"
    5.32 - * hook.
    5.33 - *
    5.34 - * frontend: the string describing the accelerator. Must match the
    5.35 - * one passed to netfront_accelerator_loaded()
    5.36 - * dev: the xenbus device the plugin was asked to accelerate
    5.37 - */
    5.38 -extern void netfront_accelerator_ready(const char *frontend,
    5.39 -				       struct xenbus_device *dev);
    5.40 -
    5.41 -/* 
    5.42   * Called by an accelerator plugin module when it is about to unload.
    5.43   *
    5.44   * frontend: the string describing the accelerator.  Must match the
    5.45 @@ -237,7 +232,6 @@ extern void netfront_accelerator_stop(co
    5.46  extern int netfront_check_queue_ready(struct net_device *net_dev);
    5.47  
    5.48  
    5.49 -
    5.50  /* Internal-to-netfront Functions */
    5.51  
    5.52  /* 
    5.53 @@ -267,9 +261,7 @@ extern
    5.54  int netfront_accelerator_call_get_stats(struct netfront_info *np,
    5.55  					struct net_device *dev);
    5.56  extern
    5.57 -int netfront_load_accelerator(struct netfront_info *np, 
    5.58 -			      struct xenbus_device *dev, 
    5.59 -			      const char *frontend);
    5.60 +void netfront_accelerator_add_watch(struct netfront_info *np);
    5.61  
    5.62  extern
    5.63  void netif_init_accel(void);