Merge branches 'stable/backend.base.v3' and 'stable/gntalloc.v7' of git://git.kernel.org/pub/scm/linux/kernel/git/konrad/xen

* 'stable/backend.base.v3' of git://git.kernel.org/pub/scm/linux/kernel/git/konrad/xen:
  xen/pci: Fix compiler error when CONFIG_XEN_PRIVILEGED_GUEST is not set.
  xen/p2m: Add EXPORT_SYMBOL_GPL to the M2P override functions.
  xen/p2m/m2p/gnttab: Support GNTMAP_host_map in the M2P override.
  xen/irq: The Xen hypervisor cleans up the PIRQs if the other domain forgot.
  xen/irq: Export 'xen_pirq_from_irq' function.
  xen/irq: Add support to check if IRQ line is shared with other domains.
  xen/irq: Check if the PCI device is owned by a domain different than DOMID_SELF.
  xen/pci: Add xen_[find|register|unregister]_device_domain_owner functions.

* 'stable/gntalloc.v7' of git://git.kernel.org/pub/scm/linux/kernel/git/konrad/xen:
  xen/gntdev,gntalloc: Remove unneeded VM flags
This commit is contained in:
Linus Torvalds 2011-05-19 16:14:25 -07:00
commit 5318991645
9 changed files with 208 additions and 31 deletions

View file

@ -47,8 +47,9 @@ extern bool __set_phys_to_machine(unsigned long pfn, unsigned long mfn);
extern unsigned long set_phys_range_identity(unsigned long pfn_s, extern unsigned long set_phys_range_identity(unsigned long pfn_s,
unsigned long pfn_e); unsigned long pfn_e);
extern int m2p_add_override(unsigned long mfn, struct page *page); extern int m2p_add_override(unsigned long mfn, struct page *page,
extern int m2p_remove_override(struct page *page); bool clear_pte);
extern int m2p_remove_override(struct page *page, bool clear_pte);
extern struct page *m2p_find_override(unsigned long mfn); extern struct page *m2p_find_override(unsigned long mfn);
extern unsigned long m2p_find_override_pfn(unsigned long mfn, unsigned long pfn); extern unsigned long m2p_find_override_pfn(unsigned long mfn, unsigned long pfn);

View file

@ -15,10 +15,26 @@ static inline int pci_xen_hvm_init(void)
#endif #endif
#if defined(CONFIG_XEN_DOM0) #if defined(CONFIG_XEN_DOM0)
void __init xen_setup_pirqs(void); void __init xen_setup_pirqs(void);
int xen_find_device_domain_owner(struct pci_dev *dev);
int xen_register_device_domain_owner(struct pci_dev *dev, uint16_t domain);
int xen_unregister_device_domain_owner(struct pci_dev *dev);
#else #else
static inline void __init xen_setup_pirqs(void) static inline void __init xen_setup_pirqs(void)
{ {
} }
static inline int xen_find_device_domain_owner(struct pci_dev *dev)
{
return -1;
}
static inline int xen_register_device_domain_owner(struct pci_dev *dev,
uint16_t domain)
{
return -1;
}
static inline int xen_unregister_device_domain_owner(struct pci_dev *dev)
{
return -1;
}
#endif #endif
#if defined(CONFIG_PCI_MSI) #if defined(CONFIG_PCI_MSI)

View file

