/*
* Jailhouse, a Linux-based partitioning hypervisor
*
- * Copyright (c) Siemens AG, 2014
+ * Copyright (c) Siemens AG, 2014, 2015
*
* Authors:
* Ivan Kolchin <ivan.kolchin@siemens.com>
static const struct pci_cfg_control endpoint_write[PCI_CONFIG_HEADER_SIZE] = {
[0x04/4] = {PCI_CONFIG_ALLOW, 0xffffffff}, /* Command, Status */
[0x0c/4] = {PCI_CONFIG_ALLOW, 0xff00ffff}, /* BIST, Lat., Cacheline */
+ [0x30/4] = {PCI_CONFIG_RDONLY, 0xffffffff}, /* ROM BAR */
[0x3c/4] = {PCI_CONFIG_ALLOW, 0x000000ff}, /* Int Line */
};
unsigned int size, u32 *value)
{
const struct jailhouse_pci_capability *cap;
- unsigned int cap_offs;
+ unsigned int bar_no, cap_offs;
if (!device) {
*value = -1;
if (device->info->type == JAILHOUSE_PCI_TYPE_IVSHMEM)
return pci_ivshmem_cfg_read(device, address, size, value);
+ /* Emulate BARs for physical devices */
+ if (device->info->type == JAILHOUSE_PCI_TYPE_DEVICE) {
+ /* Emulate BAR access, always returning the shadow value. */
+ if (address >= PCI_CFG_BAR && address <= PCI_CFG_BAR_END) {
+ bar_no = (address - PCI_CFG_BAR) / 4;
+ *value = device->bar[bar_no] >> ((address % 4) * 8);
+ return PCI_ACCESS_DONE;
+ }
+
+ /* We do not expose ROMs. */
+ if (address >= PCI_CFG_ROMBAR && address < PCI_CFG_CAPS) {
+ *value = 0;
+ return PCI_ACCESS_DONE;
+ }
+ }
+
if (address < PCI_CONFIG_HEADER_SIZE)
return PCI_ACCESS_PERFORM;
unsigned int bias_shift = (address % 4) * 8;
u32 mask = BYTE_MASK(size) << bias_shift;
struct pci_cfg_control cfg_control;
- unsigned int cap_offs;
+ unsigned int bar_no, cap_offs;
if (!device)
return PCI_ACCESS_REJECT;
if (device->info->type == JAILHOUSE_PCI_TYPE_IVSHMEM)
return pci_ivshmem_cfg_write(device, address, size, value);
+ value <<= bias_shift;
+
+ /* Emulate BARs for physical devices */
+ if (device->info->type == JAILHOUSE_PCI_TYPE_DEVICE &&
+ address >= PCI_CFG_BAR && address <= PCI_CFG_BAR_END) {
+ bar_no = (address - PCI_CFG_BAR) / 4;
+ mask &= device->info->bar_mask[bar_no];
+ device->bar[bar_no] &= ~mask;
+ device->bar[bar_no] |= value & mask;
+ return PCI_ACCESS_DONE;
+ }
+
if (address < PCI_CONFIG_HEADER_SIZE) {
if (device->info->type == JAILHOUSE_PCI_TYPE_BRIDGE)
cfg_control = bridge_write[address / 4];
if (!cap || !(cap->flags & JAILHOUSE_PCICAPS_WRITE))
return PCI_ACCESS_REJECT;
- value <<= bias_shift;
-
cap_offs = address - cap->start;
if (cap->id == PCI_CAP_MSI &&
(cap_offs < 10 || (device->info->msi_64bits && cap_offs < 14))) {
static int pci_add_physical_device(struct cell *cell, struct pci_device *device)
{
- unsigned int size = device->info->msix_region_size;
+ unsigned int n, size = device->info->msix_region_size;
int err;
printk("Adding PCI device %02x:%02x.%x to cell \"%s\"\n",
PCI_BDF_PARAMS(device->info->bdf), cell->config->name);
+ for (n = 0; n < PCI_NUM_BARS; n ++)
+ device->bar[n] = pci_read_config(device->info->bdf,
+ PCI_CFG_BAR + n * 4, 4);
+
err = arch_pci_add_physical_device(cell, device);
if (!err && device->info->msix_address) {