* BAR's enable bit has changed with the memory decoding bit already enabled.
* If rom_only is not set then it's the memory decoding bit that changed.
*/
-static void modify_decoding(const struct pci_dev *pdev, bool map, bool rom_only)
+static void modify_decoding(const struct pci_dev *pdev, uint16_t cmd,
+ bool rom_only)
{
struct vpci_header *header = &pdev->vpci->header;
uint8_t slot = PCI_SLOT(pdev->devfn), func = PCI_FUNC(pdev->devfn);
- uint16_t cmd;
+ bool map = cmd & PCI_COMMAND_MEMORY;
unsigned int i;
for ( i = 0; i < ARRAY_SIZE(header->bars); i++ )
header->bars[i].enabled = map;
}
- ASSERT(!rom_only);
- cmd = pci_conf_read16(pdev->seg, pdev->bus, slot, func, PCI_COMMAND);
- cmd &= ~PCI_COMMAND_MEMORY;
- cmd |= map ? PCI_COMMAND_MEMORY : 0;
- pci_conf_write16(pdev->seg, pdev->bus, slot, func, PCI_COMMAND,
- cmd);
+ if ( !rom_only )
+ pci_conf_write16(pdev->seg, pdev->bus, slot, func, PCI_COMMAND,
+ cmd);
+ else
+ ASSERT_UNREACHABLE();
}
bool vpci_process_pending(struct vcpu *v)
{
struct map_data data = {
.d = v->domain,
- .map = v->vpci.map,
+ .map = v->vpci.cmd & PCI_COMMAND_MEMORY,
};
int rc = rangeset_consume_ranges(v->vpci.mem, map_range, &data);
spin_lock(&v->vpci.pdev->vpci->lock);
/* Disable memory decoding unconditionally on failure. */
- modify_decoding(v->vpci.pdev, !rc && v->vpci.map,
+ modify_decoding(v->vpci.pdev,
+ rc ? v->vpci.cmd & ~PCI_COMMAND_MEMORY : v->vpci.cmd,
!rc && v->vpci.rom_only);
spin_unlock(&v->vpci.pdev->vpci->lock);
}
static int __init apply_map(struct domain *d, const struct pci_dev *pdev,
- struct rangeset *mem)
+ struct rangeset *mem, uint16_t cmd)
{
struct map_data data = { .d = d, .map = true };
int rc;
process_pending_softirqs();
rangeset_destroy(mem);
if ( !rc )
- modify_decoding(pdev, true, false);
+ modify_decoding(pdev, cmd, false);
return rc;
}
static void defer_map(struct domain *d, struct pci_dev *pdev,
- struct rangeset *mem, bool map, bool rom_only)
+ struct rangeset *mem, uint16_t cmd, bool rom_only)
{
struct vcpu *curr = current;
*/
curr->vpci.pdev = pdev;
curr->vpci.mem = mem;
- curr->vpci.map = map;
+ curr->vpci.cmd = cmd;
curr->vpci.rom_only = rom_only;
}
-static int modify_bars(const struct pci_dev *pdev, bool map, bool rom_only)
+static int modify_bars(const struct pci_dev *pdev, uint16_t cmd, bool rom_only)
{
struct vpci_header *header = &pdev->vpci->header;
struct rangeset *mem = rangeset_new(NULL, NULL, 0);
* be called iff the memory decoding bit is enabled, thus the operation
* will always be to establish mappings and process all the BARs.
*/
- ASSERT(map && !rom_only);
- return apply_map(pdev->domain, pdev, mem);
+ ASSERT((cmd & PCI_COMMAND_MEMORY) && !rom_only);
+ return apply_map(pdev->domain, pdev, mem, cmd);
}
- defer_map(dev->domain, dev, mem, map, rom_only);
+ defer_map(dev->domain, dev, mem, cmd, rom_only);
return 0;
}
* memory decoding bit has not been changed, so leave everything as-is,
* hoping the guest will realize and try again.
*/
- modify_bars(pdev, cmd & PCI_COMMAND_MEMORY, false);
+ modify_bars(pdev, cmd, false);
else
pci_conf_write16(pdev->seg, pdev->bus, slot, func, reg, cmd);
}
header->rom_enabled = new_enabled;
pci_conf_write32(pdev->seg, pdev->bus, slot, func, reg, val);
}
- else if ( modify_bars(pdev, new_enabled, true) )
+ /*
+ * Pass PCI_COMMAND_MEMORY or 0 to signal a map/unmap request, note that
+ * this fabricated command is never going to be written to the register.
+ */
+ else if ( modify_bars(pdev, new_enabled ? PCI_COMMAND_MEMORY : 0, true) )
/*
* No memory has been added or removed from the p2m (because the actual
* p2m changes are deferred in defer_map) and the ROM enable bit has
rom->type = VPCI_BAR_EMPTY;
}
- return (cmd & PCI_COMMAND_MEMORY) ? modify_bars(pdev, true, false) : 0;
+ return (cmd & PCI_COMMAND_MEMORY) ? modify_bars(pdev, cmd, false) : 0;
}
REGISTER_VPCI_INIT(init_bars, VPCI_PRIORITY_MIDDLE);