diff options
Diffstat (limited to 'arch/x86/pci/xen.c')
| -rw-r--r-- | arch/x86/pci/xen.c | 96 | 
1 files changed, 91 insertions, 5 deletions
diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c index e37b407a0ee..8214724ce54 100644 --- a/arch/x86/pci/xen.c +++ b/arch/x86/pci/xen.c @@ -108,7 +108,8 @@ static int xen_hvm_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)  		}  		irq = xen_bind_pirq_msi_to_irq(dev, msidesc, pirq, 0,  					       (type == PCI_CAP_ID_MSIX) ? -					       "msi-x" : "msi"); +					       "msi-x" : "msi", +					       DOMID_SELF);  		if (irq < 0)  			goto error;  		dev_dbg(&dev->dev, @@ -148,7 +149,8 @@ static int xen_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)  		irq = xen_bind_pirq_msi_to_irq(dev, msidesc, v[i], 0,  					       (type == PCI_CAP_ID_MSIX) ?  					       "pcifront-msi-x" : -					       "pcifront-msi"); +					       "pcifront-msi", +						DOMID_SELF);  		if (irq < 0)  			goto free;  		i++; @@ -190,9 +192,16 @@ static int xen_initdom_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)  	list_for_each_entry(msidesc, &dev->msi_list, list) {  		struct physdev_map_pirq map_irq; +		domid_t domid; + +		domid = ret = xen_find_device_domain_owner(dev); +		/* N.B. Casting int's -ENODEV to uint16_t results in 0xFFED, +		 * hence check ret value for < 0. */ +		if (ret < 0) +			domid = DOMID_SELF;  		memset(&map_irq, 0, sizeof(map_irq)); -		map_irq.domid = DOMID_SELF; +		map_irq.domid = domid;  		map_irq.type = MAP_PIRQ_TYPE_MSI;  		map_irq.index = -1;  		map_irq.pirq = -1; @@ -215,14 +224,16 @@ static int xen_initdom_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)  		ret = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq, &map_irq);  		if (ret) { -			dev_warn(&dev->dev, "xen map irq failed %d\n", ret); +			dev_warn(&dev->dev, "xen map irq failed %d for %d domain\n", +				 ret, domid);  			goto out;  		}  		ret = xen_bind_pirq_msi_to_irq(dev, msidesc,  					       map_irq.pirq, map_irq.index,  					       (type == PCI_CAP_ID_MSIX) ? -					       "msi-x" : "msi"); +					       "msi-x" : "msi", +						domid);  		if (ret < 0)  			goto out;  	} @@ -461,3 +472,78 @@ void __init xen_setup_pirqs(void)  	}  }  #endif + +#ifdef CONFIG_XEN_DOM0 +struct xen_device_domain_owner { +	domid_t domain; +	struct pci_dev *dev; +	struct list_head list; +}; + +static DEFINE_SPINLOCK(dev_domain_list_spinlock); +static struct list_head dev_domain_list = LIST_HEAD_INIT(dev_domain_list); + +static struct xen_device_domain_owner *find_device(struct pci_dev *dev) +{ +	struct xen_device_domain_owner *owner; + +	list_for_each_entry(owner, &dev_domain_list, list) { +		if (owner->dev == dev) +			return owner; +	} +	return NULL; +} + +int xen_find_device_domain_owner(struct pci_dev *dev) +{ +	struct xen_device_domain_owner *owner; +	int domain = -ENODEV; + +	spin_lock(&dev_domain_list_spinlock); +	owner = find_device(dev); +	if (owner) +		domain = owner->domain; +	spin_unlock(&dev_domain_list_spinlock); +	return domain; +} +EXPORT_SYMBOL_GPL(xen_find_device_domain_owner); + +int xen_register_device_domain_owner(struct pci_dev *dev, uint16_t domain) +{ +	struct xen_device_domain_owner *owner; + +	owner = kzalloc(sizeof(struct xen_device_domain_owner), GFP_KERNEL); +	if (!owner) +		return -ENODEV; + +	spin_lock(&dev_domain_list_spinlock); +	if (find_device(dev)) { +		spin_unlock(&dev_domain_list_spinlock); +		kfree(owner); +		return -EEXIST; +	} +	owner->domain = domain; +	owner->dev = dev; +	list_add_tail(&owner->list, &dev_domain_list); +	spin_unlock(&dev_domain_list_spinlock); +	return 0; +} +EXPORT_SYMBOL_GPL(xen_register_device_domain_owner); + +int xen_unregister_device_domain_owner(struct pci_dev *dev) +{ +	struct xen_device_domain_owner *owner; + +	spin_lock(&dev_domain_list_spinlock); +	owner = find_device(dev); +	if (!owner) { +		spin_unlock(&dev_domain_list_spinlock); +		return -ENODEV; +	} +	list_del(&owner->list); +	spin_unlock(&dev_domain_list_spinlock); +	kfree(owner); +	return 0; +} +EXPORT_SYMBOL_GPL(xen_unregister_device_domain_owner); +#endif  |