Commit | Line | Data |
---|---|---|
09c434b8 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
ec3d41c4 RR |
2 | #include <linux/virtio.h> |
3 | #include <linux/spinlock.h> | |
4 | #include <linux/virtio_config.h> | |
b5a2c4f1 | 5 | #include <linux/module.h> |
90e03207 | 6 | #include <linux/idr.h> |
694a1116 | 7 | #include <linux/of.h> |
b6098c30 | 8 | #include <uapi/linux/virtio_ids.h> |
ec3d41c4 | 9 | |
b769f579 | 10 | /* Unique numbering for virtio devices. */ |
90e03207 | 11 | static DEFINE_IDA(virtio_index_ida); |
b769f579 | 12 | |
ec3d41c4 RR |
13 | static ssize_t device_show(struct device *_d, |
14 | struct device_attribute *attr, char *buf) | |
15 | { | |
9bffdca8 | 16 | struct virtio_device *dev = dev_to_virtio(_d); |
be6528b2 | 17 | return sprintf(buf, "0x%04x\n", dev->id.device); |
ec3d41c4 | 18 | } |
3736dab6 GKH |
19 | static DEVICE_ATTR_RO(device); |
20 | ||
ec3d41c4 RR |
21 | static ssize_t vendor_show(struct device *_d, |
22 | struct device_attribute *attr, char *buf) | |
23 | { | |
9bffdca8 | 24 | struct virtio_device *dev = dev_to_virtio(_d); |
be6528b2 | 25 | return sprintf(buf, "0x%04x\n", dev->id.vendor); |
ec3d41c4 | 26 | } |
3736dab6 GKH |
27 | static DEVICE_ATTR_RO(vendor); |
28 | ||
ec3d41c4 RR |
29 | static ssize_t status_show(struct device *_d, |
30 | struct device_attribute *attr, char *buf) | |
31 | { | |
9bffdca8 | 32 | struct virtio_device *dev = dev_to_virtio(_d); |
be6528b2 | 33 | return sprintf(buf, "0x%08x\n", dev->config->get_status(dev)); |
ec3d41c4 | 34 | } |
3736dab6 GKH |
35 | static DEVICE_ATTR_RO(status); |
36 | ||
b01d9f28 RR |
37 | static ssize_t modalias_show(struct device *_d, |
38 | struct device_attribute *attr, char *buf) | |
39 | { | |
9bffdca8 | 40 | struct virtio_device *dev = dev_to_virtio(_d); |
b01d9f28 RR |
41 | return sprintf(buf, "virtio:d%08Xv%08X\n", |
42 | dev->id.device, dev->id.vendor); | |
43 | } | |
3736dab6 GKH |
44 | static DEVICE_ATTR_RO(modalias); |
45 | ||
a9289282 RR |
46 | static ssize_t features_show(struct device *_d, |
47 | struct device_attribute *attr, char *buf) | |
48 | { | |
9bffdca8 | 49 | struct virtio_device *dev = dev_to_virtio(_d); |
a9289282 RR |
50 | unsigned int i; |
51 | ssize_t len = 0; | |
52 | ||
53 | /* We actually represent this as a bitstring, as it could be | |
54 | * arbitrary length in future. */ | |
e16e12be | 55 | for (i = 0; i < sizeof(dev->features)*8; i++) |
a9289282 | 56 | len += sprintf(buf+len, "%c", |
e16e12be | 57 | __virtio_test_bit(dev, i) ? '1' : '0'); |
a9289282 RR |
58 | len += sprintf(buf+len, "\n"); |
59 | return len; | |
60 | } | |
3736dab6 GKH |
61 | static DEVICE_ATTR_RO(features); |
62 | ||
63 | static struct attribute *virtio_dev_attrs[] = { | |
64 | &dev_attr_device.attr, | |
65 | &dev_attr_vendor.attr, | |
66 | &dev_attr_status.attr, | |
67 | &dev_attr_modalias.attr, | |
68 | &dev_attr_features.attr, | |
69 | NULL, | |
ec3d41c4 | 70 | }; |
3736dab6 | 71 | ATTRIBUTE_GROUPS(virtio_dev); |
ec3d41c4 RR |
72 | |
73 | static inline int virtio_id_match(const struct virtio_device *dev, | |
74 | const struct virtio_device_id *id) | |
75 | { | |
e3353853 | 76 | if (id->device != dev->id.device && id->device != VIRTIO_DEV_ANY_ID) |
ec3d41c4 RR |
77 | return 0; |
78 | ||
c89e8016 | 79 | return id->vendor == VIRTIO_DEV_ANY_ID || id->vendor == dev->id.vendor; |
ec3d41c4 RR |
80 | } |
81 | ||
82 | /* This looks through all the IDs a driver claims to support. If any of them | |
83 | * match, we return 1 and the kernel will call virtio_dev_probe(). */ | |
84 | static int virtio_dev_match(struct device *_dv, struct device_driver *_dr) | |
85 | { | |
86 | unsigned int i; | |
9bffdca8 | 87 | struct virtio_device *dev = dev_to_virtio(_dv); |
ec3d41c4 RR |
88 | const struct virtio_device_id *ids; |
89 | ||
9a2bdcc8 | 90 | ids = drv_to_virtio(_dr)->id_table; |
ec3d41c4 RR |
91 | for (i = 0; ids[i].device; i++) |
92 | if (virtio_id_match(dev, &ids[i])) | |
93 | return 1; | |
94 | return 0; | |
95 | } | |
96 | ||
b01d9f28 RR |
97 | static int virtio_uevent(struct device *_dv, struct kobj_uevent_env *env) |
98 | { | |
9bffdca8 | 99 | struct virtio_device *dev = dev_to_virtio(_dv); |
b01d9f28 RR |
100 | |
101 | return add_uevent_var(env, "MODALIAS=virtio:d%08Xv%08X", | |
102 | dev->id.device, dev->id.vendor); | |
103 | } | |
104 | ||
c45a6816 RR |
105 | void virtio_check_driver_offered_feature(const struct virtio_device *vdev, |
106 | unsigned int fbit) | |
107 | { | |
108 | unsigned int i; | |
9a2bdcc8 | 109 | struct virtio_driver *drv = drv_to_virtio(vdev->dev.driver); |
c45a6816 RR |
110 | |
111 | for (i = 0; i < drv->feature_table_size; i++) | |
112 | if (drv->feature_table[i] == fbit) | |
113 | return; | |
b3bb62d1 MT |
114 | |
115 | if (drv->feature_table_legacy) { | |
116 | for (i = 0; i < drv->feature_table_size_legacy; i++) | |
117 | if (drv->feature_table_legacy[i] == fbit) | |
118 | return; | |
119 | } | |
120 | ||
c45a6816 RR |
121 | BUG(); |
122 | } | |
123 | EXPORT_SYMBOL_GPL(virtio_check_driver_offered_feature); | |
124 | ||
22b7050a MT |
125 | static void __virtio_config_changed(struct virtio_device *dev) |
126 | { | |
127 | struct virtio_driver *drv = drv_to_virtio(dev->dev.driver); | |
128 | ||
129 | if (!dev->config_enabled) | |
130 | dev->config_change_pending = true; | |
131 | else if (drv && drv->config_changed) | |
132 | drv->config_changed(dev); | |
133 | } | |
134 | ||
135 | void virtio_config_changed(struct virtio_device *dev) | |
136 | { | |
137 | unsigned long flags; | |
138 | ||
139 | spin_lock_irqsave(&dev->config_lock, flags); | |
140 | __virtio_config_changed(dev); | |
141 | spin_unlock_irqrestore(&dev->config_lock, flags); | |
142 | } | |
143 | EXPORT_SYMBOL_GPL(virtio_config_changed); | |
144 | ||
bc22ed2e | 145 | static void virtio_config_disable(struct virtio_device *dev) |
22b7050a MT |
146 | { |
147 | spin_lock_irq(&dev->config_lock); | |
148 | dev->config_enabled = false; | |
149 | spin_unlock_irq(&dev->config_lock); | |
150 | } | |
151 | ||
bc22ed2e | 152 | static void virtio_config_enable(struct virtio_device *dev) |
22b7050a MT |
153 | { |
154 | spin_lock_irq(&dev->config_lock); | |
155 | dev->config_enabled = true; | |
156 | if (dev->config_change_pending) | |
157 | __virtio_config_changed(dev); | |
158 | dev->config_change_pending = false; | |
159 | spin_unlock_irq(&dev->config_lock); | |
160 | } | |
9fe7bfce JF |
161 | |
162 | void virtio_add_status(struct virtio_device *dev, unsigned int status) | |
163 | { | |
ab7a2375 | 164 | might_sleep(); |
9fe7bfce JF |
165 | dev->config->set_status(dev, dev->config->get_status(dev) | status); |
166 | } | |
167 | EXPORT_SYMBOL_GPL(virtio_add_status); | |
22b7050a | 168 | |
4fa59ede MT |
169 | /* Do some validation, then set FEATURES_OK */ |
170 | static int virtio_features_ok(struct virtio_device *dev) | |
30683a8c | 171 | { |
30683a8c | 172 | unsigned status; |
4fa59ede | 173 | int ret; |
30683a8c | 174 | |
ab7a2375 | 175 | might_sleep(); |
30683a8c | 176 | |
0afa15e1 PM |
177 | ret = arch_has_restricted_virtio_memory_access(); |
178 | if (ret) { | |
179 | if (!virtio_has_feature(dev, VIRTIO_F_VERSION_1)) { | |
180 | dev_warn(&dev->dev, | |
181 | "device must provide VIRTIO_F_VERSION_1\n"); | |
182 | return -ENODEV; | |
183 | } | |
184 | ||
185 | if (!virtio_has_feature(dev, VIRTIO_F_ACCESS_PLATFORM)) { | |
186 | dev_warn(&dev->dev, | |
187 | "device must provide VIRTIO_F_ACCESS_PLATFORM\n"); | |
188 | return -ENODEV; | |
189 | } | |
190 | } | |
191 | ||
30683a8c MT |
192 | if (!virtio_has_feature(dev, VIRTIO_F_VERSION_1)) |
193 | return 0; | |
194 | ||
9fe7bfce | 195 | virtio_add_status(dev, VIRTIO_CONFIG_S_FEATURES_OK); |
30683a8c MT |
196 | status = dev->config->get_status(dev); |
197 | if (!(status & VIRTIO_CONFIG_S_FEATURES_OK)) { | |
198 | dev_err(&dev->dev, "virtio: device refuses features: %x\n", | |
199 | status); | |
200 | return -ENODEV; | |
201 | } | |
202 | return 0; | |
203 | } | |
204 | ||
c46eccda MT |
205 | /** |
206 | * virtio_reset_device - quiesce device for removal | |
207 | * @dev: the device to reset | |
208 | * | |
209 | * Prevents device from sending interrupts and accessing memory. | |
210 | * | |
211 | * Generally used for cleanup during driver / device removal. | |
212 | * | |
213 | * Once this has been invoked, caller must ensure that | |
214 | * virtqueue_notify / virtqueue_kick are not in progress. | |
215 | * | |
216 | * Note: this guarantees that vq callbacks are not in progress, however caller | |
217 | * is responsible for preventing access from other contexts, such as a system | |
218 | * call/workqueue/bh. Invoking virtio_break_device then flushing any such | |
219 | * contexts is one way to handle that. | |
220 | * */ | |
d9679d00 MT |
221 | void virtio_reset_device(struct virtio_device *dev) |
222 | { | |
223 | dev->config->reset(dev); | |
224 | } | |
225 | EXPORT_SYMBOL_GPL(virtio_reset_device); | |
226 | ||
ec3d41c4 RR |
227 | static int virtio_dev_probe(struct device *_d) |
228 | { | |
c45a6816 | 229 | int err, i; |
9bffdca8 | 230 | struct virtio_device *dev = dev_to_virtio(_d); |
9a2bdcc8 | 231 | struct virtio_driver *drv = drv_to_virtio(dev->dev.driver); |
d0254773 | 232 | u64 device_features; |
c102659d | 233 | u64 driver_features; |
b3bb62d1 | 234 | u64 driver_features_legacy; |
ec3d41c4 | 235 | |
c45a6816 | 236 | /* We have a driver! */ |
9fe7bfce | 237 | virtio_add_status(dev, VIRTIO_CONFIG_S_DRIVER); |
c45a6816 RR |
238 | |
239 | /* Figure out what features the device supports. */ | |
240 | device_features = dev->config->get_features(dev); | |
241 | ||
c102659d MT |
242 | /* Figure out what features the driver supports. */ |
243 | driver_features = 0; | |
c45a6816 RR |
244 | for (i = 0; i < drv->feature_table_size; i++) { |
245 | unsigned int f = drv->feature_table[i]; | |
d0254773 | 246 | BUG_ON(f >= 64); |
c102659d | 247 | driver_features |= (1ULL << f); |
c45a6816 RR |
248 | } |
249 | ||
b3bb62d1 MT |
250 | /* Some drivers have a separate feature table for virtio v1.0 */ |
251 | if (drv->feature_table_legacy) { | |
252 | driver_features_legacy = 0; | |
253 | for (i = 0; i < drv->feature_table_size_legacy; i++) { | |
254 | unsigned int f = drv->feature_table_legacy[i]; | |
255 | BUG_ON(f >= 64); | |
256 | driver_features_legacy |= (1ULL << f); | |
257 | } | |
258 | } else { | |
259 | driver_features_legacy = driver_features; | |
260 | } | |
261 | ||
747ae34a | 262 | if (device_features & (1ULL << VIRTIO_F_VERSION_1)) |
b3bb62d1 MT |
263 | dev->features = driver_features & device_features; |
264 | else | |
265 | dev->features = driver_features_legacy & device_features; | |
c102659d | 266 | |
c624896e | 267 | /* Transport features always preserved to pass to finalize_features. */ |
dd7c7bc4 | 268 | for (i = VIRTIO_TRANSPORT_F_START; i < VIRTIO_TRANSPORT_F_END; i++) |
d0254773 | 269 | if (device_features & (1ULL << i)) |
e16e12be | 270 | __virtio_set_bit(dev, i); |
dd7c7bc4 | 271 | |
4fa59ede MT |
272 | err = dev->config->finalize_features(dev); |
273 | if (err) | |
274 | goto err; | |
275 | ||
404123c2 | 276 | if (drv->validate) { |
4fa59ede MT |
277 | u64 features = dev->features; |
278 | ||
404123c2 MT |
279 | err = drv->validate(dev); |
280 | if (err) | |
281 | goto err; | |
4fa59ede MT |
282 | |
283 | /* Did validation change any features? Then write them again. */ | |
284 | if (features != dev->features) { | |
285 | err = dev->config->finalize_features(dev); | |
286 | if (err) | |
287 | goto err; | |
288 | } | |
404123c2 MT |
289 | } |
290 | ||
4fa59ede | 291 | err = virtio_features_ok(dev); |
5c609a5e MT |
292 | if (err) |
293 | goto err; | |
ef688e15 | 294 | |
ec3d41c4 RR |
295 | err = drv->probe(dev); |
296 | if (err) | |
cb3f6d9d | 297 | goto err; |
22b7050a | 298 | |
5b40a7da RR |
299 | /* If probe didn't do it, mark device DRIVER_OK ourselves. */ |
300 | if (!(dev->config->get_status(dev) & VIRTIO_CONFIG_S_DRIVER_OK)) | |
301 | virtio_device_ready(dev); | |
302 | ||
cb3f6d9d MT |
303 | if (drv->scan) |
304 | drv->scan(dev); | |
ef688e15 | 305 | |
cb3f6d9d MT |
306 | virtio_config_enable(dev); |
307 | ||
308 | return 0; | |
309 | err: | |
9fe7bfce | 310 | virtio_add_status(dev, VIRTIO_CONFIG_S_FAILED); |
ec3d41c4 | 311 | return err; |
cb3f6d9d | 312 | |
ec3d41c4 RR |
313 | } |
314 | ||
fc7a6209 | 315 | static void virtio_dev_remove(struct device *_d) |
74b2553f | 316 | { |
9bffdca8 | 317 | struct virtio_device *dev = dev_to_virtio(_d); |
9a2bdcc8 | 318 | struct virtio_driver *drv = drv_to_virtio(dev->dev.driver); |
74b2553f | 319 | |
22b7050a MT |
320 | virtio_config_disable(dev); |
321 | ||
74b2553f | 322 | drv->remove(dev); |
6e5aa7ef RR |
323 | |
324 | /* Driver should have reset device. */ | |
5543a6ac | 325 | WARN_ON_ONCE(dev->config->get_status(dev)); |
6e5aa7ef RR |
326 | |
327 | /* Acknowledge the device's existence again. */ | |
9fe7bfce | 328 | virtio_add_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE); |
694a1116 VK |
329 | |
330 | of_node_put(dev->dev.of_node); | |
74b2553f RR |
331 | } |
332 | ||
e962fa66 MM |
333 | static struct bus_type virtio_bus = { |
334 | .name = "virtio", | |
335 | .match = virtio_dev_match, | |
3736dab6 | 336 | .dev_groups = virtio_dev_groups, |
e962fa66 MM |
337 | .uevent = virtio_uevent, |
338 | .probe = virtio_dev_probe, | |
339 | .remove = virtio_dev_remove, | |
340 | }; | |
341 | ||
ec3d41c4 RR |
342 | int register_virtio_driver(struct virtio_driver *driver) |
343 | { | |
c45a6816 RR |
344 | /* Catch this early. */ |
345 | BUG_ON(driver->feature_table_size && !driver->feature_table); | |
ec3d41c4 | 346 | driver->driver.bus = &virtio_bus; |
ec3d41c4 RR |
347 | return driver_register(&driver->driver); |
348 | } | |
349 | EXPORT_SYMBOL_GPL(register_virtio_driver); | |
350 | ||
351 | void unregister_virtio_driver(struct virtio_driver *driver) | |
352 | { | |
353 | driver_unregister(&driver->driver); | |
354 | } | |
355 | EXPORT_SYMBOL_GPL(unregister_virtio_driver); | |
356 | ||
694a1116 VK |
357 | static int virtio_device_of_init(struct virtio_device *dev) |
358 | { | |
359 | struct device_node *np, *pnode = dev_of_node(dev->dev.parent); | |
360 | char compat[] = "virtio,deviceXXXXXXXX"; | |
361 | int ret, count; | |
362 | ||
363 | if (!pnode) | |
364 | return 0; | |
365 | ||
366 | count = of_get_available_child_count(pnode); | |
367 | if (!count) | |
368 | return 0; | |
369 | ||
370 | /* There can be only 1 child node */ | |
371 | if (WARN_ON(count > 1)) | |
372 | return -EINVAL; | |
373 | ||
374 | np = of_get_next_available_child(pnode, NULL); | |
375 | if (WARN_ON(!np)) | |
376 | return -ENODEV; | |
377 | ||
378 | ret = snprintf(compat, sizeof(compat), "virtio,device%x", dev->id.device); | |
379 | BUG_ON(ret >= sizeof(compat)); | |
380 | ||
0d818706 MT |
381 | /* |
382 | * On powerpc/pseries virtio devices are PCI devices so PCI | |
383 | * vendor/device ids play the role of the "compatible" property. | |
384 | * Simply don't init of_node in this case. | |
385 | */ | |
694a1116 | 386 | if (!of_device_is_compatible(np, compat)) { |
0d818706 | 387 | ret = 0; |
694a1116 VK |
388 | goto out; |
389 | } | |
390 | ||
391 | dev->dev.of_node = np; | |
392 | return 0; | |
393 | ||
394 | out: | |
395 | of_node_put(np); | |
396 | return ret; | |
397 | } | |
398 | ||
f2b44cde | 399 | /** |
400 | * register_virtio_device - register virtio device | |
401 | * @dev : virtio device to be registered | |
402 | * | |
403 | * On error, the caller must call put_device on &@dev->dev (and not kfree), | |
404 | * as another code path may have obtained a reference to @dev. | |
405 | * | |
406 | * Returns: 0 on suceess, -error on failure | |
407 | */ | |
ec3d41c4 RR |
408 | int register_virtio_device(struct virtio_device *dev) |
409 | { | |
410 | int err; | |
411 | ||
412 | dev->dev.bus = &virtio_bus; | |
f2b44cde | 413 | device_initialize(&dev->dev); |
b769f579 RR |
414 | |
415 | /* Assign a unique device index and hence name. */ | |
90e03207 AH |
416 | err = ida_simple_get(&virtio_index_ida, 0, 0, GFP_KERNEL); |
417 | if (err < 0) | |
418 | goto out; | |
419 | ||
420 | dev->index = err; | |
99e0b6c8 | 421 | dev_set_name(&dev->dev, "virtio%u", dev->index); |
ec3d41c4 | 422 | |
694a1116 VK |
423 | err = virtio_device_of_init(dev); |
424 | if (err) | |
425 | goto out_ida_remove; | |
426 | ||
22b7050a MT |
427 | spin_lock_init(&dev->config_lock); |
428 | dev->config_enabled = false; | |
429 | dev->config_change_pending = false; | |
430 | ||
6e5aa7ef RR |
431 | /* We always start by resetting the device, in case a previous |
432 | * driver messed it up. This also tests that code path a little. */ | |
433 | dev->config->reset(dev); | |
434 | ||
ec3d41c4 | 435 | /* Acknowledge that we've seen the device. */ |
9fe7bfce | 436 | virtio_add_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE); |
ec3d41c4 | 437 | |
9499f5e7 | 438 | INIT_LIST_HEAD(&dev->vqs); |
0e566c8f | 439 | spin_lock_init(&dev->vqs_list_lock); |
9499f5e7 | 440 | |
f2b44cde | 441 | /* |
442 | * device_add() causes the bus infrastructure to look for a matching | |
443 | * driver. | |
444 | */ | |
445 | err = device_add(&dev->dev); | |
e60ea67b | 446 | if (err) |
694a1116 VK |
447 | goto out_of_node_put; |
448 | ||
449 | return 0; | |
450 | ||
451 | out_of_node_put: | |
452 | of_node_put(dev->dev.of_node); | |
453 | out_ida_remove: | |
454 | ida_simple_remove(&virtio_index_ida, dev->index); | |
90e03207 | 455 | out: |
694a1116 | 456 | virtio_add_status(dev, VIRTIO_CONFIG_S_FAILED); |
ec3d41c4 RR |
457 | return err; |
458 | } | |
459 | EXPORT_SYMBOL_GPL(register_virtio_device); | |
460 | ||
a0308938 DS |
461 | bool is_virtio_device(struct device *dev) |
462 | { | |
463 | return dev->bus == &virtio_bus; | |
464 | } | |
465 | EXPORT_SYMBOL_GPL(is_virtio_device); | |
466 | ||
ec3d41c4 RR |
467 | void unregister_virtio_device(struct virtio_device *dev) |
468 | { | |
237242bd CH |
469 | int index = dev->index; /* save for after device release */ |
470 | ||
ec3d41c4 | 471 | device_unregister(&dev->dev); |
237242bd | 472 | ida_simple_remove(&virtio_index_ida, index); |
ec3d41c4 RR |
473 | } |
474 | EXPORT_SYMBOL_GPL(unregister_virtio_device); | |
475 | ||
c6716bae MT |
476 | #ifdef CONFIG_PM_SLEEP |
477 | int virtio_device_freeze(struct virtio_device *dev) | |
478 | { | |
479 | struct virtio_driver *drv = drv_to_virtio(dev->dev.driver); | |
480 | ||
22b7050a MT |
481 | virtio_config_disable(dev); |
482 | ||
c6716bae MT |
483 | dev->failed = dev->config->get_status(dev) & VIRTIO_CONFIG_S_FAILED; |
484 | ||
485 | if (drv && drv->freeze) | |
486 | return drv->freeze(dev); | |
487 | ||
488 | return 0; | |
489 | } | |
490 | EXPORT_SYMBOL_GPL(virtio_device_freeze); | |
491 | ||
492 | int virtio_device_restore(struct virtio_device *dev) | |
493 | { | |
494 | struct virtio_driver *drv = drv_to_virtio(dev->dev.driver); | |
5c609a5e | 495 | int ret; |
c6716bae MT |
496 | |
497 | /* We always start by resetting the device, in case a previous | |
498 | * driver messed it up. */ | |
499 | dev->config->reset(dev); | |
500 | ||
501 | /* Acknowledge that we've seen the device. */ | |
9fe7bfce | 502 | virtio_add_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE); |
c6716bae MT |
503 | |
504 | /* Maybe driver failed before freeze. | |
505 | * Restore the failed status, for debugging. */ | |
506 | if (dev->failed) | |
9fe7bfce | 507 | virtio_add_status(dev, VIRTIO_CONFIG_S_FAILED); |
c6716bae MT |
508 | |
509 | if (!drv) | |
510 | return 0; | |
511 | ||
512 | /* We have a driver! */ | |
9fe7bfce | 513 | virtio_add_status(dev, VIRTIO_CONFIG_S_DRIVER); |
c6716bae | 514 | |
4fa59ede MT |
515 | ret = dev->config->finalize_features(dev); |
516 | if (ret) | |
517 | goto err; | |
518 | ||
519 | ret = virtio_features_ok(dev); | |
5c609a5e MT |
520 | if (ret) |
521 | goto err; | |
c6716bae MT |
522 | |
523 | if (drv->restore) { | |
5c609a5e MT |
524 | ret = drv->restore(dev); |
525 | if (ret) | |
526 | goto err; | |
c6716bae MT |
527 | } |
528 | ||
7414539c MT |
529 | /* Finally, tell the device we're all set */ |
530 | virtio_add_status(dev, VIRTIO_CONFIG_S_DRIVER_OK); | |
c6716bae | 531 | |
22b7050a MT |
532 | virtio_config_enable(dev); |
533 | ||
c6716bae | 534 | return 0; |
5c609a5e MT |
535 | |
536 | err: | |
9fe7bfce | 537 | virtio_add_status(dev, VIRTIO_CONFIG_S_FAILED); |
5c609a5e | 538 | return ret; |
c6716bae MT |
539 | } |
540 | EXPORT_SYMBOL_GPL(virtio_device_restore); | |
541 | #endif | |
542 | ||
ec3d41c4 RR |
543 | static int virtio_init(void) |
544 | { | |
545 | if (bus_register(&virtio_bus) != 0) | |
546 | panic("virtio bus registration failed"); | |
547 | return 0; | |
548 | } | |
c6fd4701 RR |
549 | |
550 | static void __exit virtio_exit(void) | |
551 | { | |
552 | bus_unregister(&virtio_bus); | |
c13f99b7 | 553 | ida_destroy(&virtio_index_ida); |
c6fd4701 | 554 | } |
ec3d41c4 | 555 | core_initcall(virtio_init); |
c6fd4701 RR |
556 | module_exit(virtio_exit); |
557 | ||
558 | MODULE_LICENSE("GPL"); |