162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci#include <linux/virtio.h> 362306a36Sopenharmony_ci#include <linux/spinlock.h> 462306a36Sopenharmony_ci#include <linux/virtio_config.h> 562306a36Sopenharmony_ci#include <linux/virtio_anchor.h> 662306a36Sopenharmony_ci#include <linux/module.h> 762306a36Sopenharmony_ci#include <linux/idr.h> 862306a36Sopenharmony_ci#include <linux/of.h> 962306a36Sopenharmony_ci#include <uapi/linux/virtio_ids.h> 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci/* Unique numbering for virtio devices. */ 1262306a36Sopenharmony_cistatic DEFINE_IDA(virtio_index_ida); 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_cistatic ssize_t device_show(struct device *_d, 1562306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 1662306a36Sopenharmony_ci{ 1762306a36Sopenharmony_ci struct virtio_device *dev = dev_to_virtio(_d); 1862306a36Sopenharmony_ci return sysfs_emit(buf, "0x%04x\n", dev->id.device); 1962306a36Sopenharmony_ci} 2062306a36Sopenharmony_cistatic DEVICE_ATTR_RO(device); 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_cistatic ssize_t vendor_show(struct device *_d, 2362306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 2462306a36Sopenharmony_ci{ 2562306a36Sopenharmony_ci struct virtio_device *dev = dev_to_virtio(_d); 2662306a36Sopenharmony_ci return sysfs_emit(buf, "0x%04x\n", dev->id.vendor); 2762306a36Sopenharmony_ci} 2862306a36Sopenharmony_cistatic DEVICE_ATTR_RO(vendor); 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_cistatic ssize_t status_show(struct device *_d, 3162306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 3262306a36Sopenharmony_ci{ 3362306a36Sopenharmony_ci struct virtio_device *dev = dev_to_virtio(_d); 3462306a36Sopenharmony_ci return sysfs_emit(buf, "0x%08x\n", dev->config->get_status(dev)); 3562306a36Sopenharmony_ci} 3662306a36Sopenharmony_cistatic DEVICE_ATTR_RO(status); 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_cistatic ssize_t modalias_show(struct device *_d, 3962306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 4062306a36Sopenharmony_ci{ 4162306a36Sopenharmony_ci struct virtio_device *dev = dev_to_virtio(_d); 4262306a36Sopenharmony_ci return sysfs_emit(buf, "virtio:d%08Xv%08X\n", 4362306a36Sopenharmony_ci dev->id.device, dev->id.vendor); 4462306a36Sopenharmony_ci} 4562306a36Sopenharmony_cistatic DEVICE_ATTR_RO(modalias); 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistatic ssize_t features_show(struct device *_d, 4862306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 4962306a36Sopenharmony_ci{ 5062306a36Sopenharmony_ci struct virtio_device *dev = dev_to_virtio(_d); 5162306a36Sopenharmony_ci unsigned int i; 5262306a36Sopenharmony_ci ssize_t len = 0; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci /* We actually represent this as a bitstring, as it could be 5562306a36Sopenharmony_ci * arbitrary length in future. */ 5662306a36Sopenharmony_ci for (i = 0; i < sizeof(dev->features)*8; i++) 5762306a36Sopenharmony_ci len += sysfs_emit_at(buf, len, "%c", 5862306a36Sopenharmony_ci __virtio_test_bit(dev, i) ? '1' : '0'); 5962306a36Sopenharmony_ci len += sysfs_emit_at(buf, len, "\n"); 6062306a36Sopenharmony_ci return len; 6162306a36Sopenharmony_ci} 6262306a36Sopenharmony_cistatic DEVICE_ATTR_RO(features); 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistatic struct attribute *virtio_dev_attrs[] = { 6562306a36Sopenharmony_ci &dev_attr_device.attr, 6662306a36Sopenharmony_ci &dev_attr_vendor.attr, 6762306a36Sopenharmony_ci &dev_attr_status.attr, 6862306a36Sopenharmony_ci &dev_attr_modalias.attr, 6962306a36Sopenharmony_ci &dev_attr_features.attr, 7062306a36Sopenharmony_ci NULL, 7162306a36Sopenharmony_ci}; 7262306a36Sopenharmony_ciATTRIBUTE_GROUPS(virtio_dev); 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_cistatic inline int virtio_id_match(const struct virtio_device *dev, 7562306a36Sopenharmony_ci const struct virtio_device_id *id) 7662306a36Sopenharmony_ci{ 7762306a36Sopenharmony_ci if (id->device != dev->id.device && id->device != VIRTIO_DEV_ANY_ID) 7862306a36Sopenharmony_ci return 0; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci return id->vendor == VIRTIO_DEV_ANY_ID || id->vendor == dev->id.vendor; 8162306a36Sopenharmony_ci} 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci/* This looks through all the IDs a driver claims to support. If any of them 8462306a36Sopenharmony_ci * match, we return 1 and the kernel will call virtio_dev_probe(). */ 8562306a36Sopenharmony_cistatic int virtio_dev_match(struct device *_dv, struct device_driver *_dr) 8662306a36Sopenharmony_ci{ 8762306a36Sopenharmony_ci unsigned int i; 8862306a36Sopenharmony_ci struct virtio_device *dev = dev_to_virtio(_dv); 8962306a36Sopenharmony_ci const struct virtio_device_id *ids; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci ids = drv_to_virtio(_dr)->id_table; 9262306a36Sopenharmony_ci for (i = 0; ids[i].device; i++) 9362306a36Sopenharmony_ci if (virtio_id_match(dev, &ids[i])) 9462306a36Sopenharmony_ci return 1; 9562306a36Sopenharmony_ci return 0; 9662306a36Sopenharmony_ci} 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistatic int virtio_uevent(const struct device *_dv, struct kobj_uevent_env *env) 9962306a36Sopenharmony_ci{ 10062306a36Sopenharmony_ci const struct virtio_device *dev = dev_to_virtio(_dv); 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci return add_uevent_var(env, "MODALIAS=virtio:d%08Xv%08X", 10362306a36Sopenharmony_ci dev->id.device, dev->id.vendor); 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_civoid virtio_check_driver_offered_feature(const struct virtio_device *vdev, 10762306a36Sopenharmony_ci unsigned int fbit) 10862306a36Sopenharmony_ci{ 10962306a36Sopenharmony_ci unsigned int i; 11062306a36Sopenharmony_ci struct virtio_driver *drv = drv_to_virtio(vdev->dev.driver); 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci for (i = 0; i < drv->feature_table_size; i++) 11362306a36Sopenharmony_ci if (drv->feature_table[i] == fbit) 11462306a36Sopenharmony_ci return; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci if (drv->feature_table_legacy) { 11762306a36Sopenharmony_ci for (i = 0; i < drv->feature_table_size_legacy; i++) 11862306a36Sopenharmony_ci if (drv->feature_table_legacy[i] == fbit) 11962306a36Sopenharmony_ci return; 12062306a36Sopenharmony_ci } 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci BUG(); 12362306a36Sopenharmony_ci} 12462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(virtio_check_driver_offered_feature); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_cistatic void __virtio_config_changed(struct virtio_device *dev) 12762306a36Sopenharmony_ci{ 12862306a36Sopenharmony_ci struct virtio_driver *drv = drv_to_virtio(dev->dev.driver); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci if (!dev->config_enabled) 13162306a36Sopenharmony_ci dev->config_change_pending = true; 13262306a36Sopenharmony_ci else if (drv && drv->config_changed) 13362306a36Sopenharmony_ci drv->config_changed(dev); 13462306a36Sopenharmony_ci} 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_civoid virtio_config_changed(struct virtio_device *dev) 13762306a36Sopenharmony_ci{ 13862306a36Sopenharmony_ci unsigned long flags; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci spin_lock_irqsave(&dev->config_lock, flags); 14162306a36Sopenharmony_ci __virtio_config_changed(dev); 14262306a36Sopenharmony_ci spin_unlock_irqrestore(&dev->config_lock, flags); 14362306a36Sopenharmony_ci} 14462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(virtio_config_changed); 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_cistatic void virtio_config_disable(struct virtio_device *dev) 14762306a36Sopenharmony_ci{ 14862306a36Sopenharmony_ci spin_lock_irq(&dev->config_lock); 14962306a36Sopenharmony_ci dev->config_enabled = false; 15062306a36Sopenharmony_ci spin_unlock_irq(&dev->config_lock); 15162306a36Sopenharmony_ci} 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_cistatic void virtio_config_enable(struct virtio_device *dev) 15462306a36Sopenharmony_ci{ 15562306a36Sopenharmony_ci spin_lock_irq(&dev->config_lock); 15662306a36Sopenharmony_ci dev->config_enabled = true; 15762306a36Sopenharmony_ci if (dev->config_change_pending) 15862306a36Sopenharmony_ci __virtio_config_changed(dev); 15962306a36Sopenharmony_ci dev->config_change_pending = false; 16062306a36Sopenharmony_ci spin_unlock_irq(&dev->config_lock); 16162306a36Sopenharmony_ci} 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_civoid virtio_add_status(struct virtio_device *dev, unsigned int status) 16462306a36Sopenharmony_ci{ 16562306a36Sopenharmony_ci might_sleep(); 16662306a36Sopenharmony_ci dev->config->set_status(dev, dev->config->get_status(dev) | status); 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(virtio_add_status); 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci/* Do some validation, then set FEATURES_OK */ 17162306a36Sopenharmony_cistatic int virtio_features_ok(struct virtio_device *dev) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci unsigned int status; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci might_sleep(); 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci if (virtio_check_mem_acc_cb(dev)) { 17862306a36Sopenharmony_ci if (!virtio_has_feature(dev, VIRTIO_F_VERSION_1)) { 17962306a36Sopenharmony_ci dev_warn(&dev->dev, 18062306a36Sopenharmony_ci "device must provide VIRTIO_F_VERSION_1\n"); 18162306a36Sopenharmony_ci return -ENODEV; 18262306a36Sopenharmony_ci } 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci if (!virtio_has_feature(dev, VIRTIO_F_ACCESS_PLATFORM)) { 18562306a36Sopenharmony_ci dev_warn(&dev->dev, 18662306a36Sopenharmony_ci "device must provide VIRTIO_F_ACCESS_PLATFORM\n"); 18762306a36Sopenharmony_ci return -ENODEV; 18862306a36Sopenharmony_ci } 18962306a36Sopenharmony_ci } 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci if (!virtio_has_feature(dev, VIRTIO_F_VERSION_1)) 19262306a36Sopenharmony_ci return 0; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci virtio_add_status(dev, VIRTIO_CONFIG_S_FEATURES_OK); 19562306a36Sopenharmony_ci status = dev->config->get_status(dev); 19662306a36Sopenharmony_ci if (!(status & VIRTIO_CONFIG_S_FEATURES_OK)) { 19762306a36Sopenharmony_ci dev_err(&dev->dev, "virtio: device refuses features: %x\n", 19862306a36Sopenharmony_ci status); 19962306a36Sopenharmony_ci return -ENODEV; 20062306a36Sopenharmony_ci } 20162306a36Sopenharmony_ci return 0; 20262306a36Sopenharmony_ci} 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci/** 20562306a36Sopenharmony_ci * virtio_reset_device - quiesce device for removal 20662306a36Sopenharmony_ci * @dev: the device to reset 20762306a36Sopenharmony_ci * 20862306a36Sopenharmony_ci * Prevents device from sending interrupts and accessing memory. 20962306a36Sopenharmony_ci * 21062306a36Sopenharmony_ci * Generally used for cleanup during driver / device removal. 21162306a36Sopenharmony_ci * 21262306a36Sopenharmony_ci * Once this has been invoked, caller must ensure that 21362306a36Sopenharmony_ci * virtqueue_notify / virtqueue_kick are not in progress. 21462306a36Sopenharmony_ci * 21562306a36Sopenharmony_ci * Note: this guarantees that vq callbacks are not in progress, however caller 21662306a36Sopenharmony_ci * is responsible for preventing access from other contexts, such as a system 21762306a36Sopenharmony_ci * call/workqueue/bh. Invoking virtio_break_device then flushing any such 21862306a36Sopenharmony_ci * contexts is one way to handle that. 21962306a36Sopenharmony_ci * */ 22062306a36Sopenharmony_civoid virtio_reset_device(struct virtio_device *dev) 22162306a36Sopenharmony_ci{ 22262306a36Sopenharmony_ci#ifdef CONFIG_VIRTIO_HARDEN_NOTIFICATION 22362306a36Sopenharmony_ci /* 22462306a36Sopenharmony_ci * The below virtio_synchronize_cbs() guarantees that any 22562306a36Sopenharmony_ci * interrupt for this line arriving after 22662306a36Sopenharmony_ci * virtio_synchronize_vqs() has completed is guaranteed to see 22762306a36Sopenharmony_ci * vq->broken as true. 22862306a36Sopenharmony_ci */ 22962306a36Sopenharmony_ci virtio_break_device(dev); 23062306a36Sopenharmony_ci virtio_synchronize_cbs(dev); 23162306a36Sopenharmony_ci#endif 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci dev->config->reset(dev); 23462306a36Sopenharmony_ci} 23562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(virtio_reset_device); 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_cistatic int virtio_dev_probe(struct device *_d) 23862306a36Sopenharmony_ci{ 23962306a36Sopenharmony_ci int err, i; 24062306a36Sopenharmony_ci struct virtio_device *dev = dev_to_virtio(_d); 24162306a36Sopenharmony_ci struct virtio_driver *drv = drv_to_virtio(dev->dev.driver); 24262306a36Sopenharmony_ci u64 device_features; 24362306a36Sopenharmony_ci u64 driver_features; 24462306a36Sopenharmony_ci u64 driver_features_legacy; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci /* We have a driver! */ 24762306a36Sopenharmony_ci virtio_add_status(dev, VIRTIO_CONFIG_S_DRIVER); 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci /* Figure out what features the device supports. */ 25062306a36Sopenharmony_ci device_features = dev->config->get_features(dev); 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci /* Figure out what features the driver supports. */ 25362306a36Sopenharmony_ci driver_features = 0; 25462306a36Sopenharmony_ci for (i = 0; i < drv->feature_table_size; i++) { 25562306a36Sopenharmony_ci unsigned int f = drv->feature_table[i]; 25662306a36Sopenharmony_ci BUG_ON(f >= 64); 25762306a36Sopenharmony_ci driver_features |= (1ULL << f); 25862306a36Sopenharmony_ci } 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci /* Some drivers have a separate feature table for virtio v1.0 */ 26162306a36Sopenharmony_ci if (drv->feature_table_legacy) { 26262306a36Sopenharmony_ci driver_features_legacy = 0; 26362306a36Sopenharmony_ci for (i = 0; i < drv->feature_table_size_legacy; i++) { 26462306a36Sopenharmony_ci unsigned int f = drv->feature_table_legacy[i]; 26562306a36Sopenharmony_ci BUG_ON(f >= 64); 26662306a36Sopenharmony_ci driver_features_legacy |= (1ULL << f); 26762306a36Sopenharmony_ci } 26862306a36Sopenharmony_ci } else { 26962306a36Sopenharmony_ci driver_features_legacy = driver_features; 27062306a36Sopenharmony_ci } 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci if (device_features & (1ULL << VIRTIO_F_VERSION_1)) 27362306a36Sopenharmony_ci dev->features = driver_features & device_features; 27462306a36Sopenharmony_ci else 27562306a36Sopenharmony_ci dev->features = driver_features_legacy & device_features; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci /* Transport features always preserved to pass to finalize_features. */ 27862306a36Sopenharmony_ci for (i = VIRTIO_TRANSPORT_F_START; i < VIRTIO_TRANSPORT_F_END; i++) 27962306a36Sopenharmony_ci if (device_features & (1ULL << i)) 28062306a36Sopenharmony_ci __virtio_set_bit(dev, i); 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci err = dev->config->finalize_features(dev); 28362306a36Sopenharmony_ci if (err) 28462306a36Sopenharmony_ci goto err; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci if (drv->validate) { 28762306a36Sopenharmony_ci u64 features = dev->features; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci err = drv->validate(dev); 29062306a36Sopenharmony_ci if (err) 29162306a36Sopenharmony_ci goto err; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci /* Did validation change any features? Then write them again. */ 29462306a36Sopenharmony_ci if (features != dev->features) { 29562306a36Sopenharmony_ci err = dev->config->finalize_features(dev); 29662306a36Sopenharmony_ci if (err) 29762306a36Sopenharmony_ci goto err; 29862306a36Sopenharmony_ci } 29962306a36Sopenharmony_ci } 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci err = virtio_features_ok(dev); 30262306a36Sopenharmony_ci if (err) 30362306a36Sopenharmony_ci goto err; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci err = drv->probe(dev); 30662306a36Sopenharmony_ci if (err) 30762306a36Sopenharmony_ci goto err; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci /* If probe didn't do it, mark device DRIVER_OK ourselves. */ 31062306a36Sopenharmony_ci if (!(dev->config->get_status(dev) & VIRTIO_CONFIG_S_DRIVER_OK)) 31162306a36Sopenharmony_ci virtio_device_ready(dev); 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci if (drv->scan) 31462306a36Sopenharmony_ci drv->scan(dev); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci virtio_config_enable(dev); 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci return 0; 31962306a36Sopenharmony_cierr: 32062306a36Sopenharmony_ci virtio_add_status(dev, VIRTIO_CONFIG_S_FAILED); 32162306a36Sopenharmony_ci return err; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci} 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_cistatic void virtio_dev_remove(struct device *_d) 32662306a36Sopenharmony_ci{ 32762306a36Sopenharmony_ci struct virtio_device *dev = dev_to_virtio(_d); 32862306a36Sopenharmony_ci struct virtio_driver *drv = drv_to_virtio(dev->dev.driver); 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci virtio_config_disable(dev); 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci drv->remove(dev); 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci /* Driver should have reset device. */ 33562306a36Sopenharmony_ci WARN_ON_ONCE(dev->config->get_status(dev)); 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci /* Acknowledge the device's existence again. */ 33862306a36Sopenharmony_ci virtio_add_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE); 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci of_node_put(dev->dev.of_node); 34162306a36Sopenharmony_ci} 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_cistatic struct bus_type virtio_bus = { 34462306a36Sopenharmony_ci .name = "virtio", 34562306a36Sopenharmony_ci .match = virtio_dev_match, 34662306a36Sopenharmony_ci .dev_groups = virtio_dev_groups, 34762306a36Sopenharmony_ci .uevent = virtio_uevent, 34862306a36Sopenharmony_ci .probe = virtio_dev_probe, 34962306a36Sopenharmony_ci .remove = virtio_dev_remove, 35062306a36Sopenharmony_ci}; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ciint register_virtio_driver(struct virtio_driver *driver) 35362306a36Sopenharmony_ci{ 35462306a36Sopenharmony_ci /* Catch this early. */ 35562306a36Sopenharmony_ci BUG_ON(driver->feature_table_size && !driver->feature_table); 35662306a36Sopenharmony_ci driver->driver.bus = &virtio_bus; 35762306a36Sopenharmony_ci return driver_register(&driver->driver); 35862306a36Sopenharmony_ci} 35962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(register_virtio_driver); 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_civoid unregister_virtio_driver(struct virtio_driver *driver) 36262306a36Sopenharmony_ci{ 36362306a36Sopenharmony_ci driver_unregister(&driver->driver); 36462306a36Sopenharmony_ci} 36562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(unregister_virtio_driver); 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_cistatic int virtio_device_of_init(struct virtio_device *dev) 36862306a36Sopenharmony_ci{ 36962306a36Sopenharmony_ci struct device_node *np, *pnode = dev_of_node(dev->dev.parent); 37062306a36Sopenharmony_ci char compat[] = "virtio,deviceXXXXXXXX"; 37162306a36Sopenharmony_ci int ret, count; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci if (!pnode) 37462306a36Sopenharmony_ci return 0; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci count = of_get_available_child_count(pnode); 37762306a36Sopenharmony_ci if (!count) 37862306a36Sopenharmony_ci return 0; 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci /* There can be only 1 child node */ 38162306a36Sopenharmony_ci if (WARN_ON(count > 1)) 38262306a36Sopenharmony_ci return -EINVAL; 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci np = of_get_next_available_child(pnode, NULL); 38562306a36Sopenharmony_ci if (WARN_ON(!np)) 38662306a36Sopenharmony_ci return -ENODEV; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci ret = snprintf(compat, sizeof(compat), "virtio,device%x", dev->id.device); 38962306a36Sopenharmony_ci BUG_ON(ret >= sizeof(compat)); 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci /* 39262306a36Sopenharmony_ci * On powerpc/pseries virtio devices are PCI devices so PCI 39362306a36Sopenharmony_ci * vendor/device ids play the role of the "compatible" property. 39462306a36Sopenharmony_ci * Simply don't init of_node in this case. 39562306a36Sopenharmony_ci */ 39662306a36Sopenharmony_ci if (!of_device_is_compatible(np, compat)) { 39762306a36Sopenharmony_ci ret = 0; 39862306a36Sopenharmony_ci goto out; 39962306a36Sopenharmony_ci } 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci dev->dev.of_node = np; 40262306a36Sopenharmony_ci return 0; 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ciout: 40562306a36Sopenharmony_ci of_node_put(np); 40662306a36Sopenharmony_ci return ret; 40762306a36Sopenharmony_ci} 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci/** 41062306a36Sopenharmony_ci * register_virtio_device - register virtio device 41162306a36Sopenharmony_ci * @dev : virtio device to be registered 41262306a36Sopenharmony_ci * 41362306a36Sopenharmony_ci * On error, the caller must call put_device on &@dev->dev (and not kfree), 41462306a36Sopenharmony_ci * as another code path may have obtained a reference to @dev. 41562306a36Sopenharmony_ci * 41662306a36Sopenharmony_ci * Returns: 0 on suceess, -error on failure 41762306a36Sopenharmony_ci */ 41862306a36Sopenharmony_ciint register_virtio_device(struct virtio_device *dev) 41962306a36Sopenharmony_ci{ 42062306a36Sopenharmony_ci int err; 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci dev->dev.bus = &virtio_bus; 42362306a36Sopenharmony_ci device_initialize(&dev->dev); 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci /* Assign a unique device index and hence name. */ 42662306a36Sopenharmony_ci err = ida_alloc(&virtio_index_ida, GFP_KERNEL); 42762306a36Sopenharmony_ci if (err < 0) 42862306a36Sopenharmony_ci goto out; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci dev->index = err; 43162306a36Sopenharmony_ci err = dev_set_name(&dev->dev, "virtio%u", dev->index); 43262306a36Sopenharmony_ci if (err) 43362306a36Sopenharmony_ci goto out_ida_remove; 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci err = virtio_device_of_init(dev); 43662306a36Sopenharmony_ci if (err) 43762306a36Sopenharmony_ci goto out_ida_remove; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci spin_lock_init(&dev->config_lock); 44062306a36Sopenharmony_ci dev->config_enabled = false; 44162306a36Sopenharmony_ci dev->config_change_pending = false; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci INIT_LIST_HEAD(&dev->vqs); 44462306a36Sopenharmony_ci spin_lock_init(&dev->vqs_list_lock); 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci /* We always start by resetting the device, in case a previous 44762306a36Sopenharmony_ci * driver messed it up. This also tests that code path a little. */ 44862306a36Sopenharmony_ci virtio_reset_device(dev); 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci /* Acknowledge that we've seen the device. */ 45162306a36Sopenharmony_ci virtio_add_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE); 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci /* 45462306a36Sopenharmony_ci * device_add() causes the bus infrastructure to look for a matching 45562306a36Sopenharmony_ci * driver. 45662306a36Sopenharmony_ci */ 45762306a36Sopenharmony_ci err = device_add(&dev->dev); 45862306a36Sopenharmony_ci if (err) 45962306a36Sopenharmony_ci goto out_of_node_put; 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci return 0; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ciout_of_node_put: 46462306a36Sopenharmony_ci of_node_put(dev->dev.of_node); 46562306a36Sopenharmony_ciout_ida_remove: 46662306a36Sopenharmony_ci ida_free(&virtio_index_ida, dev->index); 46762306a36Sopenharmony_ciout: 46862306a36Sopenharmony_ci virtio_add_status(dev, VIRTIO_CONFIG_S_FAILED); 46962306a36Sopenharmony_ci return err; 47062306a36Sopenharmony_ci} 47162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(register_virtio_device); 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_cibool is_virtio_device(struct device *dev) 47462306a36Sopenharmony_ci{ 47562306a36Sopenharmony_ci return dev->bus == &virtio_bus; 47662306a36Sopenharmony_ci} 47762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(is_virtio_device); 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_civoid unregister_virtio_device(struct virtio_device *dev) 48062306a36Sopenharmony_ci{ 48162306a36Sopenharmony_ci int index = dev->index; /* save for after device release */ 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci device_unregister(&dev->dev); 48462306a36Sopenharmony_ci ida_free(&virtio_index_ida, index); 48562306a36Sopenharmony_ci} 48662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(unregister_virtio_device); 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 48962306a36Sopenharmony_ciint virtio_device_freeze(struct virtio_device *dev) 49062306a36Sopenharmony_ci{ 49162306a36Sopenharmony_ci struct virtio_driver *drv = drv_to_virtio(dev->dev.driver); 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci virtio_config_disable(dev); 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci dev->failed = dev->config->get_status(dev) & VIRTIO_CONFIG_S_FAILED; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci if (drv && drv->freeze) 49862306a36Sopenharmony_ci return drv->freeze(dev); 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci return 0; 50162306a36Sopenharmony_ci} 50262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(virtio_device_freeze); 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ciint virtio_device_restore(struct virtio_device *dev) 50562306a36Sopenharmony_ci{ 50662306a36Sopenharmony_ci struct virtio_driver *drv = drv_to_virtio(dev->dev.driver); 50762306a36Sopenharmony_ci int ret; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci /* We always start by resetting the device, in case a previous 51062306a36Sopenharmony_ci * driver messed it up. */ 51162306a36Sopenharmony_ci virtio_reset_device(dev); 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci /* Acknowledge that we've seen the device. */ 51462306a36Sopenharmony_ci virtio_add_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE); 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci /* Maybe driver failed before freeze. 51762306a36Sopenharmony_ci * Restore the failed status, for debugging. */ 51862306a36Sopenharmony_ci if (dev->failed) 51962306a36Sopenharmony_ci virtio_add_status(dev, VIRTIO_CONFIG_S_FAILED); 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci if (!drv) 52262306a36Sopenharmony_ci return 0; 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci /* We have a driver! */ 52562306a36Sopenharmony_ci virtio_add_status(dev, VIRTIO_CONFIG_S_DRIVER); 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci ret = dev->config->finalize_features(dev); 52862306a36Sopenharmony_ci if (ret) 52962306a36Sopenharmony_ci goto err; 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci ret = virtio_features_ok(dev); 53262306a36Sopenharmony_ci if (ret) 53362306a36Sopenharmony_ci goto err; 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci if (drv->restore) { 53662306a36Sopenharmony_ci ret = drv->restore(dev); 53762306a36Sopenharmony_ci if (ret) 53862306a36Sopenharmony_ci goto err; 53962306a36Sopenharmony_ci } 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci /* If restore didn't do it, mark device DRIVER_OK ourselves. */ 54262306a36Sopenharmony_ci if (!(dev->config->get_status(dev) & VIRTIO_CONFIG_S_DRIVER_OK)) 54362306a36Sopenharmony_ci virtio_device_ready(dev); 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci virtio_config_enable(dev); 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci return 0; 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_cierr: 55062306a36Sopenharmony_ci virtio_add_status(dev, VIRTIO_CONFIG_S_FAILED); 55162306a36Sopenharmony_ci return ret; 55262306a36Sopenharmony_ci} 55362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(virtio_device_restore); 55462306a36Sopenharmony_ci#endif 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_cistatic int virtio_init(void) 55762306a36Sopenharmony_ci{ 55862306a36Sopenharmony_ci if (bus_register(&virtio_bus) != 0) 55962306a36Sopenharmony_ci panic("virtio bus registration failed"); 56062306a36Sopenharmony_ci return 0; 56162306a36Sopenharmony_ci} 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_cistatic void __exit virtio_exit(void) 56462306a36Sopenharmony_ci{ 56562306a36Sopenharmony_ci bus_unregister(&virtio_bus); 56662306a36Sopenharmony_ci ida_destroy(&virtio_index_ida); 56762306a36Sopenharmony_ci} 56862306a36Sopenharmony_cicore_initcall(virtio_init); 56962306a36Sopenharmony_cimodule_exit(virtio_exit); 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 572