@ -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, irq = xen_bind_pirq_msi_to_irq(dev, msidesc, pirq, 0,
(type == PCI_CAP_ID_MSIX) ? (type == PCI_CAP_ID_MSIX) ?
"msi-x" : "msi"); "msi-x" : "msi",
DOMID_SELF);
if (irq < 0) if (irq < 0)
goto error; goto error;
dev_dbg(&dev->dev, 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, irq = xen_bind_pirq_msi_to_irq(dev, msidesc, v[i], 0,
(type == PCI_CAP_ID_MSIX) ? (type == PCI_CAP_ID_MSIX) ?
"pcifront-msi-x" : "pcifront-msi-x" :
"pcifront-msi"); "pcifront-msi",
DOMID_SELF);
if (irq < 0) if (irq < 0)
goto free; goto free;
i++; 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) { list_for_each_entry(msidesc, &dev->msi_list, list) {
struct physdev_map_pirq map_irq; 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)); 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.type = MAP_PIRQ_TYPE_MSI;
map_irq.index = -1; map_irq.index = -1;
map_irq.pirq = -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); ret = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq, &map_irq);
if (ret) { 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; goto out;
} }
ret = xen_bind_pirq_msi_to_irq(dev, msidesc, ret = xen_bind_pirq_msi_to_irq(dev, msidesc,
map_irq.pirq, map_irq.index, map_irq.pirq, map_irq.index,
(type == PCI_CAP_ID_MSIX) ? (type == PCI_CAP_ID_MSIX) ?
"msi-x" : "msi"); "msi-x" : "msi",
domid);
if (ret < 0) if (ret < 0)
goto out; goto out;
} }
@ -461,3 +472,78 @@ void __init xen_setup_pirqs(void)
} }
} }
#endif #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

View file

