@@ -30,6 +30,7 @@
struct map_data {
struct domain *d;
+ const struct vpci_bar *bar;
bool map;
};
@@ -41,8 +42,21 @@ static int map_range(unsigned long s, unsigned long e, void *data,
for ( ; ; )
{
+ /* Start address of the BAR as seen by the guest. */
+ gfn_t start_gfn = _gfn(PFN_DOWN(is_hardware_domain(map->d)
+ ? map->bar->addr
+ : map->bar->guest_reg));
+ /* Physical start address of the BAR. */
+ mfn_t start_mfn = _mfn(PFN_DOWN(map->bar->addr));
unsigned long size = e - s + 1;
+ /*
+ * Ranges to be mapped don't always start at the BAR start address, as
+ * there can be holes or partially consumed ranges. Account for the
+ * offset of the current address from the BAR start.
+ */
+ start_gfn = gfn_add(start_gfn, s - mfn_x(start_mfn));
+
/*
* ARM TODOs:
* - On ARM whether the memory is prefetchable or not should be passed
@@ -52,8 +66,8 @@ static int map_range(unsigned long s, unsigned long e, void *data,
* - {un}map_mmio_regions doesn't support preemption.
*/
- rc = map->map ? map_mmio_regions(map->d, _gfn(s), size, _mfn(s))
- : unmap_mmio_regions(map->d, _gfn(s), size, _mfn(s));
+ rc = map->map ? map_mmio_regions(map->d, start_gfn, size, _mfn(s))
+ : unmap_mmio_regions(map->d, start_gfn, size, _mfn(s));
if ( rc == 0 )
{
*c += size;
@@ -62,8 +76,8 @@ static int map_range(unsigned long s, unsigned long e, void *data,
if ( rc < 0 )
{
printk(XENLOG_G_WARNING
- "Failed to identity %smap [%lx, %lx] for d%d: %d\n",
- map->map ? "" : "un", s, e, map->d->domain_id, rc);
+ "Failed to %smap [%lx, %lx] for %pd: %d\n",
+ map->map ? "" : "un", s, e, map->d, rc);
break;
}
ASSERT(rc < size);
@@ -154,6 +168,7 @@ bool vpci_process_pending(struct vcpu *v)
if ( rangeset_is_empty(bar->mem) )
continue;
+ data.bar = bar;
rc = rangeset_consume_ranges(bar->mem, map_range, &data);
if ( rc == -ERESTART )
@@ -206,6 +221,7 @@ static int __init apply_map(struct domain *d, const struct pci_dev *pdev,
if ( rangeset_is_empty(bar->mem) )
continue;
+ data.bar = bar;
while ( (rc = rangeset_consume_ranges(bar->mem, map_range,
&data)) == -ERESTART )
process_pending_softirqs();