.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | #include <linux/virtio.h> |
---|
2 | 3 | #include <linux/spinlock.h> |
---|
3 | 4 | #include <linux/virtio_config.h> |
---|
.. | .. |
---|
161 | 162 | |
---|
162 | 163 | void virtio_add_status(struct virtio_device *dev, unsigned int status) |
---|
163 | 164 | { |
---|
| 165 | + might_sleep(); |
---|
164 | 166 | dev->config->set_status(dev, dev->config->get_status(dev) | status); |
---|
165 | 167 | } |
---|
166 | 168 | EXPORT_SYMBOL_GPL(virtio_add_status); |
---|
167 | 169 | |
---|
168 | | -int virtio_finalize_features(struct virtio_device *dev) |
---|
| 170 | +/* Do some validation, then set FEATURES_OK */ |
---|
| 171 | +static int virtio_features_ok(struct virtio_device *dev) |
---|
169 | 172 | { |
---|
170 | | - int ret = dev->config->finalize_features(dev); |
---|
171 | 173 | unsigned status; |
---|
| 174 | + int ret; |
---|
172 | 175 | |
---|
173 | | - if (ret) |
---|
174 | | - return ret; |
---|
| 176 | + might_sleep(); |
---|
| 177 | + |
---|
| 178 | + ret = arch_has_restricted_virtio_memory_access(); |
---|
| 179 | + if (ret) { |
---|
| 180 | + if (!virtio_has_feature(dev, VIRTIO_F_VERSION_1)) { |
---|
| 181 | + dev_warn(&dev->dev, |
---|
| 182 | + "device must provide VIRTIO_F_VERSION_1\n"); |
---|
| 183 | + return -ENODEV; |
---|
| 184 | + } |
---|
| 185 | + |
---|
| 186 | + if (!virtio_has_feature(dev, VIRTIO_F_ACCESS_PLATFORM)) { |
---|
| 187 | + dev_warn(&dev->dev, |
---|
| 188 | + "device must provide VIRTIO_F_ACCESS_PLATFORM\n"); |
---|
| 189 | + return -ENODEV; |
---|
| 190 | + } |
---|
| 191 | + } |
---|
175 | 192 | |
---|
176 | 193 | if (!virtio_has_feature(dev, VIRTIO_F_VERSION_1)) |
---|
177 | 194 | return 0; |
---|
.. | .. |
---|
185 | 202 | } |
---|
186 | 203 | return 0; |
---|
187 | 204 | } |
---|
188 | | -EXPORT_SYMBOL_GPL(virtio_finalize_features); |
---|
189 | 205 | |
---|
190 | 206 | static int virtio_dev_probe(struct device *_d) |
---|
191 | 207 | { |
---|
.. | .. |
---|
222 | 238 | driver_features_legacy = driver_features; |
---|
223 | 239 | } |
---|
224 | 240 | |
---|
225 | | - /* |
---|
226 | | - * Some devices detect legacy solely via F_VERSION_1. Write |
---|
227 | | - * F_VERSION_1 to force LE config space accesses before FEATURES_OK for |
---|
228 | | - * these when needed. |
---|
229 | | - */ |
---|
230 | | - if (drv->validate && !virtio_legacy_is_little_endian() |
---|
231 | | - && device_features & BIT_ULL(VIRTIO_F_VERSION_1)) { |
---|
232 | | - dev->features = BIT_ULL(VIRTIO_F_VERSION_1); |
---|
233 | | - dev->config->finalize_features(dev); |
---|
234 | | - } |
---|
235 | | - |
---|
236 | 241 | if (device_features & (1ULL << VIRTIO_F_VERSION_1)) |
---|
237 | 242 | dev->features = driver_features & device_features; |
---|
238 | 243 | else |
---|
.. | .. |
---|
243 | 248 | if (device_features & (1ULL << i)) |
---|
244 | 249 | __virtio_set_bit(dev, i); |
---|
245 | 250 | |
---|
| 251 | + err = dev->config->finalize_features(dev); |
---|
| 252 | + if (err) |
---|
| 253 | + goto err; |
---|
| 254 | + |
---|
246 | 255 | if (drv->validate) { |
---|
| 256 | + u64 features = dev->features; |
---|
| 257 | + |
---|
247 | 258 | err = drv->validate(dev); |
---|
248 | 259 | if (err) |
---|
249 | 260 | goto err; |
---|
| 261 | + |
---|
| 262 | + /* Did validation change any features? Then write them again. */ |
---|
| 263 | + if (features != dev->features) { |
---|
| 264 | + err = dev->config->finalize_features(dev); |
---|
| 265 | + if (err) |
---|
| 266 | + goto err; |
---|
| 267 | + } |
---|
250 | 268 | } |
---|
251 | 269 | |
---|
252 | | - err = virtio_finalize_features(dev); |
---|
| 270 | + err = virtio_features_ok(dev); |
---|
253 | 271 | if (err) |
---|
254 | 272 | goto err; |
---|
255 | 273 | |
---|
.. | .. |
---|
365 | 383 | } |
---|
366 | 384 | EXPORT_SYMBOL_GPL(register_virtio_device); |
---|
367 | 385 | |
---|
| 386 | +bool is_virtio_device(struct device *dev) |
---|
| 387 | +{ |
---|
| 388 | + return dev->bus == &virtio_bus; |
---|
| 389 | +} |
---|
| 390 | +EXPORT_SYMBOL_GPL(is_virtio_device); |
---|
| 391 | + |
---|
368 | 392 | void unregister_virtio_device(struct virtio_device *dev) |
---|
369 | 393 | { |
---|
370 | 394 | int index = dev->index; /* save for after device release */ |
---|
.. | .. |
---|
395 | 419 | struct virtio_driver *drv = drv_to_virtio(dev->dev.driver); |
---|
396 | 420 | int ret; |
---|
397 | 421 | |
---|
| 422 | + /* Short path for stateful devices. Here we assume that if the device |
---|
| 423 | + * does not have a freeze callback, its state was not changed when |
---|
| 424 | + * suspended. |
---|
| 425 | + */ |
---|
| 426 | + if (drv && !drv->freeze) |
---|
| 427 | + goto on_config_enable; |
---|
| 428 | + |
---|
398 | 429 | /* We always start by resetting the device, in case a previous |
---|
399 | 430 | * driver messed it up. */ |
---|
400 | 431 | dev->config->reset(dev); |
---|
.. | .. |
---|
413 | 444 | /* We have a driver! */ |
---|
414 | 445 | virtio_add_status(dev, VIRTIO_CONFIG_S_DRIVER); |
---|
415 | 446 | |
---|
416 | | - ret = virtio_finalize_features(dev); |
---|
| 447 | + ret = dev->config->finalize_features(dev); |
---|
| 448 | + if (ret) |
---|
| 449 | + goto err; |
---|
| 450 | + |
---|
| 451 | + ret = virtio_features_ok(dev); |
---|
417 | 452 | if (ret) |
---|
418 | 453 | goto err; |
---|
419 | 454 | |
---|
.. | .. |
---|
426 | 461 | /* Finally, tell the device we're all set */ |
---|
427 | 462 | virtio_add_status(dev, VIRTIO_CONFIG_S_DRIVER_OK); |
---|
428 | 463 | |
---|
| 464 | +on_config_enable: |
---|
429 | 465 | virtio_config_enable(dev); |
---|
430 | 466 | |
---|
431 | 467 | return 0; |
---|