@ -650,7 +650,7 @@ static unsigned long mfn_hash(unsigned long mfn)
} }
/* Add an MFN override for a particular page */ /* Add an MFN override for a particular page */
int m2p_add_override(unsigned long mfn, struct page *page) int m2p_add_override(unsigned long mfn, struct page *page, bool clear_pte)
{ {
unsigned long flags; unsigned long flags;
unsigned long pfn; unsigned long pfn;
@ -662,7 +662,6 @@ int m2p_add_override(unsigned long mfn, struct page *page)
if (!PageHighMem(page)) { if (!PageHighMem(page)) {
address = (unsigned long)__va(pfn << PAGE_SHIFT); address = (unsigned long)__va(pfn << PAGE_SHIFT);
ptep = lookup_address(address, &level); ptep = lookup_address(address, &level);
if (WARN(ptep == NULL || level != PG_LEVEL_4K, if (WARN(ptep == NULL || level != PG_LEVEL_4K,
"m2p_add_override: pfn %lx not mapped", pfn)) "m2p_add_override: pfn %lx not mapped", pfn))
return -EINVAL; return -EINVAL;
@ -674,18 +673,17 @@ int m2p_add_override(unsigned long mfn, struct page *page)
if (unlikely(!set_phys_to_machine(pfn, FOREIGN_FRAME(mfn)))) if (unlikely(!set_phys_to_machine(pfn, FOREIGN_FRAME(mfn))))
return -ENOMEM; return -ENOMEM;
if (!PageHighMem(page)) if (clear_pte && !PageHighMem(page))
/* Just zap old mapping for now */ /* Just zap old mapping for now */
pte_clear(&init_mm, address, ptep); pte_clear(&init_mm, address, ptep);
spin_lock_irqsave(&m2p_override_lock, flags); spin_lock_irqsave(&m2p_override_lock, flags);
list_add(&page->lru, &m2p_overrides[mfn_hash(mfn)]); list_add(&page->lru, &m2p_overrides[mfn_hash(mfn)]);
spin_unlock_irqrestore(&m2p_override_lock, flags); spin_unlock_irqrestore(&m2p_override_lock, flags);
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(m2p_add_override);
int m2p_remove_override(struct page *page) int m2p_remove_override(struct page *page, bool clear_pte)
{ {
unsigned long flags; unsigned long flags;
unsigned long mfn; unsigned long mfn;
@ -713,7 +711,7 @@ int m2p_remove_override(struct page *page)
spin_unlock_irqrestore(&m2p_override_lock, flags); spin_unlock_irqrestore(&m2p_override_lock, flags);
set_phys_to_machine(pfn, page->index); set_phys_to_machine(pfn, page->index);
if (!PageHighMem(page)) if (clear_pte && !PageHighMem(page))
set_pte_at(&init_mm, address, ptep, set_pte_at(&init_mm, address, ptep,
pfn_pte(pfn, PAGE_KERNEL)); pfn_pte(pfn, PAGE_KERNEL));
/* No tlb flush necessary because the caller already /* No tlb flush necessary because the caller already
@ -721,6 +719,7 @@ int m2p_remove_override(struct page *page)
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(m2p_remove_override);
struct page *m2p_find_override(unsigned long mfn) struct page *m2p_find_override(unsigned long mfn)
{ {

View file

@ -101,6 +101,7 @@ struct irq_info
unsigned short gsi; unsigned short gsi;
unsigned char vector; unsigned char vector;
unsigned char flags; unsigned char flags;
uint16_t domid;
} pirq; } pirq;
} u; } u;
}; };
@ -184,6 +185,7 @@ static void xen_irq_info_pirq_init(unsigned irq,
unsigned short pirq, unsigned short pirq,
unsigned short gsi, unsigned short gsi,
unsigned short vector, unsigned short vector,
uint16_t domid,
unsigned char flags) unsigned char flags)
{ {
struct irq_info *info = info_for_irq(irq); struct irq_info *info = info_for_irq(irq);
@ -193,6 +195,7 @@ static void xen_irq_info_pirq_init(unsigned irq,
info->u.pirq.pirq = pirq; info->u.pirq.pirq = pirq;
info->u.pirq.gsi = gsi; info->u.pirq.gsi = gsi;
info->u.pirq.vector = vector; info->u.pirq.vector = vector;
info->u.pirq.domid = domid;
info->u.pirq.flags = flags; info->u.pirq.flags = flags;
} }
@ -655,7 +658,7 @@ int xen_bind_pirq_gsi_to_irq(unsigned gsi,
goto out; goto out;
} }
xen_irq_info_pirq_init(irq, 0, pirq, gsi, irq_op.vector, xen_irq_info_pirq_init(irq, 0, pirq, gsi, irq_op.vector, DOMID_SELF,
shareable ? PIRQ_SHAREABLE : 0); shareable ? PIRQ_SHAREABLE : 0);
out: out:
@ -680,7 +683,8 @@ int xen_allocate_pirq_msi(struct pci_dev *dev, struct msi_desc *msidesc)
} }
int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc *msidesc, int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc *msidesc,
int pirq, int vector, const char *name) int pirq, int vector, const char *name,
domid_t domid)
{ {
int irq, ret; int irq, ret;
@ -693,7 +697,7 @@ int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc *msidesc,
irq_set_chip_and_handler_name(irq, &xen_pirq_chip, handle_level_irq, irq_set_chip_and_handler_name(irq, &xen_pirq_chip, handle_level_irq,
name); name);
xen_irq_info_pirq_init(irq, 0, pirq, 0, vector, 0); xen_irq_info_pirq_init(irq, 0, pirq, 0, vector, domid, 0);
ret = irq_set_msi_desc(irq, msidesc); ret = irq_set_msi_desc(irq, msidesc);
if (ret < 0) if (ret < 0)
goto error_irq; goto error_irq;
@ -722,9 +726,16 @@ int xen_destroy_irq(int irq)
if (xen_initial_domain()) { if (xen_initial_domain()) {
unmap_irq.pirq = info->u.pirq.pirq; unmap_irq.pirq = info->u.pirq.pirq;
unmap_irq.domid = DOMID_SELF; unmap_irq.domid = info->u.pirq.domid;
rc = HYPERVISOR_physdev_op(PHYSDEVOP_unmap_pirq, &unmap_irq); rc = HYPERVISOR_physdev_op(PHYSDEVOP_unmap_pirq, &unmap_irq);
if (rc) { /* If another domain quits without making the pci_disable_msix
* call, the Xen hypervisor takes care of freeing the PIRQs
* (free_domain_pirqs).
*/
if ((rc == -ESRCH && info->u.pirq.domid != DOMID_SELF))
printk(KERN_INFO "domain %d does not have %d anymore\n",
info->u.pirq.domid, info->u.pirq.pirq);
else if (rc) {
printk(KERN_WARNING "unmap irq failed %d\n", rc); printk(KERN_WARNING "unmap irq failed %d\n", rc);
goto out; goto out;
} }
@ -759,6 +770,12 @@ int xen_irq_from_pirq(unsigned pirq)
return irq; return irq;
} }
int xen_pirq_from_irq(unsigned irq)
{
return pirq_from_irq(irq);
}
EXPORT_SYMBOL_GPL(xen_pirq_from_irq);
int bind_evtchn_to_irq(unsigned int evtchn) int bind_evtchn_to_irq(unsigned int evtchn)
{ {
int irq; int irq;
@ -1502,6 +1519,18 @@ void xen_poll_irq(int irq)
xen_poll_irq_timeout(irq, 0 /* no timeout */); xen_poll_irq_timeout(irq, 0 /* no timeout */);
} }
/* Check whether the IRQ line is shared with other guests. */
int xen_test_irq_shared(int irq)
{
struct irq_info *info = info_for_irq(irq);
struct physdev_irq_status_query irq_status = { .irq = info->u.pirq.pirq };
if (HYPERVISOR_physdev_op(PHYSDEVOP_irq_status_query, &irq_status))
return 0;
return !(irq_status.flags & XENIRQSTAT_shared);
}
EXPORT_SYMBOL_GPL(xen_test_irq_shared);
void xen_irq_resume(void) void xen_irq_resume(void)
{ {
unsigned int cpu, evtchn; unsigned int cpu, evtchn;

View file

@ -427,6 +427,17 @@ static long gntalloc_ioctl(struct file *filp, unsigned int cmd,
return 0; return 0;
} }
static void gntalloc_vma_open(struct vm_area_struct *vma)
{
struct gntalloc_gref *gref = vma->vm_private_data;
if (!gref)
return;
spin_lock(&gref_lock);
gref->users++;
spin_unlock(&gref_lock);
}
static void gntalloc_vma_close(struct vm_area_struct *vma) static void gntalloc_vma_close(struct vm_area_struct *vma)
{ {
struct gntalloc_gref *gref = vma->vm_private_data; struct gntalloc_gref *gref = vma->vm_private_data;
@ -441,6 +452,7 @@ static void gntalloc_vma_close(struct vm_area_struct *vma)
} }
static struct vm_operations_struct gntalloc_vmops = { static struct vm_operations_struct gntalloc_vmops = {
.open = gntalloc_vma_open,
.close = gntalloc_vma_close, .close = gntalloc_vma_close,
}; };
@ -471,8 +483,6 @@ static int gntalloc_mmap(struct file *filp, struct vm_area_struct *vma)
vma->vm_private_data = gref; vma->vm_private_data = gref;
vma->vm_flags |= VM_RESERVED; vma->vm_flags |= VM_RESERVED;
vma->vm_flags |= VM_DONTCOPY;
vma->vm_flags |= VM_PFNMAP | VM_PFN_AT_MMAP;
vma->vm_ops = &gntalloc_vmops; vma->vm_ops = &gntalloc_vmops;

View file

@ -330,17 +330,26 @@ static int unmap_grant_pages(struct grant_map *map, int offset, int pages)
/* ------------------------------------------------------------------ */ /* ------------------------------------------------------------------ */
static void gntdev_vma_open(struct vm_area_struct *vma)
{
struct grant_map *map = vma->vm_private_data;
pr_debug("gntdev_vma_open %p\n", vma);
atomic_inc(&map->users);
}
static void gntdev_vma_close(struct vm_area_struct *vma) static void gntdev_vma_close(struct vm_area_struct *vma)
{ {
struct grant_map *map = vma->vm_private_data; struct grant_map *map = vma->vm_private_data;
pr_debug("close %p\n", vma); pr_debug("gntdev_vma_close %p\n", vma);
map->vma = NULL; map->vma = NULL;
vma->vm_private_data = NULL; vma->vm_private_data = NULL;
gntdev_put_map(map); gntdev_put_map(map);
} }
static struct vm_operations_struct gntdev_vmops = { static struct vm_operations_struct gntdev_vmops = {
.open = gntdev_vma_open,
.close = gntdev_vma_close, .close = gntdev_vma_close,
}; };
@ -652,7 +661,10 @@ static int gntdev_mmap(struct file *flip, struct vm_area_struct *vma)
vma->vm_ops = &gntdev_vmops; vma->vm_ops = &gntdev_vmops;
vma->vm_flags |= VM_RESERVED|VM_DONTCOPY|VM_DONTEXPAND|VM_PFNMAP; vma->vm_flags |= VM_RESERVED|VM_DONTEXPAND;
if (use_ptemod)
vma->vm_flags |= VM_DONTCOPY|VM_PFNMAP;
vma->vm_private_data = map; vma->vm_private_data = map;

View file

@ -466,13 +466,30 @@ int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops,
if (map_ops[i].status) if (map_ops[i].status)
continue; continue;
/* m2p override only supported for GNTMAP_contains_pte mappings */ if (map_ops[i].flags & GNTMAP_contains_pte) {
if (!(map_ops[i].flags & GNTMAP_contains_pte)) pte = (pte_t *) (mfn_to_virt(PFN_DOWN(map_ops[i].host_addr)) +
continue;
pte = (pte_t *) (mfn_to_virt(PFN_DOWN(map_ops[i].host_addr)) +
(map_ops[i].host_addr & ~PAGE_MASK)); (map_ops[i].host_addr & ~PAGE_MASK));
mfn = pte_mfn(*pte); mfn = pte_mfn(*pte);
ret = m2p_add_override(mfn, pages[i]); } else {
/* If you really wanted to do this:
* mfn = PFN_DOWN(map_ops[i].dev_bus_addr);
*
* The reason we do not implement it is b/c on the
* unmap path (gnttab_unmap_refs) we have no means of
* checking whether the page is !GNTMAP_contains_pte.
*
* That is without some extra data-structure to carry
* the struct page, bool clear_pte, and list_head next
* tuples and deal with allocation/delallocation, etc.
*
* The users of this API set the GNTMAP_contains_pte
* flag so lets just return not supported until it
* becomes neccessary to implement.
*/
return -EOPNOTSUPP;
}
ret = m2p_add_override(mfn, pages[i],
map_ops[i].flags & GNTMAP_contains_pte);
if (ret) if (ret)
return ret; return ret;
} }
@ -494,7 +511,7 @@ int gnttab_unmap_refs(struct gnttab_unmap_grant_ref *unmap_ops,
return ret; return ret;
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
ret = m2p_remove_override(pages[i]); ret = m2p_remove_override(pages[i], true /* clear the PTE */);
if (ret) if (ret)
return ret; return ret;
} }

View file

@ -85,7 +85,8 @@ int xen_bind_pirq_gsi_to_irq(unsigned gsi,
int xen_allocate_pirq_msi(struct pci_dev *dev, struct msi_desc *msidesc); int xen_allocate_pirq_msi(struct pci_dev *dev, struct msi_desc *msidesc);
/* Bind an PSI pirq to an irq. */ /* Bind an PSI pirq to an irq. */
int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc *msidesc, int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc *msidesc,
int pirq, int vector, const char *name); int pirq, int vector, const char *name,
domid_t domid);
#endif #endif
/* De-allocates the above mentioned physical interrupt. */ /* De-allocates the above mentioned physical interrupt. */
@ -94,4 +95,10 @@ int xen_destroy_irq(int irq);
/* Return irq from pirq */ /* Return irq from pirq */
int xen_irq_from_pirq(unsigned pirq); int xen_irq_from_pirq(unsigned pirq);
/* Return the pirq allocated to the irq. */
int xen_pirq_from_irq(unsigned irq);
/* Determine whether to ignore this IRQ if it is passed to a guest. */
int xen_test_irq_shared(int irq);
#endif /* _XEN_EVENTS_H */ #endif /* _XEN_EVENTS_H */