mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	virt-pci: add platform bus support
This driver registers PCI busses, but the underlying virtio protocol could just as easily be used to provide a platform bus instead. If the virtio device node in the devicetree indicates that it's compatible with simple-bus, register platform devices instead of handling it as a PCI bus. Only one platform bus is allowed and the logic MMIO region for the platform bus is placed at an arbitrarily-chosen address away from the PCI region. Signed-off-by: Vincent Whitchurch <vincent.whitchurch@axis.com> Signed-off-by: Richard Weinberger <richard@nod.at>
This commit is contained in:
		
							parent
							
								
									935f8f7a01
								
							
						
					
					
						commit
						522c532c4f
					
				
					 1 changed files with 91 additions and 0 deletions
				
			
		| 
						 | 
				
			
			@ -8,6 +8,7 @@
 | 
			
		|||
#include <linux/virtio.h>
 | 
			
		||||
#include <linux/virtio_config.h>
 | 
			
		||||
#include <linux/logic_iomem.h>
 | 
			
		||||
#include <linux/of_platform.h>
 | 
			
		||||
#include <linux/irqdomain.h>
 | 
			
		||||
#include <linux/virtio_pcidev.h>
 | 
			
		||||
#include <linux/virtio-uml.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -39,6 +40,8 @@ struct um_pci_device {
 | 
			
		|||
	unsigned long status;
 | 
			
		||||
 | 
			
		||||
	int irq;
 | 
			
		||||
 | 
			
		||||
	bool platform;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct um_pci_device_reg {
 | 
			
		||||
| 
						 | 
				
			
			@ -48,6 +51,7 @@ struct um_pci_device_reg {
 | 
			
		|||
 | 
			
		||||
static struct pci_host_bridge *bridge;
 | 
			
		||||
static DEFINE_MUTEX(um_pci_mtx);
 | 
			
		||||
static struct um_pci_device *um_pci_platform_device;
 | 
			
		||||
static struct um_pci_device_reg um_pci_devices[MAX_DEVICES];
 | 
			
		||||
static struct fwnode_handle *um_pci_fwnode;
 | 
			
		||||
static struct irq_domain *um_pci_inner_domain;
 | 
			
		||||
| 
						 | 
				
			
			@ -481,6 +485,9 @@ static void um_pci_handle_irq_message(struct virtqueue *vq,
 | 
			
		|||
	struct virtio_device *vdev = vq->vdev;
 | 
			
		||||
	struct um_pci_device *dev = vdev->priv;
 | 
			
		||||
 | 
			
		||||
	if (!dev->irq)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	/* we should properly chain interrupts, but on ARCH=um we don't care */
 | 
			
		||||
 | 
			
		||||
	switch (msg->op) {
 | 
			
		||||
| 
						 | 
				
			
			@ -581,6 +588,55 @@ static int um_pci_init_vqs(struct um_pci_device *dev)
 | 
			
		|||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void __um_pci_virtio_platform_remove(struct virtio_device *vdev,
 | 
			
		||||
					    struct um_pci_device *dev)
 | 
			
		||||
{
 | 
			
		||||
	virtio_reset_device(vdev);
 | 
			
		||||
	vdev->config->del_vqs(vdev);
 | 
			
		||||
 | 
			
		||||
	mutex_lock(&um_pci_mtx);
 | 
			
		||||
	um_pci_platform_device = NULL;
 | 
			
		||||
	mutex_unlock(&um_pci_mtx);
 | 
			
		||||
 | 
			
		||||
	kfree(dev);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int um_pci_virtio_platform_probe(struct virtio_device *vdev,
 | 
			
		||||
					struct um_pci_device *dev)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	dev->platform = true;
 | 
			
		||||
 | 
			
		||||
	mutex_lock(&um_pci_mtx);
 | 
			
		||||
 | 
			
		||||
	if (um_pci_platform_device) {
 | 
			
		||||
		mutex_unlock(&um_pci_mtx);
 | 
			
		||||
		ret = -EBUSY;
 | 
			
		||||
		goto out_free;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ret = um_pci_init_vqs(dev);
 | 
			
		||||
	if (ret) {
 | 
			
		||||
		mutex_unlock(&um_pci_mtx);
 | 
			
		||||
		goto out_free;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	um_pci_platform_device = dev;
 | 
			
		||||
 | 
			
		||||
	mutex_unlock(&um_pci_mtx);
 | 
			
		||||
 | 
			
		||||
	ret = of_platform_default_populate(vdev->dev.of_node, NULL, &vdev->dev);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		__um_pci_virtio_platform_remove(vdev, dev);
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
 | 
			
		||||
out_free:
 | 
			
		||||
	kfree(dev);
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int um_pci_virtio_probe(struct virtio_device *vdev)
 | 
			
		||||
{
 | 
			
		||||
	struct um_pci_device *dev;
 | 
			
		||||
| 
						 | 
				
			
			@ -594,6 +650,9 @@ static int um_pci_virtio_probe(struct virtio_device *vdev)
 | 
			
		|||
	dev->vdev = vdev;
 | 
			
		||||
	vdev->priv = dev;
 | 
			
		||||
 | 
			
		||||
	if (of_device_is_compatible(vdev->dev.of_node, "simple-bus"))
 | 
			
		||||
		return um_pci_virtio_platform_probe(vdev, dev);
 | 
			
		||||
 | 
			
		||||
	mutex_lock(&um_pci_mtx);
 | 
			
		||||
	for (i = 0; i < MAX_DEVICES; i++) {
 | 
			
		||||
		if (um_pci_devices[i].dev)
 | 
			
		||||
| 
						 | 
				
			
			@ -643,6 +702,12 @@ static void um_pci_virtio_remove(struct virtio_device *vdev)
 | 
			
		|||
	struct um_pci_device *dev = vdev->priv;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	if (dev->platform) {
 | 
			
		||||
		of_platform_depopulate(&vdev->dev);
 | 
			
		||||
		__um_pci_virtio_platform_remove(vdev, dev);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
        /* Stop all virtqueues */
 | 
			
		||||
        virtio_reset_device(vdev);
 | 
			
		||||
        vdev->config->del_vqs(vdev);
 | 
			
		||||
| 
						 | 
				
			
			@ -880,6 +945,30 @@ void *pci_root_bus_fwnode(struct pci_bus *bus)
 | 
			
		|||
	return um_pci_fwnode;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static long um_pci_map_platform(unsigned long offset, size_t size,
 | 
			
		||||
				const struct logic_iomem_ops **ops,
 | 
			
		||||
				void **priv)
 | 
			
		||||
{
 | 
			
		||||
	if (!um_pci_platform_device)
 | 
			
		||||
		return -ENOENT;
 | 
			
		||||
 | 
			
		||||
	*ops = &um_pci_device_bar_ops;
 | 
			
		||||
	*priv = &um_pci_platform_device->resptr[0];
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const struct logic_iomem_region_ops um_pci_platform_ops = {
 | 
			
		||||
	.map = um_pci_map_platform,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct resource virt_platform_resource = {
 | 
			
		||||
	.name = "platform",
 | 
			
		||||
	.start = 0x10000000,
 | 
			
		||||
	.end = 0x1fffffff,
 | 
			
		||||
	.flags = IORESOURCE_MEM,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int __init um_pci_init(void)
 | 
			
		||||
{
 | 
			
		||||
	int err, i;
 | 
			
		||||
| 
						 | 
				
			
			@ -888,6 +977,8 @@ static int __init um_pci_init(void)
 | 
			
		|||
				       &um_pci_cfgspace_ops));
 | 
			
		||||
	WARN_ON(logic_iomem_add_region(&virt_iomem_resource,
 | 
			
		||||
				       &um_pci_iomem_ops));
 | 
			
		||||
	WARN_ON(logic_iomem_add_region(&virt_platform_resource,
 | 
			
		||||
				       &um_pci_platform_ops));
 | 
			
		||||
 | 
			
		||||
	if (WARN(CONFIG_UML_PCI_OVER_VIRTIO_DEVICE_ID < 0,
 | 
			
		||||
		 "No virtio device ID configured for PCI - no PCI support\n"))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue