|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH v1 4/5] vpci: use separate rangeset for BAR unmapping
Introduce a new per-BAR rangeset, unmap_mem, for p2m unmapping. Rename
existing mem rangeset to map_mem, which is now only used for mapping.
Populate unmap_mem by moving just-mapped ranges from map_mem to
unmap_mem. In modify_bars(), skip recalculating the ranges when
unmapping as they are already stored in unmap_mem.
Signed-off-by: Stewart Hildebrand <stewart.hildebrand@xxxxxxx>
---
xen/drivers/vpci/header.c | 74 +++++++++++++++++++++++++++++----------
xen/drivers/vpci/vpci.c | 5 ++-
xen/include/xen/vpci.h | 3 +-
3 files changed, 62 insertions(+), 20 deletions(-)
diff --git a/xen/drivers/vpci/header.c b/xen/drivers/vpci/header.c
index b09ccc5e6be6..c9519c804d97 100644
--- a/xen/drivers/vpci/header.c
+++ b/xen/drivers/vpci/header.c
@@ -90,6 +90,8 @@ static int cf_check map_range(
if ( rc == 0 )
{
*c += size;
+ if ( map->map )
+ rc = rangeset_add_range(map->bar->unmap_mem, s, e);
break;
}
if ( rc < 0 )
@@ -102,6 +104,13 @@ static int cf_check map_range(
}
ASSERT(rc < size);
*c += rc;
+ if ( map->map )
+ {
+ int rc2 = rangeset_add_range(map->bar->unmap_mem, s, s + rc);
+
+ if ( rc2 )
+ return rc2;
+ }
s += rc;
if ( general_preempt_check() )
return -ERESTART;
@@ -185,12 +194,13 @@ static int map_bars(struct vpci_header *header, struct
domain *d, bool map)
.map = map,
.bar = bar,
};
+ struct rangeset *r = map ? bar->map_mem : bar->unmap_mem;
int rc;
- if ( rangeset_is_empty(bar->mem) )
+ if ( rangeset_is_empty(r) )
continue;
- rc = rangeset_consume_ranges(bar->mem, map_range, &data);
+ rc = rangeset_consume_ranges(r, map_range, &data);
if ( rc )
return rc;
@@ -248,8 +258,13 @@ bool vpci_process_pending(struct vcpu *v)
/* Clean all the rangesets */
for ( i = 0; i < ARRAY_SIZE(header->bars); i++ )
- if ( !rangeset_is_empty(header->bars[i].mem) )
- rangeset_purge(header->bars[i].mem);
+ {
+ if ( !rangeset_is_empty(header->bars[i].map_mem) )
+ rangeset_purge(header->bars[i].map_mem);
+
+ if ( !rangeset_is_empty(header->bars[i].unmap_mem) )
+ rangeset_purge(header->bars[i].unmap_mem);
+ }
v->vpci.pdev = NULL;
@@ -275,10 +290,10 @@ static int __init apply_map(struct domain *d, const
struct pci_dev *pdev,
struct vpci_bar *bar = &header->bars[i];
struct map_data data = { .d = d, .map = true, .bar = bar };
- if ( rangeset_is_empty(bar->mem) )
+ if ( rangeset_is_empty(bar->map_mem) )
continue;
- while ( (rc = rangeset_consume_ranges(bar->mem, map_range,
+ while ( (rc = rangeset_consume_ranges(bar->map_mem, map_range,
&data)) == -ERESTART )
{
/*
@@ -329,6 +344,13 @@ static int modify_bars(const struct pci_dev *pdev,
uint16_t cmd, bool rom_only)
ASSERT(rw_is_write_locked(&pdev->domain->pci_lock));
+ if ( !(cmd & PCI_COMMAND_MEMORY) )
+ {
+ defer_map(pdev, cmd, rom_only);
+
+ return 0;
+ }
+
/*
* Create a rangeset per BAR that represents the current device memory
* region and compare it against all the currently active BAR memory
@@ -349,7 +371,7 @@ static int modify_bars(const struct pci_dev *pdev, uint16_t
cmd, bool rom_only)
unsigned long start_guest = PFN_DOWN(bar->guest_addr);
unsigned long end_guest = PFN_DOWN(bar->guest_addr + bar->size - 1);
- if ( !bar->mem )
+ if ( !bar->map_mem || !bar->unmap_mem )
continue;
if ( !MAPPABLE_BAR(bar) ||
@@ -367,7 +389,7 @@ static int modify_bars(const struct pci_dev *pdev, uint16_t
cmd, bool rom_only)
continue;
}
- ASSERT(rangeset_is_empty(bar->mem));
+ ASSERT(rangeset_is_empty(bar->map_mem));
/*
* Make sure that the guest set address has the same page offset
@@ -382,7 +404,7 @@ static int modify_bars(const struct pci_dev *pdev, uint16_t
cmd, bool rom_only)
return -EINVAL;
}
- rc = rangeset_add_range(bar->mem, start_guest, end_guest);
+ rc = rangeset_add_range(bar->map_mem, start_guest, end_guest);
if ( rc )
{
printk(XENLOG_G_WARNING "Failed to add [%lx, %lx]: %d\n",
@@ -395,10 +417,10 @@ static int modify_bars(const struct pci_dev *pdev,
uint16_t cmd, bool rom_only)
{
struct vpci_bar *prev_bar = &header->bars[j];
- if ( rangeset_is_empty(prev_bar->mem) )
+ if ( rangeset_is_empty(prev_bar->map_mem) )
continue;
- rc = rangeset_remove_range(prev_bar->mem, start_guest, end_guest);
+ rc = rangeset_remove_range(prev_bar->map_mem, start_guest,
end_guest);
if ( rc )
{
gprintk(XENLOG_WARNING,
@@ -408,7 +430,7 @@ static int modify_bars(const struct pci_dev *pdev, uint16_t
cmd, bool rom_only)
}
}
- rc = pci_sanitize_bar_memory(bar->mem);
+ rc = pci_sanitize_bar_memory(bar->map_mem);
if ( rc )
{
gprintk(XENLOG_WARNING,
@@ -429,10 +451,10 @@ static int modify_bars(const struct pci_dev *pdev,
uint16_t cmd, bool rom_only)
{
const struct vpci_bar *bar = &header->bars[j];
- if ( rangeset_is_empty(bar->mem) )
+ if ( rangeset_is_empty(bar->map_mem) )
continue;
- rc = rangeset_remove_range(bar->mem, start, end);
+ rc = rangeset_remove_range(bar->map_mem, start, end);
if ( rc )
{
gprintk(XENLOG_WARNING,
@@ -486,7 +508,7 @@ static int modify_bars(const struct pci_dev *pdev, uint16_t
cmd, bool rom_only)
{
const struct vpci_bar *bar = &header->bars[j];
- if ( !rangeset_overlaps_range(bar->mem, start, end) ||
+ if ( !rangeset_overlaps_range(bar->map_mem, start, end) ||
/*
* If only the ROM enable bit is toggled check against
* other BARs in the same device for overlaps, but not
@@ -497,7 +519,7 @@ static int modify_bars(const struct pci_dev *pdev, uint16_t
cmd, bool rom_only)
bar->type == VPCI_BAR_ROM) )
continue;
- rc = rangeset_remove_range(bar->mem, start, end);
+ rc = rangeset_remove_range(bar->map_mem, start, end);
if ( rc )
{
gprintk(XENLOG_WARNING,
@@ -752,12 +774,28 @@ static int bar_add_rangeset(const struct pci_dev *pdev,
struct vpci_bar *bar,
unsigned int i)
{
char str[32];
+ int rc = 0;
snprintf(str, sizeof(str), "%pp:BAR%u", &pdev->sbdf, i);
- bar->mem = rangeset_new(pdev->domain, str, RANGESETF_no_print);
+ bar->map_mem = rangeset_new(pdev->domain, str, RANGESETF_no_print);
+ bar->unmap_mem = rangeset_new(pdev->domain, str, RANGESETF_no_print);
+
+ if ( !bar->map_mem )
+ rc = -ENOMEM;
+
+ if ( !bar->unmap_mem )
+ rc = -ENOMEM;
- return !bar->mem ? -ENOMEM : 0;
+ if ( rc == -ENOMEM )
+ {
+ rangeset_destroy(bar->map_mem);
+ rangeset_destroy(bar->unmap_mem);
+ bar->map_mem = NULL;
+ bar->unmap_mem = NULL;
+ }
+
+ return rc;
}
static int cf_check init_header(struct pci_dev *pdev)
diff --git a/xen/drivers/vpci/vpci.c b/xen/drivers/vpci/vpci.c
index d2f0f97e0a04..c0198aa1b08d 100644
--- a/xen/drivers/vpci/vpci.c
+++ b/xen/drivers/vpci/vpci.c
@@ -118,7 +118,10 @@ void vpci_deassign_device(struct pci_dev *pdev)
}
for ( i = 0; i < ARRAY_SIZE(pdev->vpci->header.bars); i++ )
- rangeset_destroy(pdev->vpci->header.bars[i].mem);
+ {
+ rangeset_destroy(pdev->vpci->header.bars[i].map_mem);
+ rangeset_destroy(pdev->vpci->header.bars[i].unmap_mem);
+ }
xfree(pdev->vpci->msix);
xfree(pdev->vpci->msi);
diff --git a/xen/include/xen/vpci.h b/xen/include/xen/vpci.h
index 27eebdcef170..e74359848440 100644
--- a/xen/include/xen/vpci.h
+++ b/xen/include/xen/vpci.h
@@ -101,7 +101,8 @@ struct vpci {
uint64_t guest_addr;
uint64_t size;
uint64_t resizable_sizes;
- struct rangeset *mem;
+ struct rangeset *map_mem;
+ struct rangeset *unmap_mem;
enum {
VPCI_BAR_EMPTY,
VPCI_BAR_IO,
--
2.49.0
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |