dbb8aafa702b8b4f5568e08641d98471fd04e0f8 has a bug:
The virtual CMD value we get from reg_entry->data is not the proper value
because reg_entry->data only holds the emulated bits and the
PCI_COMMAND_IO/PCI_COMMAND_MEMORY bits are not in it.
Instead, we can use pt_pci_read_config(&ptdev->dev, PCI_COMMAND, 2) to get the
proper value.
We should only update the mapping of the related BAR, NOT the mappings of ALL
BARs.
In pt_exp_rom_bar_reg_write(), we should also update the mapping. And for
PCI_ROM_SLOT, when the PCI_ROM_ADDRESS_ENABLE bit is 0, we should not have the
mapping.
Signed-off-by: Dexuan Cui <dexuan.cui@xxxxxxxxx>
diff --git a/hw/pass-through.c b/hw/pass-through.c
index 6a53137..d2bed51 100644
--- a/hw/pass-through.c
+++ b/hw/pass-through.c
@@ -1791,64 +1791,74 @@ out:
}
/* mapping BAR */
-static void pt_bar_mapping(struct pt_dev *ptdev, int io_enable, int mem_enable)
+static void pt_bar_mapping_one(struct pt_dev *ptdev, int bar, int io_enable,
+ int mem_enable)
{
PCIDevice *dev = (PCIDevice *)&ptdev->dev;
PCIIORegion *r;
struct pt_region *base = NULL;
uint32_t r_size = 0, r_addr = -1;
int ret = 0;
- int i;
- for (i=0; i<PCI_NUM_REGIONS; i++)
- {
- r = &dev->io_regions[i];
+ r = &dev->io_regions[bar];
- /* check valid region */
- if (!r->size)
- continue;
+ /* check valid region */
+ if (!r->size)
+ return;
- base = &ptdev->bases[i];
- /* skip unused BAR or upper 64bit BAR */
- if ((base->bar_flag == PT_BAR_FLAG_UNUSED) ||
- (base->bar_flag == PT_BAR_FLAG_UPPER))
- continue;
+ base = &ptdev->bases[bar];
+ /* skip unused BAR or upper 64bit BAR */
+ if ((base->bar_flag == PT_BAR_FLAG_UNUSED) ||
+ (base->bar_flag == PT_BAR_FLAG_UPPER))
+ return;
- /* copy region address to temporary */
- r_addr = r->addr;
+ /* copy region address to temporary */
+ r_addr = r->addr;
- /* need unmapping in case I/O Space or Memory Space disable */
- if (((base->bar_flag == PT_BAR_FLAG_IO) && !io_enable ) ||
- ((base->bar_flag == PT_BAR_FLAG_MEM) && !mem_enable ))
+ /* need unmapping in case I/O Space or Memory Space disable */
+ if (((base->bar_flag == PT_BAR_FLAG_IO) && !io_enable ) ||
+ ((base->bar_flag == PT_BAR_FLAG_MEM) && !mem_enable ))
+ r_addr = -1;
+ if ( (bar == PCI_ROM_SLOT) && (r_addr != -1) )
+ {
+ uint32_t rom_reg;
+ rom_reg = pt_pci_read_config(&ptdev->dev, PCI_ROM_ADDRESS, 4);
+ if ( !(rom_reg & PCI_ROM_ADDRESS_ENABLE) )
r_addr = -1;
+ }
- /* prevent guest software mapping memory resource to 00000000h */
- if ((base->bar_flag == PT_BAR_FLAG_MEM) && (r_addr == 0))
- r_addr = -1;
+ /* prevent guest software mapping memory resource to 00000000h */
+ if ((base->bar_flag == PT_BAR_FLAG_MEM) && (r_addr == 0))
+ r_addr = -1;
- /* align resource size (memory type only) */
- r_size = r->size;
- PT_GET_EMUL_SIZE(base->bar_flag, r_size);
-
- /* check overlapped address */
- ret = pt_chk_bar_overlap(dev->bus, dev->devfn,
- r_addr, r_size, r->type);
- if (ret > 0)
- PT_LOG("Warning: ptdev[%02x:%02x.%x][Region:%d][Address:%08xh]"
- "[Size:%08xh] is overlapped.\n", pci_bus_num(dev->bus),
- (dev->devfn >> 3) & 0x1F, (dev->devfn & 0x7),
- i, r_addr, r_size);
-
- /* check whether we need to update the mapping or not */
- if (r_addr != ptdev->bases[i].e_physbase)
- {
- /* mapping BAR */
- r->map_func((PCIDevice *)ptdev, i, r_addr,
- r_size, r->type);
- }
+ /* align resource size (memory type only) */
+ r_size = r->size;
+ PT_GET_EMUL_SIZE(base->bar_flag, r_size);
+
+ /* check overlapped address */
+ ret = pt_chk_bar_overlap(dev->bus, dev->devfn,
+ r_addr, r_size, r->type);
+ if (ret > 0)
+ PT_LOG("Warning: ptdev[%02x:%02x.%x][Region:%d][Address:%08xh]"
+ "[Size:%08xh] is overlapped.\n", pci_bus_num(dev->bus),
+ (dev->devfn >> 3) & 0x1F, (dev->devfn & 0x7),
+ bar, r_addr, r_size);
+
+ /* check whether we need to update the mapping or not */
+ if (r_addr != ptdev->bases[bar].e_physbase)
+ {
+ /* mapping BAR */
+ r->map_func((PCIDevice *)ptdev, bar, r_addr,
+ r_size, r->type);
}
+}
- return;
+static void pt_bar_mapping(struct pt_dev *ptdev, int io_enable, int mem_enable)
+{
+ int i;
+
+ for (i=0; i<PCI_NUM_REGIONS; i++)
+ pt_bar_mapping_one(ptdev, i, io_enable, mem_enable);
}
/* check power state transition */
@@ -3051,6 +3061,7 @@ static int pt_bar_reg_write(struct pt_dev *ptdev,
uint32_t prev_offset;
uint32_t r_size = 0;
int index = 0;
+ uint16_t cmd;
/* get BAR index */
index = pt_bar_offset_to_index(reg->offset);
@@ -3170,14 +3181,10 @@ exit:
*value = PT_MERGE_VALUE(*value, dev_value, throughable_mask);
/* After BAR reg update, we need to remap BAR*/
- reg_grp_entry = pt_find_reg_grp(ptdev, PCI_COMMAND);
- if (reg_grp_entry)
- {
- reg_entry = pt_find_reg(reg_grp_entry, PCI_COMMAND);
- if (reg_entry)
- pt_bar_mapping(ptdev, reg_entry->data & PCI_COMMAND_IO,
- reg_entry->data & PCI_COMMAND_MEMORY);
- }
+ cmd = pt_pci_read_config(&ptdev->dev, PCI_COMMAND, 2);
+ pt_bar_mapping_one(ptdev, index, cmd & PCI_COMMAND_IO,
+ cmd & PCI_COMMAND_MEMORY);
+
return 0;
}
@@ -3195,6 +3202,7 @@ static int pt_exp_rom_bar_reg_write(struct pt_dev *ptdev,
uint32_t r_size = 0;
uint32_t bar_emu_mask = 0;
uint32_t bar_ro_mask = 0;
+ uint16_t cmd;
r = &d->io_regions[PCI_ROM_SLOT];
r_size = r->size;
@@ -3217,6 +3225,11 @@ static int pt_exp_rom_bar_reg_write(struct pt_dev *ptdev,
throughable_mask = ~bar_emu_mask & valid_mask;
*value = PT_MERGE_VALUE(*value, dev_value, throughable_mask);
+ /* After BAR reg update, we need to remap BAR*/
+ cmd = pt_pci_read_config(&ptdev->dev, PCI_COMMAND, 2);
+ pt_bar_mapping_one(ptdev, PCI_ROM_SLOT, cmd & PCI_COMMAND_IO,
+ cmd & PCI_COMMAND_MEMORY);
+
return 0;
}
fix_bar_mapping.patch
Description: fix_bar_mapping.patch
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel
|