Add management and locking of PCI device structures

Add functions for managing pci_dev structures.  Create a list
containing all current pci_devs.  Remove msi_pdev_list.  Create a
read-write lock protecting all pci_dev lists.  Add spinlocks for
pci_dev access.  Do necessary modifications to MSI code.

Signed-off-by: Espen Skoglund <espen.skoglund@netronome.com>
This commit is contained in:
Keir Fraser committed 2008-07-04 17:52:24 +01:00
1 parent f800030ddb
commit ffd9d82c69
11 files changed
+303 -185

No files matched your search

-3
View File
@@ -382,7 +382,6 @@ void __devinit init_8259A(int auto_eoi)
static struct irqaction cascade = { no_action, "cascade", NULL};
extern struct list_head msi_pdev_list;
void __init init_IRQ(void)
{
int i;
@@ -419,7 +418,5 @@ void __init init_IRQ(void)
outb(LATCH >> 8, PIT_CH0); /* MSB */
setup_irq(2, &cascade);
INIT_LIST_HEAD(&msi_pdev_list);
}
+71 -99
View File
@@ -29,21 +29,6 @@
extern int msi_irq_enable;
/* PCI-dev list with MSI/MSIX capabilities */
DEFINE_SPINLOCK(msi_pdev_lock);
struct list_head msi_pdev_list;
struct pci_dev *get_msi_pdev(u8 bus, u8 devfn)
{
struct pci_dev *pdev = NULL;
list_for_each_entry(pdev, &msi_pdev_list, msi_dev_list)
if ( pdev->bus == bus && pdev->devfn == devfn )
return pdev;
return NULL;
}
/* bitmap indicate which fixed map is free */
DEFINE_SPINLOCK(msix_fixmap_lock);
DECLARE_BITMAP(msix_fixmap_pages, MAX_MSIX_PAGES);
@@ -112,10 +97,8 @@ static void msi_compose_msg(struct pci_dev *pdev, int vector,
}
}
void read_msi_msg(unsigned int irq, struct msi_msg *msg)
static void read_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
{
struct msi_desc *entry = irq_desc[irq].msi_desc;
switch ( entry->msi_attrib.type )
{
case PCI_CAP_ID_MSI:
@@ -147,7 +130,7 @@ void read_msi_msg(unsigned int irq, struct msi_msg *msg)
{
void __iomem *base;
base = entry->mask_base +
entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE;
entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE;
msg->address_lo = readl(base + PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
msg->address_hi = readl(base + PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
@@ -164,9 +147,6 @@ void read_msi_msg(unsigned int irq, struct msi_msg *msg)
static int set_vector_msi(struct msi_desc *entry)
{
irq_desc_t *desc;
unsigned long flags;
if ( entry->vector >= NR_VECTORS )
{
dprintk(XENLOG_ERR, "Trying to install msi data for Vector %d\n",
@@ -174,19 +154,12 @@ static int set_vector_msi(struct msi_desc *entry)
return -EINVAL;
}
desc = &irq_desc[entry->vector];
spin_lock_irqsave(&desc->lock, flags);
desc->msi_desc = entry;
spin_unlock_irqrestore(&desc->lock, flags);
irq_desc[entry->vector].msi_desc = entry;
return 0;
}
static int unset_vector_msi(int vector)
{
irq_desc_t *desc;
unsigned long flags;
if ( vector >= NR_VECTORS )
{
dprintk(XENLOG_ERR, "Trying to uninstall msi data for Vector %d\n",
@@ -194,18 +167,12 @@ static int unset_vector_msi(int vector)
return -EINVAL;
}
desc = &irq_desc[vector];
spin_lock_irqsave(&desc->lock, flags);
desc->msi_desc = NULL;
spin_unlock_irqrestore(&desc->lock, flags);
irq_desc[vector].msi_desc = NULL;
return 0;
}
void write_msi_msg(unsigned int irq, struct msi_msg *msg)
static void write_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
{
struct msi_desc *entry = irq_desc[irq].msi_desc;
if ( vtd_enabled )
msi_msg_write_remap_rte(entry, msg);
@@ -254,6 +221,7 @@ void write_msi_msg(unsigned int irq, struct msi_msg *msg)
void set_msi_irq_affinity(unsigned int irq, cpumask_t mask)
{
struct msi_desc *desc = irq_desc[irq].msi_desc;
struct msi_msg msg;
unsigned int dest;
@@ -263,12 +231,18 @@ void set_msi_irq_affinity(unsigned int irq, cpumask_t mask)
mask = TARGET_CPUS;
dest = cpu_mask_to_apicid(mask);
read_msi_msg(irq, &msg);
if ( !desc )
return;
ASSERT(spin_is_locked(&irq_desc[vector].lock));
spin_lock(&desc->dev->lock);
read_msi_msg(desc, &msg);
msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK;
msg.address_lo |= MSI_ADDR_DEST_ID(dest);
write_msi_msg(irq, &msg);
write_msi_msg(desc, &msg);
spin_unlock(&desc->dev->lock);
}
static void msi_set_enable(struct pci_dev *dev, int enable)
@@ -290,7 +264,7 @@ static void msi_set_enable(struct pci_dev *dev, int enable)
}
}
void msix_set_enable(struct pci_dev *dev, int enable)
static void msix_set_enable(struct pci_dev *dev, int enable)
{
int pos;
u16 control;
@@ -335,6 +309,7 @@ static void msi_set_mask_bit(unsigned int irq, int flag)
{
struct msi_desc *entry = irq_desc[irq].msi_desc;
ASSERT(spin_is_locked(&irq_desc[vector].lock));
BUG_ON(!entry || !entry->dev);
switch (entry->msi_attrib.type) {
case PCI_CAP_ID_MSI:
@@ -401,7 +376,7 @@ static int setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
msi_compose_msg(dev, desc->vector, &msg);
set_vector_msi(desc);
write_msi_msg(desc->vector, &msg);
write_msi_msg(irq_desc[desc->vector].msi_desc, &msg);
return 0;
}
@@ -415,8 +390,8 @@ static void msi_free_vector(int vector)
{
struct msi_desc *entry;
ASSERT(spin_is_locked(&irq_desc[vector].lock));
entry = irq_desc[vector].msi_desc;
teardown_msi_vector(vector);
if ( entry->msi_attrib.type == PCI_CAP_ID_MSIX )
@@ -619,35 +594,22 @@ static int msix_capability_init(struct pci_dev *dev, int vector, int entry_nr)
static int __pci_enable_msi(u8 bus, u8 devfn, int vector)
{
int status;
struct pci_dev *dev;
struct pci_dev *pdev;
dev = get_msi_pdev(bus, devfn);
if ( !dev )
{
dev = xmalloc(struct pci_dev);
if ( !dev )
return -ENOMEM;
dev->bus = bus;
dev->devfn = devfn;
INIT_LIST_HEAD(&dev->msi_list);
}
pdev = pci_lock_pdev(bus, devfn);
if ( !pdev )
return -ENODEV;
if ( find_msi_entry(dev, vector, PCI_CAP_ID_MSI) )
if ( find_msi_entry(pdev, vector, PCI_CAP_ID_MSI) )
{
spin_unlock(&pdev->lock);
dprintk(XENLOG_WARNING, "vector %d has already mapped to MSI on device \
%02x:%02x.%01x.\n", vector, bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
return 0;
}
status = msi_capability_init(dev, vector);
if ( dev != get_msi_pdev(bus, devfn) )
{
spin_lock(&msi_pdev_lock);
list_add_tail(&dev->msi_dev_list, &msi_pdev_list);
spin_unlock(&msi_pdev_lock);
}
status = msi_capability_init(pdev, vector);
spin_unlock(&pdev->lock);
return status;
}
@@ -660,6 +622,13 @@ static void __pci_disable_msi(int vector)
u8 bus, slot, func;
entry = irq_desc[vector].msi_desc;
if ( !entry )
return;
/*
* Lock here is safe. msi_desc can not be removed without holding
* both irq_desc[].lock (which we do) and pdev->lock.
*/
spin_lock(&entry->dev->lock);
dev = entry->dev;
bus = dev->bus;
slot = PCI_SLOT(dev->devfn);
@@ -674,6 +643,7 @@ static void __pci_disable_msi(int vector)
msi_free_vector(vector);
pci_conf_write16(bus, slot, func, msi_control_reg(pos), control);
spin_unlock(&dev->lock);
}
/**
@@ -694,47 +664,35 @@ static void __pci_disable_msi(int vector)
static int __pci_enable_msix(u8 bus, u8 devfn, int vector, int entry_nr)
{
int status, pos, nr_entries;
struct pci_dev *dev;
struct pci_dev *pdev;
u16 control;
u8 slot = PCI_SLOT(devfn);
u8 func = PCI_FUNC(devfn);
pdev = pci_lock_pdev(bus, devfn);
if ( !pdev )
return -ENODEV;
pos = pci_find_cap_offset(bus, slot, func, PCI_CAP_ID_MSIX);
control = pci_conf_read16(bus, slot, func, msi_control_reg(pos));
nr_entries = multi_msix_capable(control);
if (entry_nr > nr_entries)
return -EINVAL;
/* Check whether driver already requested for MSI-X irqs */
dev = get_msi_pdev(bus, devfn);
if ( !dev )
{
dev = xmalloc(struct pci_dev);
if ( !dev )
return -ENOMEM;
dev->bus = bus;
dev->devfn = devfn;
INIT_LIST_HEAD(&dev->msi_list);
spin_unlock(&pdev->lock);
return -EINVAL;
}
if ( find_msi_entry(dev, vector, PCI_CAP_ID_MSIX) )
if ( find_msi_entry(pdev, vector, PCI_CAP_ID_MSIX) )
{
spin_unlock(&pdev->lock);
dprintk(XENLOG_WARNING, "vector %d has already mapped to MSIX on \
device %02x:%02x.%01x.\n", vector, bus,
PCI_SLOT(devfn), PCI_FUNC(devfn));
return 0;
}
status = msix_capability_init(dev, vector, entry_nr);
if ( dev != get_msi_pdev(bus, devfn) )
{
spin_lock(&msi_pdev_lock);
list_add_tail(&dev->msi_dev_list, &msi_pdev_list);
spin_unlock(&msi_pdev_lock);
}
status = msix_capability_init(pdev, vector, entry_nr);
spin_unlock(&pdev->lock);
return status;
}
@@ -747,6 +705,13 @@ static void __pci_disable_msix(int vector)
u8 bus, slot, func;
entry = irq_desc[vector].msi_desc;
if ( !entry )
return;
/*
* Lock here is safe. msi_desc can not be removed without holding
* both irq_desc[].lock (which we do) and pdev->lock.
*/
spin_lock(&entry->dev->lock);
dev = entry->dev;
bus = dev->bus;
slot = PCI_SLOT(dev->devfn);
@@ -761,10 +726,12 @@ static void __pci_disable_msix(int vector)
msi_free_vector(vector);
pci_conf_write16(bus, slot, func, msix_control_reg(pos), control);
spin_unlock(&dev->lock);
}
int pci_enable_msi(u8 bus, u8 devfn, int vector, int entry_nr, int msi)
{
ASSERT(spin_is_locked(&irq_desc[vector].lock));
if ( msi )
return __pci_enable_msi(bus, devfn, vector);
else
@@ -773,9 +740,11 @@ int pci_enable_msi(u8 bus, u8 devfn, int vector, int entry_nr, int msi)
void pci_disable_msi(int vector)
{
irq_desc_t *desc;
irq_desc_t *desc = &irq_desc[vector];
ASSERT(spin_is_locked(&desc->lock));
if ( !desc->msi_desc )
return;
desc = &irq_desc[vector];
if ( desc->msi_desc->msi_attrib.type == PCI_CAP_ID_MSI )
__pci_disable_msi(vector);
else if ( desc->msi_desc->msi_attrib.type == PCI_CAP_ID_MSIX )
@@ -789,10 +758,18 @@ static void msi_free_vectors(struct pci_dev* dev)
irq_desc_t *desc;
unsigned long flags;
retry:
list_for_each_entry_safe( entry, tmp, &dev->msi_list, list )
{
desc = &irq_desc[entry->vector];
local_irq_save(flags);
if ( !spin_trylock(&desc->lock) )
{
local_irq_restore(flags);
goto retry;
}
spin_lock_irqsave(&desc->lock, flags);
if ( desc->handler == &pci_msi_type )
{
@@ -800,22 +777,17 @@ static void msi_free_vectors(struct pci_dev* dev)
BUG_ON(desc->status & IRQ_GUEST);
desc->handler = &no_irq_type;
}
spin_unlock_irqrestore(&desc->lock, flags);
msi_free_vector(entry->vector);
spin_unlock_irqrestore(&desc->lock, flags);
}
}
void pci_cleanup_msi(u8 bus, u8 devfn)
void pci_cleanup_msi(struct pci_dev *pdev)
{
struct pci_dev *dev = get_msi_pdev(bus, devfn);
if ( !dev )
return;
/* Disable MSI and/or MSI-X */
msi_set_enable(dev, 0);
msix_set_enable(dev, 0);
msi_free_vectors(dev);
msi_set_enable(pdev, 0);
msix_set_enable(pdev, 0);
msi_free_vectors(pdev);
}
+2 -2
View File
@@ -114,12 +114,12 @@ static int map_domain_pirq(struct domain *d, int pirq, int vector,
gdprintk(XENLOG_G_ERR, "Map vector %x to msi while it is in use\n",
vector);
desc->handler = &pci_msi_type;
spin_unlock_irqrestore(&desc->lock, flags);
ret = pci_enable_msi(map->msi_info.bus,
map->msi_info.devfn, vector,
map->msi_info.entry_nr,
map->msi_info.msi);
spin_unlock_irqrestore(&desc->lock, flags);
if ( ret )
goto done;
}
@@ -161,10 +161,10 @@ static int unmap_domain_pirq(struct domain *d, int pirq)
irq_desc_t *desc;
desc = &irq_desc[vector];
spin_lock_irqsave(&desc->lock, flags);
if ( desc->msi_desc )
pci_disable_msi(vector);
spin_lock_irqsave(&desc->lock, flags);
if ( desc->handler == &pci_msi_type )
{
/* MSI is not shared, so should be released already */
+1
View File
@@ -3,3 +3,4 @@ subdir-$(x86) += amd
obj-y += iommu.o
obj-y += io.o
obj-y += pci.o
+37 -35
View File
@@ -298,6 +298,7 @@ static void amd_iommu_setup_dom0_devices(struct domain *d)
u32 l;
int bdf;
write_lock(&pcidevs_lock);
for ( bus = 0; bus < 256; bus++ )
{
for ( dev = 0; dev < 32; dev++ )
@@ -310,10 +311,9 @@ static void amd_iommu_setup_dom0_devices(struct domain *d)
(l == 0x0000ffff) || (l == 0xffff0000) )
continue;
pdev = xmalloc(struct pci_dev);
pdev->bus = bus;
pdev->devfn = PCI_DEVFN(dev, func);
list_add_tail(&pdev->domain_list, &d->arch.pdev_list);
pdev = alloc_pdev(bus, PCI_DEVFN(dev, func));
pdev->domain = d;
list_add(&pdev->domain_list, &d->arch.pdev_list);
bdf = (bus << 8) | pdev->devfn;
/* supported device? */
@@ -325,6 +325,7 @@ static void amd_iommu_setup_dom0_devices(struct domain *d)
}
}
}
write_unlock(&pcidevs_lock);
}
int amd_iov_detect(void)
@@ -493,38 +494,37 @@ static int reassign_device( struct domain *source, struct domain *target,
struct amd_iommu *iommu;
int bdf;
for_each_pdev ( source, pdev )
pdev = pci_lock_domain_pdev(source, bus, devfn);
if ( !pdev )
return -ENODEV;
bdf = (bus << 8) | devfn;
/* supported device? */
iommu = (bdf < ivrs_bdf_entries) ?
find_iommu_for_device(bus, pdev->devfn) : NULL;
if ( !iommu )
{
if ( (pdev->bus != bus) || (pdev->devfn != devfn) )
continue;
spin_unlock(&pdev->lock);
amd_iov_error("Fail to find iommu."
" %x:%x.%x cannot be assigned to domain %d\n",
bus, PCI_SLOT(devfn), PCI_FUNC(devfn), target->domain_id);
return -ENODEV;
}
pdev->bus = bus;
pdev->devfn = devfn;
amd_iommu_disable_domain_device(source, iommu, bdf);
bdf = (bus << 8) | devfn;
/* supported device? */
iommu = (bdf < ivrs_bdf_entries) ?
find_iommu_for_device(bus, pdev->devfn) : NULL;
write_lock(&pcidevs_lock);
list_move(&pdev->domain_list, &target->arch.pdev_list);
write_unlock(&pcidevs_lock);
pdev->domain = target;
if ( !iommu )
{
amd_iov_error("Fail to find iommu."
" %x:%x.%x cannot be assigned to domain %d\n",
bus, PCI_SLOT(devfn), PCI_FUNC(devfn), target->domain_id);
return -ENODEV;
}
amd_iommu_disable_domain_device(source, iommu, bdf);
/* Move pci device from the source domain to target domain. */
list_move(&pdev->domain_list, &target->arch.pdev_list);
amd_iommu_setup_domain_device(target, iommu, bdf);
amd_iov_info("reassign %x:%x.%x domain %d -> domain %d\n",
amd_iommu_setup_domain_device(target, iommu, bdf);
amd_iov_info("reassign %x:%x.%x domain %d -> domain %d\n",
bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
source->domain_id, target->domain_id);
break;
}
spin_unlock(&pdev->lock);
return 0;
}
@@ -552,14 +552,16 @@ static int amd_iommu_assign_device(struct domain *d, u8 bus, u8 devfn)
static void release_domain_devices(struct domain *d)
{
struct pci_dev *pdev;
u8 bus, devfn;
while ( has_arch_pdevs(d) )
while ( (pdev = pci_lock_domain_pdev(d, -1, -1)) )
{
pdev = list_entry(d->arch.pdev_list.next, typeof(*pdev), domain_list);
pdev_flr(pdev->bus, pdev->devfn);
bus = pdev->bus; devfn = pdev->devfn;
spin_unlock(&pdev->lock);
amd_iov_info("release domain %d devices %x:%x.%x\n", d->domain_id,
pdev->bus, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
reassign_device(d, dom0, pdev->bus, pdev->devfn);
bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
reassign_device(d, dom0, bus, devfn);
}
}
@@ -619,11 +621,11 @@ static void amd_iommu_domain_destroy(struct domain *d)
release_domain_devices(d);
}
static void amd_iommu_return_device(
static int amd_iommu_return_device(
struct domain *s, struct domain *t, u8 bus, u8 devfn)
{
pdev_flr(bus, devfn);
reassign_device(s, t, bus, devfn);
return reassign_device(s, t, bus, devfn);
}
static int amd_iommu_group_id(u8 bus, u8 devfn)
+5
View File
@@ -240,6 +240,7 @@ int iommu_get_device_group(struct domain *d, u8 bus, u8 devfn,
group_id = ops->get_device_group_id(bus, devfn);
read_lock(&pcidevs_lock);
for_each_pdev( d, pdev )
{
if ( (pdev->bus == bus) && (pdev->devfn == devfn) )
@@ -252,10 +253,14 @@ int iommu_get_device_group(struct domain *d, u8 bus, u8 devfn,
bdf |= (pdev->bus & 0xff) << 16;
bdf |= (pdev->devfn & 0xff) << 8;
if ( unlikely(copy_to_guest_offset(buf, i, &bdf, 1)) )
{
read_unlock(&pcidevs_lock);
return -1;
}
i++;
}
}
read_unlock(&pcidevs_lock);
return i;
}
+124
View File
@@ -0,0 +1,124 @@
/*
* Copyright (C) 2008, Netronome Systems, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307 USA.
*/
#include <xen/sched.h>
#include <xen/pci.h>
#include <xen/list.h>
#include <xen/prefetch.h>
#include <xen/keyhandler.h>
LIST_HEAD(alldevs_list);
rwlock_t pcidevs_lock = RW_LOCK_UNLOCKED;
struct pci_dev *alloc_pdev(u8 bus, u8 devfn)
{
struct pci_dev *pdev;
list_for_each_entry ( pdev, &alldevs_list, alldevs_list )
if ( pdev->bus == bus && pdev->devfn == devfn )
return pdev;
pdev = xmalloc(struct pci_dev);
if ( !pdev )
return NULL;
*((u8*) &pdev->bus) = bus;
*((u8*) &pdev->devfn) = devfn;
pdev->domain = NULL;
spin_lock_init(&pdev->lock);
INIT_LIST_HEAD(&pdev->msi_list);
list_add(&pdev->alldevs_list, &alldevs_list);
return pdev;
}
void free_pdev(struct pci_dev *pdev)
{
list_del(&pdev->alldevs_list);
xfree(pdev);
}
struct pci_dev *pci_lock_pdev(int bus, int devfn)
{
struct pci_dev *pdev;
read_lock(&pcidevs_lock);
list_for_each_entry ( pdev, &alldevs_list, alldevs_list )
if ( (pdev->bus == bus || bus == -1) &&
(pdev->devfn == devfn || devfn == -1) )
{
spin_lock(&pdev->lock);
read_unlock(&pcidevs_lock);
return pdev;
}
read_unlock(&pcidevs_lock);
return NULL;
}
struct pci_dev *pci_lock_domain_pdev(struct domain *d, int bus, int devfn)
{
struct pci_dev *pdev;
read_lock(&pcidevs_lock);
list_for_each_entry ( pdev, &d->arch.pdev_list, domain_list )
{
spin_lock(&pdev->lock);
if ( (pdev->bus == bus || bus == -1) &&
(pdev->devfn == devfn || devfn == -1) &&
(pdev->domain == d) )
{
read_unlock(&pcidevs_lock);
return pdev;
}
spin_unlock(&pdev->lock);
}
read_unlock(&pcidevs_lock);
return NULL;
}
static void dump_pci_devices(unsigned char ch)
{
struct pci_dev *pdev;
struct msi_desc *msi;
printk("==== PCI devices ====\n");
read_lock(&pcidevs_lock);
list_for_each_entry ( pdev, &alldevs_list, alldevs_list )
{
spin_lock(&pdev->lock);
printk("%02x:%02x.%x - dom %-3d - MSIs < ",
pdev->bus, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
pdev->domain ? pdev->domain->domain_id : -1);
list_for_each_entry ( msi, &pdev->msi_list, list )
printk("%d ", msi->vector);
printk(">\n");
spin_unlock(&pdev->lock);
}
read_unlock(&pcidevs_lock);
}
static int __init setup_dump_pcidevs(void)
{
register_keyhandler('P', dump_pci_devices, "dump PCI devices");
return 0;
}
__initcall(setup_dump_pcidevs);
+38 -35
View File
@@ -1345,7 +1345,7 @@ static int domain_context_unmap(u8 bus, u8 devfn)
return ret;
}
void reassign_device_ownership(
static int reassign_device_ownership(
struct domain *source,
struct domain *target,
u8 bus, u8 devfn)
@@ -1353,61 +1353,62 @@ void reassign_device_ownership(
struct hvm_iommu *source_hd = domain_hvm_iommu(source);
struct pci_dev *pdev;
struct acpi_drhd_unit *drhd;
struct iommu *iommu;
int status;
int found = 0;
struct iommu *pdev_iommu;
int ret, found = 0;
if ( !(pdev = pci_lock_domain_pdev(source, bus, devfn)) )
return -ENODEV;
pdev_flr(bus, devfn);
for_each_pdev( source, pdev )
if ( (pdev->bus == bus) && (pdev->devfn == devfn) )
goto found;
return;
found:
drhd = acpi_find_matched_drhd_unit(bus, devfn);
iommu = drhd->iommu;
pdev_iommu = drhd->iommu;
domain_context_unmap(bus, devfn);
/* Move pci device from the source domain to target domain. */
write_lock(&pcidevs_lock);
list_move(&pdev->domain_list, &target->arch.pdev_list);
write_unlock(&pcidevs_lock);
pdev->domain = target;
ret = domain_context_mapping(target, bus, devfn);
spin_unlock(&pdev->lock);
read_lock(&pcidevs_lock);
for_each_pdev ( source, pdev )
{
drhd = acpi_find_matched_drhd_unit(pdev->bus, pdev->devfn);
if ( drhd->iommu == iommu )
if ( drhd->iommu == pdev_iommu )
{
found = 1;
break;
}
}
read_unlock(&pcidevs_lock);
if ( !found )
clear_bit(iommu->index, &source_hd->iommu_bitmap);
clear_bit(pdev_iommu->index, &source_hd->iommu_bitmap);
status = domain_context_mapping(target, bus, devfn);
if ( status != 0 )
gdprintk(XENLOG_ERR VTDPREFIX, "domain_context_mapping failed\n");
return ret;
}
void return_devices_to_dom0(struct domain *d)
{
struct pci_dev *pdev;
while ( has_arch_pdevs(d) )
while ( (pdev = pci_lock_domain_pdev(d, -1, -1)) )
{
pdev = list_entry(d->arch.pdev_list.next, typeof(*pdev), domain_list);
pci_cleanup_msi(pdev->bus, pdev->devfn);
pci_cleanup_msi(pdev);
spin_unlock(&pdev->lock);
reassign_device_ownership(d, dom0, pdev->bus, pdev->devfn);
}
#ifdef VTD_DEBUG
read_lock(&pcidevs_lock);
for_each_pdev ( dom0, pdev )
dprintk(XENLOG_INFO VTDPREFIX,
"return_devices_to_dom0:%x: bdf = %x:%x:%x\n",
dom0->domain_id, pdev->bus,
PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
read_unlock(&pcidevs_lock);
#endif
}
@@ -1568,11 +1569,7 @@ static int iommu_prepare_rmrr_dev(struct domain *d,
return ret;
if ( domain_context_mapped(bus, devfn) == 0 )
{
ret = domain_context_mapping(d, bus, devfn);
if ( !ret )
return 0;
}
return ret;
}
@@ -1586,6 +1583,7 @@ static void setup_dom0_devices(struct domain *d)
hd = domain_hvm_iommu(d);
write_lock(&pcidevs_lock);
for ( bus = 0; bus < 256; bus++ )
{
for ( dev = 0; dev < 32; dev++ )
@@ -1597,10 +1595,10 @@ static void setup_dom0_devices(struct domain *d)
if ( (l == 0xffffffff) || (l == 0x00000000) ||
(l == 0x0000ffff) || (l == 0xffff0000) )
continue;
pdev = xmalloc(struct pci_dev);
pdev->bus = bus;
pdev->devfn = PCI_DEVFN(dev, func);
list_add_tail(&pdev->domain_list, &d->arch.pdev_list);
pdev = alloc_pdev(bus, PCI_DEVFN(dev, func));
pdev->domain = d;
list_add(&pdev->domain_list, &d->arch.pdev_list);
ret = domain_context_mapping(d, pdev->bus, pdev->devfn);
if ( ret != 0 )
@@ -1609,6 +1607,7 @@ static void setup_dom0_devices(struct domain *d)
}
}
}
write_unlock(&pcidevs_lock);
}
void clear_fault_bits(struct iommu *iommu)
@@ -1737,9 +1736,11 @@ int device_assigned(u8 bus, u8 devfn)
{
struct pci_dev *pdev;
for_each_pdev( dom0, pdev )
if ( (pdev->bus == bus ) && (pdev->devfn == devfn) )
return 0;
if ( (pdev = pci_lock_domain_pdev(dom0, bus, devfn)) )
{
spin_unlock(&pdev->lock);
return 0;
}
return 1;
}
@@ -1751,9 +1752,11 @@ int intel_iommu_assign_device(struct domain *d, u8 bus, u8 devfn)
u16 bdf;
if ( list_empty(&acpi_drhd_units) )
return ret;
return -ENODEV;
reassign_device_ownership(dom0, d, bus, devfn);
ret = reassign_device_ownership(dom0, d, bus, devfn);
if ( ret )
return ret;
/* Setup rmrr identity mapping */
for_each_rmrr_device( rmrr, bdf, i )
+1 -3
View File
@@ -63,12 +63,10 @@ struct msi_msg {
/* Helper functions */
extern void mask_msi_irq(unsigned int irq);
extern void unmask_msi_irq(unsigned int irq);
extern void read_msi_msg(unsigned int irq, struct msi_msg *msg);
extern void write_msi_msg(unsigned int irq, struct msi_msg *msg);
extern void set_msi_irq_affinity(unsigned int irq, cpumask_t mask);
extern int pci_enable_msi(u8 bus, u8 devfn, int vector, int entry_nr, int msi);
extern void pci_disable_msi(int vector);
extern void pci_cleanup_msi(u8 bus, u8 devfn);
extern void pci_cleanup_msi(struct pci_dev *pdev);
struct msi_desc {
struct {
+4 -5
View File
@@ -56,6 +56,8 @@ struct iommu {
struct intel_iommu *intel;
};
int iommu_add_device(u8 bus, u8 devfn);
void iommu_remove_device(u8 bus, u8 devfn);
int iommu_domain_init(struct domain *d);
void iommu_domain_destroy(struct domain *d);
int device_assigned(u8 bus, u8 devfn);
@@ -63,9 +65,6 @@ int assign_device(struct domain *d, u8 bus, u8 devfn);
void deassign_device(struct domain *d, u8 bus, u8 devfn);
int iommu_get_device_group(struct domain *d, u8 bus, u8 devfn,
XEN_GUEST_HANDLE_64(uint32) buf, int max_sdevs);
void reassign_device_ownership(struct domain *source,
struct domain *target,
u8 bus, u8 devfn);
int iommu_map_page(struct domain *d, unsigned long gfn, unsigned long mfn);
int iommu_unmap_page(struct domain *d, unsigned long gfn);
void iommu_domain_teardown(struct domain *d);
@@ -99,8 +98,8 @@ struct iommu_ops {
void (*teardown)(struct domain *d);
int (*map_page)(struct domain *d, unsigned long gfn, unsigned long mfn);
int (*unmap_page)(struct domain *d, unsigned long gfn);
void (*reassign_device)(struct domain *s, struct domain *t,
u8 bus, u8 devfn);
int (*reassign_device)(struct domain *s, struct domain *t,
u8 bus, u8 devfn);
int (*get_device_group_id)(u8 bus, u8 devfn);
};
+20 -3
View File
@@ -10,6 +10,7 @@
#include <xen/config.h>
#include <xen/types.h>
#include <xen/list.h>
#include <xen/spinlock.h>
/*
* The PCI interface treats multi-function devices as independent
@@ -29,16 +30,32 @@
#define PCI_BDF2(b,df) (((b & 0xff) << 8) | (df & 0xff))
struct pci_dev {
struct list_head alldevs_list;
struct list_head domain_list;
struct list_head msi_dev_list;
u8 bus;
u8 devfn;
struct list_head msi_list;
struct domain *domain;
const u8 bus;
const u8 devfn;
spinlock_t lock;
};
#define for_each_pdev(domain, pdev) \
list_for_each_entry(pdev, &(domain->arch.pdev_list), domain_list)
/*
* The pcidevs_lock write-lock must be held when doing alloc_pdev() or
* free_pdev(). Never de-reference pdev without holding pdev->lock or
* pcidevs_lock. Always aquire pcidevs_lock before pdev->lock when
* doing free_pdev().
*/
extern rwlock_t pcidevs_lock;
struct pci_dev *alloc_pdev(u8 bus, u8 devfn);
void free_pdev(struct pci_dev *pdev);
struct pci_dev *pci_lock_pdev(int bus, int devfn);
struct pci_dev *pci_lock_domain_pdev(struct domain *d, int bus, int devfn);
uint8_t pci_conf_read8(
unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg);
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.