Blame view

drivers/virtio/virtio.c 10.3 KB
ec3d41c4d   Rusty Russell   Virtio interface
1
2
3
  #include <linux/virtio.h>
  #include <linux/spinlock.h>
  #include <linux/virtio_config.h>
b5a2c4f19   Paul Gortmaker   virtio: Add modul...
4
  #include <linux/module.h>
90e03207f   Asias He   virtio: Use ida t...
5
  #include <linux/idr.h>
b6098c304   Michael S. Tsirkin   virtio: add API t...
6
  #include <uapi/linux/virtio_ids.h>
ec3d41c4d   Rusty Russell   Virtio interface
7

b769f5790   Rusty Russell   virtio: set devic...
8
  /* Unique numbering for virtio devices. */
90e03207f   Asias He   virtio: Use ida t...
9
  static DEFINE_IDA(virtio_index_ida);
b769f5790   Rusty Russell   virtio: set devic...
10

ec3d41c4d   Rusty Russell   Virtio interface
11
12
13
  static ssize_t device_show(struct device *_d,
  			   struct device_attribute *attr, char *buf)
  {
9bffdca8c   Wanlong Gao   virtio: use dev_t...
14
  	struct virtio_device *dev = dev_to_virtio(_d);
be6528b2e   Stephen Hemminger   virtio: fix forma...
15
16
  	return sprintf(buf, "0x%04x
  ", dev->id.device);
ec3d41c4d   Rusty Russell   Virtio interface
17
  }
3736dab6e   Greg Kroah-Hartman   virtio: convert b...
18
  static DEVICE_ATTR_RO(device);
ec3d41c4d   Rusty Russell   Virtio interface
19
20
21
  static ssize_t vendor_show(struct device *_d,
  			   struct device_attribute *attr, char *buf)
  {
9bffdca8c   Wanlong Gao   virtio: use dev_t...
22
  	struct virtio_device *dev = dev_to_virtio(_d);
be6528b2e   Stephen Hemminger   virtio: fix forma...
23
24
  	return sprintf(buf, "0x%04x
  ", dev->id.vendor);
ec3d41c4d   Rusty Russell   Virtio interface
25
  }
3736dab6e   Greg Kroah-Hartman   virtio: convert b...
26
  static DEVICE_ATTR_RO(vendor);
ec3d41c4d   Rusty Russell   Virtio interface
27
28
29
  static ssize_t status_show(struct device *_d,
  			   struct device_attribute *attr, char *buf)
  {
9bffdca8c   Wanlong Gao   virtio: use dev_t...
30
  	struct virtio_device *dev = dev_to_virtio(_d);
be6528b2e   Stephen Hemminger   virtio: fix forma...
31
32
  	return sprintf(buf, "0x%08x
  ", dev->config->get_status(dev));
ec3d41c4d   Rusty Russell   Virtio interface
33
  }
3736dab6e   Greg Kroah-Hartman   virtio: convert b...
34
  static DEVICE_ATTR_RO(status);
b01d9f286   Rusty Russell   Module autoprobin...
35
36
37
  static ssize_t modalias_show(struct device *_d,
  			     struct device_attribute *attr, char *buf)
  {
9bffdca8c   Wanlong Gao   virtio: use dev_t...
38
  	struct virtio_device *dev = dev_to_virtio(_d);
b01d9f286   Rusty Russell   Module autoprobin...
39
40
41
42
  	return sprintf(buf, "virtio:d%08Xv%08X
  ",
  		       dev->id.device, dev->id.vendor);
  }
3736dab6e   Greg Kroah-Hartman   virtio: convert b...
43
  static DEVICE_ATTR_RO(modalias);
a92892825   Rusty Russell   virtio: expose fe...
44
45
46
  static ssize_t features_show(struct device *_d,
  			     struct device_attribute *attr, char *buf)
  {
9bffdca8c   Wanlong Gao   virtio: use dev_t...
47
  	struct virtio_device *dev = dev_to_virtio(_d);
a92892825   Rusty Russell   virtio: expose fe...
48
49
50
51
52
  	unsigned int i;
  	ssize_t len = 0;
  
  	/* We actually represent this as a bitstring, as it could be
  	 * arbitrary length in future. */
e16e12be3   Michael S. Tsirkin   virtio: use u32, ...
53
  	for (i = 0; i < sizeof(dev->features)*8; i++)
a92892825   Rusty Russell   virtio: expose fe...
54
  		len += sprintf(buf+len, "%c",
e16e12be3   Michael S. Tsirkin   virtio: use u32, ...
55
  			       __virtio_test_bit(dev, i) ? '1' : '0');
a92892825   Rusty Russell   virtio: expose fe...
56
57
58
59
  	len += sprintf(buf+len, "
  ");
  	return len;
  }
3736dab6e   Greg Kroah-Hartman   virtio: convert b...
60
61
62
63
64
65
66
67
68
  static DEVICE_ATTR_RO(features);
  
  static struct attribute *virtio_dev_attrs[] = {
  	&dev_attr_device.attr,
  	&dev_attr_vendor.attr,
  	&dev_attr_status.attr,
  	&dev_attr_modalias.attr,
  	&dev_attr_features.attr,
  	NULL,
ec3d41c4d   Rusty Russell   Virtio interface
69
  };
3736dab6e   Greg Kroah-Hartman   virtio: convert b...
70
  ATTRIBUTE_GROUPS(virtio_dev);
ec3d41c4d   Rusty Russell   Virtio interface
71
72
73
74
  
  static inline int virtio_id_match(const struct virtio_device *dev,
  				  const struct virtio_device_id *id)
  {
e33538537   Christian Borntraeger   virtio: enhance i...
75
  	if (id->device != dev->id.device && id->device != VIRTIO_DEV_ANY_ID)
ec3d41c4d   Rusty Russell   Virtio interface
76
  		return 0;
c89e80168   Christian Borntraeger   virtio: fix id_ma...
77
  	return id->vendor == VIRTIO_DEV_ANY_ID || id->vendor == dev->id.vendor;
ec3d41c4d   Rusty Russell   Virtio interface
78
79
80
81
82
83
84
  }
  
  /* This looks through all the IDs a driver claims to support.  If any of them
   * match, we return 1 and the kernel will call virtio_dev_probe(). */
  static int virtio_dev_match(struct device *_dv, struct device_driver *_dr)
  {
  	unsigned int i;
9bffdca8c   Wanlong Gao   virtio: use dev_t...
85
  	struct virtio_device *dev = dev_to_virtio(_dv);
ec3d41c4d   Rusty Russell   Virtio interface
86
  	const struct virtio_device_id *ids;
9a2bdcc85   Wanlong Gao   virtio: add drv_t...
87
  	ids = drv_to_virtio(_dr)->id_table;
ec3d41c4d   Rusty Russell   Virtio interface
88
89
90
91
92
  	for (i = 0; ids[i].device; i++)
  		if (virtio_id_match(dev, &ids[i]))
  			return 1;
  	return 0;
  }
b01d9f286   Rusty Russell   Module autoprobin...
93
94
  static int virtio_uevent(struct device *_dv, struct kobj_uevent_env *env)
  {
9bffdca8c   Wanlong Gao   virtio: use dev_t...
95
  	struct virtio_device *dev = dev_to_virtio(_dv);
b01d9f286   Rusty Russell   Module autoprobin...
96
97
98
99
  
  	return add_uevent_var(env, "MODALIAS=virtio:d%08Xv%08X",
  			      dev->id.device, dev->id.vendor);
  }
ec3d41c4d   Rusty Russell   Virtio interface
100
101
102
103
  static void add_status(struct virtio_device *dev, unsigned status)
  {
  	dev->config->set_status(dev, dev->config->get_status(dev) | status);
  }
c45a6816c   Rusty Russell   virtio: explicit ...
104
105
106
107
  void virtio_check_driver_offered_feature(const struct virtio_device *vdev,
  					 unsigned int fbit)
  {
  	unsigned int i;
9a2bdcc85   Wanlong Gao   virtio: add drv_t...
108
  	struct virtio_driver *drv = drv_to_virtio(vdev->dev.driver);
c45a6816c   Rusty Russell   virtio: explicit ...
109
110
111
112
  
  	for (i = 0; i < drv->feature_table_size; i++)
  		if (drv->feature_table[i] == fbit)
  			return;
b3bb62d11   Michael S. Tsirkin   virtio: add legac...
113
114
115
116
117
118
  
  	if (drv->feature_table_legacy) {
  		for (i = 0; i < drv->feature_table_size_legacy; i++)
  			if (drv->feature_table_legacy[i] == fbit)
  				return;
  	}
c45a6816c   Rusty Russell   virtio: explicit ...
119
120
121
  	BUG();
  }
  EXPORT_SYMBOL_GPL(virtio_check_driver_offered_feature);
22b7050a0   Michael S. Tsirkin   virtio: defer con...
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
  static void __virtio_config_changed(struct virtio_device *dev)
  {
  	struct virtio_driver *drv = drv_to_virtio(dev->dev.driver);
  
  	if (!dev->config_enabled)
  		dev->config_change_pending = true;
  	else if (drv && drv->config_changed)
  		drv->config_changed(dev);
  }
  
  void virtio_config_changed(struct virtio_device *dev)
  {
  	unsigned long flags;
  
  	spin_lock_irqsave(&dev->config_lock, flags);
  	__virtio_config_changed(dev);
  	spin_unlock_irqrestore(&dev->config_lock, flags);
  }
  EXPORT_SYMBOL_GPL(virtio_config_changed);
  
  static void virtio_config_disable(struct virtio_device *dev)
  {
  	spin_lock_irq(&dev->config_lock);
  	dev->config_enabled = false;
  	spin_unlock_irq(&dev->config_lock);
  }
  
  static void virtio_config_enable(struct virtio_device *dev)
  {
  	spin_lock_irq(&dev->config_lock);
  	dev->config_enabled = true;
  	if (dev->config_change_pending)
  		__virtio_config_changed(dev);
  	dev->config_change_pending = false;
  	spin_unlock_irq(&dev->config_lock);
  }
30683a8cc   Michael S. Tsirkin   virtio: set VIRTI...
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
  static int virtio_finalize_features(struct virtio_device *dev)
  {
  	int ret = dev->config->finalize_features(dev);
  	unsigned status;
  
  	if (ret)
  		return ret;
  
  	if (!virtio_has_feature(dev, VIRTIO_F_VERSION_1))
  		return 0;
  
  	add_status(dev, VIRTIO_CONFIG_S_FEATURES_OK);
  	status = dev->config->get_status(dev);
  	if (!(status & VIRTIO_CONFIG_S_FEATURES_OK)) {
  		dev_err(&dev->dev, "virtio: device refuses features: %x
  ",
  			status);
  		return -ENODEV;
  	}
  	return 0;
  }
ec3d41c4d   Rusty Russell   Virtio interface
179
180
  static int virtio_dev_probe(struct device *_d)
  {
c45a6816c   Rusty Russell   virtio: explicit ...
181
  	int err, i;
9bffdca8c   Wanlong Gao   virtio: use dev_t...
182
  	struct virtio_device *dev = dev_to_virtio(_d);
9a2bdcc85   Wanlong Gao   virtio: add drv_t...
183
  	struct virtio_driver *drv = drv_to_virtio(dev->dev.driver);
d02547736   Michael S. Tsirkin   virtio: add suppo...
184
  	u64 device_features;
c102659d6   Michael S. Tsirkin   virtio: simplify ...
185
  	u64 driver_features;
b3bb62d11   Michael S. Tsirkin   virtio: add legac...
186
  	u64 driver_features_legacy;
ec3d41c4d   Rusty Russell   Virtio interface
187

c45a6816c   Rusty Russell   virtio: explicit ...
188
  	/* We have a driver! */
ec3d41c4d   Rusty Russell   Virtio interface
189
  	add_status(dev, VIRTIO_CONFIG_S_DRIVER);
c45a6816c   Rusty Russell   virtio: explicit ...
190
191
192
  
  	/* Figure out what features the device supports. */
  	device_features = dev->config->get_features(dev);
c102659d6   Michael S. Tsirkin   virtio: simplify ...
193
194
  	/* Figure out what features the driver supports. */
  	driver_features = 0;
c45a6816c   Rusty Russell   virtio: explicit ...
195
196
  	for (i = 0; i < drv->feature_table_size; i++) {
  		unsigned int f = drv->feature_table[i];
d02547736   Michael S. Tsirkin   virtio: add suppo...
197
  		BUG_ON(f >= 64);
c102659d6   Michael S. Tsirkin   virtio: simplify ...
198
  		driver_features |= (1ULL << f);
c45a6816c   Rusty Russell   virtio: explicit ...
199
  	}
b3bb62d11   Michael S. Tsirkin   virtio: add legac...
200
201
202
203
204
205
206
207
208
209
210
  	/* Some drivers have a separate feature table for virtio v1.0 */
  	if (drv->feature_table_legacy) {
  		driver_features_legacy = 0;
  		for (i = 0; i < drv->feature_table_size_legacy; i++) {
  			unsigned int f = drv->feature_table_legacy[i];
  			BUG_ON(f >= 64);
  			driver_features_legacy |= (1ULL << f);
  		}
  	} else {
  		driver_features_legacy = driver_features;
  	}
747ae34a6   Michael S. Tsirkin   virtio: make VIRT...
211
  	if (device_features & (1ULL << VIRTIO_F_VERSION_1))
b3bb62d11   Michael S. Tsirkin   virtio: add legac...
212
213
214
  		dev->features = driver_features & device_features;
  	else
  		dev->features = driver_features_legacy & device_features;
c102659d6   Michael S. Tsirkin   virtio: simplify ...
215

c624896e4   Rusty Russell   virtio: Rename se...
216
  	/* Transport features always preserved to pass to finalize_features. */
dd7c7bc46   Rusty Russell   virtio: Formally ...
217
  	for (i = VIRTIO_TRANSPORT_F_START; i < VIRTIO_TRANSPORT_F_END; i++)
d02547736   Michael S. Tsirkin   virtio: add suppo...
218
  		if (device_features & (1ULL << i))
e16e12be3   Michael S. Tsirkin   virtio: use u32, ...
219
  			__virtio_set_bit(dev, i);
dd7c7bc46   Rusty Russell   virtio: Formally ...
220

30683a8cc   Michael S. Tsirkin   virtio: set VIRTI...
221
  	err = virtio_finalize_features(dev);
5c609a5ef   Michael S. Tsirkin   virtio: allow fin...
222
223
  	if (err)
  		goto err;
ef688e151   Rusty Russell   virtio: meet virt...
224

ec3d41c4d   Rusty Russell   Virtio interface
225
226
  	err = drv->probe(dev);
  	if (err)
cb3f6d9da   Michael S. Tsirkin   virtio: set FEATU...
227
  		goto err;
22b7050a0   Michael S. Tsirkin   virtio: defer con...
228

5b40a7daf   Rusty Russell   virtio: don't set...
229
230
231
  	/* If probe didn't do it, mark device DRIVER_OK ourselves. */
  	if (!(dev->config->get_status(dev) & VIRTIO_CONFIG_S_DRIVER_OK))
  		virtio_device_ready(dev);
cb3f6d9da   Michael S. Tsirkin   virtio: set FEATU...
232
233
  	if (drv->scan)
  		drv->scan(dev);
ef688e151   Rusty Russell   virtio: meet virt...
234

cb3f6d9da   Michael S. Tsirkin   virtio: set FEATU...
235
236
237
238
239
  	virtio_config_enable(dev);
  
  	return 0;
  err:
  	add_status(dev, VIRTIO_CONFIG_S_FAILED);
ec3d41c4d   Rusty Russell   Virtio interface
240
  	return err;
cb3f6d9da   Michael S. Tsirkin   virtio: set FEATU...
241

ec3d41c4d   Rusty Russell   Virtio interface
242
  }
74b2553f1   Rusty Russell   virtio: fix modul...
243
244
  static int virtio_dev_remove(struct device *_d)
  {
9bffdca8c   Wanlong Gao   virtio: use dev_t...
245
  	struct virtio_device *dev = dev_to_virtio(_d);
9a2bdcc85   Wanlong Gao   virtio: add drv_t...
246
  	struct virtio_driver *drv = drv_to_virtio(dev->dev.driver);
74b2553f1   Rusty Russell   virtio: fix modul...
247

22b7050a0   Michael S. Tsirkin   virtio: defer con...
248
  	virtio_config_disable(dev);
74b2553f1   Rusty Russell   virtio: fix modul...
249
  	drv->remove(dev);
6e5aa7efb   Rusty Russell   virtio: reset fun...
250
251
  
  	/* Driver should have reset device. */
5543a6ac3   Michael S. Tsirkin   virtio: don't cra...
252
  	WARN_ON_ONCE(dev->config->get_status(dev));
6e5aa7efb   Rusty Russell   virtio: reset fun...
253
254
255
  
  	/* Acknowledge the device's existence again. */
  	add_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE);
74b2553f1   Rusty Russell   virtio: fix modul...
256
257
  	return 0;
  }
e962fa660   Mark McLoughlin   virtio: Use bus_t...
258
259
260
  static struct bus_type virtio_bus = {
  	.name  = "virtio",
  	.match = virtio_dev_match,
3736dab6e   Greg Kroah-Hartman   virtio: convert b...
261
  	.dev_groups = virtio_dev_groups,
e962fa660   Mark McLoughlin   virtio: Use bus_t...
262
263
264
265
  	.uevent = virtio_uevent,
  	.probe = virtio_dev_probe,
  	.remove = virtio_dev_remove,
  };
ec3d41c4d   Rusty Russell   Virtio interface
266
267
  int register_virtio_driver(struct virtio_driver *driver)
  {
c45a6816c   Rusty Russell   virtio: explicit ...
268
269
  	/* Catch this early. */
  	BUG_ON(driver->feature_table_size && !driver->feature_table);
ec3d41c4d   Rusty Russell   Virtio interface
270
  	driver->driver.bus = &virtio_bus;
ec3d41c4d   Rusty Russell   Virtio interface
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
  	return driver_register(&driver->driver);
  }
  EXPORT_SYMBOL_GPL(register_virtio_driver);
  
  void unregister_virtio_driver(struct virtio_driver *driver)
  {
  	driver_unregister(&driver->driver);
  }
  EXPORT_SYMBOL_GPL(unregister_virtio_driver);
  
  int register_virtio_device(struct virtio_device *dev)
  {
  	int err;
  
  	dev->dev.bus = &virtio_bus;
b769f5790   Rusty Russell   virtio: set devic...
286
287
  
  	/* Assign a unique device index and hence name. */
90e03207f   Asias He   virtio: Use ida t...
288
289
290
291
292
  	err = ida_simple_get(&virtio_index_ida, 0, 0, GFP_KERNEL);
  	if (err < 0)
  		goto out;
  
  	dev->index = err;
99e0b6c8e   Kay Sievers   virtio: struct de...
293
  	dev_set_name(&dev->dev, "virtio%u", dev->index);
ec3d41c4d   Rusty Russell   Virtio interface
294

22b7050a0   Michael S. Tsirkin   virtio: defer con...
295
296
297
  	spin_lock_init(&dev->config_lock);
  	dev->config_enabled = false;
  	dev->config_change_pending = false;
6e5aa7efb   Rusty Russell   virtio: reset fun...
298
299
300
  	/* We always start by resetting the device, in case a previous
  	 * driver messed it up.  This also tests that code path a little. */
  	dev->config->reset(dev);
ec3d41c4d   Rusty Russell   Virtio interface
301
302
  	/* Acknowledge that we've seen the device. */
  	add_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE);
9499f5e7e   Rusty Russell   virtio: add names...
303
  	INIT_LIST_HEAD(&dev->vqs);
ec3d41c4d   Rusty Russell   Virtio interface
304
305
306
  	/* device_register() causes the bus infrastructure to look for a
  	 * matching driver. */
  	err = device_register(&dev->dev);
90e03207f   Asias He   virtio: Use ida t...
307
  out:
ec3d41c4d   Rusty Russell   Virtio interface
308
309
310
311
312
313
314
315
  	if (err)
  		add_status(dev, VIRTIO_CONFIG_S_FAILED);
  	return err;
  }
  EXPORT_SYMBOL_GPL(register_virtio_device);
  
  void unregister_virtio_device(struct virtio_device *dev)
  {
237242bdd   Cornelia Huck   virtio: Don't acc...
316
  	int index = dev->index; /* save for after device release */
ec3d41c4d   Rusty Russell   Virtio interface
317
  	device_unregister(&dev->dev);
237242bdd   Cornelia Huck   virtio: Don't acc...
318
  	ida_simple_remove(&virtio_index_ida, index);
ec3d41c4d   Rusty Russell   Virtio interface
319
320
  }
  EXPORT_SYMBOL_GPL(unregister_virtio_device);
c6716bae5   Michael S. Tsirkin   virtio-pci: move ...
321
322
323
324
  #ifdef CONFIG_PM_SLEEP
  int virtio_device_freeze(struct virtio_device *dev)
  {
  	struct virtio_driver *drv = drv_to_virtio(dev->dev.driver);
22b7050a0   Michael S. Tsirkin   virtio: defer con...
325
  	virtio_config_disable(dev);
c6716bae5   Michael S. Tsirkin   virtio-pci: move ...
326
327
328
329
330
331
332
333
334
335
336
337
  	dev->failed = dev->config->get_status(dev) & VIRTIO_CONFIG_S_FAILED;
  
  	if (drv && drv->freeze)
  		return drv->freeze(dev);
  
  	return 0;
  }
  EXPORT_SYMBOL_GPL(virtio_device_freeze);
  
  int virtio_device_restore(struct virtio_device *dev)
  {
  	struct virtio_driver *drv = drv_to_virtio(dev->dev.driver);
5c609a5ef   Michael S. Tsirkin   virtio: allow fin...
338
  	int ret;
c6716bae5   Michael S. Tsirkin   virtio-pci: move ...
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
  
  	/* We always start by resetting the device, in case a previous
  	 * driver messed it up. */
  	dev->config->reset(dev);
  
  	/* Acknowledge that we've seen the device. */
  	add_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE);
  
  	/* Maybe driver failed before freeze.
  	 * Restore the failed status, for debugging. */
  	if (dev->failed)
  		add_status(dev, VIRTIO_CONFIG_S_FAILED);
  
  	if (!drv)
  		return 0;
  
  	/* We have a driver! */
  	add_status(dev, VIRTIO_CONFIG_S_DRIVER);
30683a8cc   Michael S. Tsirkin   virtio: set VIRTI...
357
  	ret = virtio_finalize_features(dev);
5c609a5ef   Michael S. Tsirkin   virtio: allow fin...
358
359
  	if (ret)
  		goto err;
c6716bae5   Michael S. Tsirkin   virtio-pci: move ...
360
361
  
  	if (drv->restore) {
5c609a5ef   Michael S. Tsirkin   virtio: allow fin...
362
363
364
  		ret = drv->restore(dev);
  		if (ret)
  			goto err;
c6716bae5   Michael S. Tsirkin   virtio-pci: move ...
365
366
367
368
  	}
  
  	/* Finally, tell the device we're all set */
  	add_status(dev, VIRTIO_CONFIG_S_DRIVER_OK);
22b7050a0   Michael S. Tsirkin   virtio: defer con...
369
  	virtio_config_enable(dev);
c6716bae5   Michael S. Tsirkin   virtio-pci: move ...
370
  	return 0;
5c609a5ef   Michael S. Tsirkin   virtio: allow fin...
371
372
373
374
  
  err:
  	add_status(dev, VIRTIO_CONFIG_S_FAILED);
  	return ret;
c6716bae5   Michael S. Tsirkin   virtio-pci: move ...
375
376
377
  }
  EXPORT_SYMBOL_GPL(virtio_device_restore);
  #endif
ec3d41c4d   Rusty Russell   Virtio interface
378
379
380
381
382
383
  static int virtio_init(void)
  {
  	if (bus_register(&virtio_bus) != 0)
  		panic("virtio bus registration failed");
  	return 0;
  }
c6fd47011   Rusty Russell   virtio: Allow vir...
384
385
386
387
  
  static void __exit virtio_exit(void)
  {
  	bus_unregister(&virtio_bus);
c13f99b7e   Suman Anna   virtio: fix memor...
388
  	ida_destroy(&virtio_index_ida);
c6fd47011   Rusty Russell   virtio: Allow vir...
389
  }
ec3d41c4d   Rusty Russell   Virtio interface
390
  core_initcall(virtio_init);
c6fd47011   Rusty Russell   virtio: Allow vir...
391
392
393
  module_exit(virtio_exit);
  
  MODULE_LICENSE("GPL");