mirror of https://gitee.com/openkylin/qemu.git
XSA 128 129 130 131
-----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.12 (GNU/Linux) iQIcBAABAgAGBQJVbc/eAAoJEIlPj0hw4a6QGg8P/jUwi4GqK4cbKrTJpcCVJ3OW n87uvaTWqUOtx5c88KcTHJeu1B7CigNgJaNbbYcvmbuPt8Sjo+bUUYCvBi3cZHq0 MOvdtbSX8KOK7R1Dal6Hf0S3gxxlfCpbys6Bu50SZcKeXYu6Gij0njHypxC8Y5NK P+JIAyWRrt+XeOO302dzX1KR8NirCLbzFYcglm4fETiGG5ucfeFqScYs8jrM4Mmg cd1MBAdDhRuazG6Q2p1HldruC6KgNArYBU0dxPbMlvrxaePVnq7hWQOLXM1n+7Ue rXA9eUHFLQqvqtipBHFjPgUIikP/gw+JkAltwnbunkfx1n9DtaF+HYRWMBTiDXwO tnKTOylXyC5GnMJlf6EkbH1esmmWReCVl3NYRFSWm8c5sJT1AvaVsIAiWStwcg0x 4sPebrYEjWffCSDtgP2ooI7JIVKeefYUzJLpkpkEZQ2XGwaQKn7KVLUlCFdyEHgH FJMNt4KrYTUMzItGqzLv2H7qL4VyeT08HkZbYYXxvILnmSDUG+lNptQauNx0MnnN 77SdVsEm0JyI9oBsOvECILOY+drI7IXDbxDqxhi2K3GOUOVwPWlWbylgcNXMtzRn df7o7u5iFg7JWWWHpnEbED+U3RRjJTWNwCLxVoOq5FzPD6MxaxYE57OZMFvQoLsv MMi/VoURdXahAKpQIphv =ThTq -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/sstabellini/tags/xen-15-06-02-tag' into staging XSA 128 129 130 131 # gpg: Signature made Tue Jun 2 16:46:38 2015 BST using RSA key ID 70E1AE90 # gpg: Good signature from "Stefano Stabellini <stefano.stabellini@eu.citrix.com>" * remotes/sstabellini/tags/xen-15-06-02-tag: xen/pt: unknown PCI config space fields should be read-only xen/pt: add a few PCI config space field descriptions xen/pt: mark reserved bits in PCI config space fields xen/pt: mark all PCIe capability bits read-only xen/pt: split out calculation of throughable mask in PCI config space handling xen/pt: correctly handle PM status bit xen/pt: consolidate PM capability emu_mask xen/MSI: don't open-code pass-through of enable bit modifications xen/MSI-X: limit error messages xen: don't allow guest to control MSI mask register xen: properly gate host writes of modified PCI CFG contents Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
42d58e7c67
|
@ -21,10 +21,6 @@
|
||||||
#include "hw/pci/msi.h"
|
#include "hw/pci/msi.h"
|
||||||
#include "qemu/range.h"
|
#include "qemu/range.h"
|
||||||
|
|
||||||
/* Eventually those constants should go to Linux pci_regs.h */
|
|
||||||
#define PCI_MSI_PENDING_32 0x10
|
|
||||||
#define PCI_MSI_PENDING_64 0x14
|
|
||||||
|
|
||||||
/* PCI_MSI_ADDRESS_LO */
|
/* PCI_MSI_ADDRESS_LO */
|
||||||
#define PCI_MSI_ADDRESS_LO_MASK (~0x3)
|
#define PCI_MSI_ADDRESS_LO_MASK (~0x3)
|
||||||
|
|
||||||
|
|
|
@ -234,11 +234,12 @@ static void xen_pt_pci_write_config(PCIDevice *d, uint32_t addr,
|
||||||
int index = 0;
|
int index = 0;
|
||||||
XenPTRegGroup *reg_grp_entry = NULL;
|
XenPTRegGroup *reg_grp_entry = NULL;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
uint32_t read_val = 0;
|
uint32_t read_val = 0, wb_mask;
|
||||||
int emul_len = 0;
|
int emul_len = 0;
|
||||||
XenPTReg *reg_entry = NULL;
|
XenPTReg *reg_entry = NULL;
|
||||||
uint32_t find_addr = addr;
|
uint32_t find_addr = addr;
|
||||||
XenPTRegInfo *reg = NULL;
|
XenPTRegInfo *reg = NULL;
|
||||||
|
bool wp_flag = false;
|
||||||
|
|
||||||
if (xen_pt_pci_config_access_check(d, addr, len)) {
|
if (xen_pt_pci_config_access_check(d, addr, len)) {
|
||||||
return;
|
return;
|
||||||
|
@ -271,10 +272,17 @@ static void xen_pt_pci_write_config(PCIDevice *d, uint32_t addr,
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
XEN_PT_ERR(d, "pci_read_block failed. return value: %d.\n", rc);
|
XEN_PT_ERR(d, "pci_read_block failed. return value: %d.\n", rc);
|
||||||
memset(&read_val, 0xff, len);
|
memset(&read_val, 0xff, len);
|
||||||
|
wb_mask = 0;
|
||||||
|
} else {
|
||||||
|
wb_mask = 0xFFFFFFFF >> ((4 - len) << 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* pass directly to the real device for passthrough type register group */
|
/* pass directly to the real device for passthrough type register group */
|
||||||
if (reg_grp_entry == NULL) {
|
if (reg_grp_entry == NULL) {
|
||||||
|
if (!s->permissive) {
|
||||||
|
wb_mask = 0;
|
||||||
|
wp_flag = true;
|
||||||
|
}
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -295,9 +303,17 @@ static void xen_pt_pci_write_config(PCIDevice *d, uint32_t addr,
|
||||||
uint32_t real_offset = reg_grp_entry->base_offset + reg->offset;
|
uint32_t real_offset = reg_grp_entry->base_offset + reg->offset;
|
||||||
uint32_t valid_mask = 0xFFFFFFFF >> ((4 - emul_len) << 3);
|
uint32_t valid_mask = 0xFFFFFFFF >> ((4 - emul_len) << 3);
|
||||||
uint8_t *ptr_val = NULL;
|
uint8_t *ptr_val = NULL;
|
||||||
|
uint32_t wp_mask = reg->emu_mask | reg->ro_mask;
|
||||||
|
|
||||||
valid_mask <<= (find_addr - real_offset) << 3;
|
valid_mask <<= (find_addr - real_offset) << 3;
|
||||||
ptr_val = (uint8_t *)&val + (real_offset & 3);
|
ptr_val = (uint8_t *)&val + (real_offset & 3);
|
||||||
|
if (!s->permissive) {
|
||||||
|
wp_mask |= reg->res_mask;
|
||||||
|
}
|
||||||
|
if (wp_mask == (0xFFFFFFFF >> ((4 - reg->size) << 3))) {
|
||||||
|
wb_mask &= ~((wp_mask >> ((find_addr - real_offset) << 3))
|
||||||
|
<< ((len - emul_len) << 3));
|
||||||
|
}
|
||||||
|
|
||||||
/* do emulation based on register size */
|
/* do emulation based on register size */
|
||||||
switch (reg->size) {
|
switch (reg->size) {
|
||||||
|
@ -339,6 +355,16 @@ static void xen_pt_pci_write_config(PCIDevice *d, uint32_t addr,
|
||||||
} else {
|
} else {
|
||||||
/* nothing to do with passthrough type register,
|
/* nothing to do with passthrough type register,
|
||||||
* continue to find next byte */
|
* continue to find next byte */
|
||||||
|
if (!s->permissive) {
|
||||||
|
wb_mask &= ~(0xff << ((len - emul_len) << 3));
|
||||||
|
/* Unused BARs will make it here, but we don't want to issue
|
||||||
|
* warnings for writes to them (bogus writes get dealt with
|
||||||
|
* above).
|
||||||
|
*/
|
||||||
|
if (index < 0) {
|
||||||
|
wp_flag = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
emul_len--;
|
emul_len--;
|
||||||
find_addr++;
|
find_addr++;
|
||||||
}
|
}
|
||||||
|
@ -350,10 +376,26 @@ static void xen_pt_pci_write_config(PCIDevice *d, uint32_t addr,
|
||||||
memory_region_transaction_commit();
|
memory_region_transaction_commit();
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if (!(reg && reg->no_wb)) {
|
if (wp_flag && !s->permissive_warned) {
|
||||||
|
s->permissive_warned = true;
|
||||||
|
xen_pt_log(d, "Write-back to unknown field 0x%02x (partially) inhibited (0x%0*x)\n",
|
||||||
|
addr, len * 2, wb_mask);
|
||||||
|
xen_pt_log(d, "If the device doesn't work, try enabling permissive mode\n");
|
||||||
|
xen_pt_log(d, "(unsafe) and if it helps report the problem to xen-devel\n");
|
||||||
|
}
|
||||||
|
for (index = 0; wb_mask; index += len) {
|
||||||
/* unknown regs are passed through */
|
/* unknown regs are passed through */
|
||||||
rc = xen_host_pci_set_block(&s->real_device, addr,
|
while (!(wb_mask & 0xff)) {
|
||||||
(uint8_t *)&val, len);
|
index++;
|
||||||
|
wb_mask >>= 8;
|
||||||
|
}
|
||||||
|
len = 0;
|
||||||
|
do {
|
||||||
|
len++;
|
||||||
|
wb_mask >>= 8;
|
||||||
|
} while (wb_mask & 0xff);
|
||||||
|
rc = xen_host_pci_set_block(&s->real_device, addr + index,
|
||||||
|
(uint8_t *)&val + index, len);
|
||||||
|
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
XEN_PT_ERR(d, "pci_write_block failed. return value: %d.\n", rc);
|
XEN_PT_ERR(d, "pci_write_block failed. return value: %d.\n", rc);
|
||||||
|
@ -807,6 +849,7 @@ static void xen_pt_unregister_device(PCIDevice *d)
|
||||||
|
|
||||||
static Property xen_pci_passthrough_properties[] = {
|
static Property xen_pci_passthrough_properties[] = {
|
||||||
DEFINE_PROP_PCI_HOST_DEVADDR("hostaddr", XenPCIPassthroughState, hostaddr),
|
DEFINE_PROP_PCI_HOST_DEVADDR("hostaddr", XenPCIPassthroughState, hostaddr),
|
||||||
|
DEFINE_PROP_BOOL("permissive", XenPCIPassthroughState, permissive, false),
|
||||||
DEFINE_PROP_END_OF_LIST(),
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -101,12 +101,12 @@ struct XenPTRegInfo {
|
||||||
uint32_t offset;
|
uint32_t offset;
|
||||||
uint32_t size;
|
uint32_t size;
|
||||||
uint32_t init_val;
|
uint32_t init_val;
|
||||||
|
/* reg reserved field mask (ON:reserved, OFF:defined) */
|
||||||
|
uint32_t res_mask;
|
||||||
/* reg read only field mask (ON:RO/ROS, OFF:other) */
|
/* reg read only field mask (ON:RO/ROS, OFF:other) */
|
||||||
uint32_t ro_mask;
|
uint32_t ro_mask;
|
||||||
/* reg emulate field mask (ON:emu, OFF:passthrough) */
|
/* reg emulate field mask (ON:emu, OFF:passthrough) */
|
||||||
uint32_t emu_mask;
|
uint32_t emu_mask;
|
||||||
/* no write back allowed */
|
|
||||||
uint32_t no_wb;
|
|
||||||
xen_pt_conf_reg_init init;
|
xen_pt_conf_reg_init init;
|
||||||
/* read/write function pointer
|
/* read/write function pointer
|
||||||
* for double_word/word/byte size */
|
* for double_word/word/byte size */
|
||||||
|
@ -177,6 +177,7 @@ typedef struct XenPTMSIXEntry {
|
||||||
uint32_t data;
|
uint32_t data;
|
||||||
uint32_t vector_ctrl;
|
uint32_t vector_ctrl;
|
||||||
bool updated; /* indicate whether MSI ADDR or DATA is updated */
|
bool updated; /* indicate whether MSI ADDR or DATA is updated */
|
||||||
|
bool warned; /* avoid issuing (bogus) warning more than once */
|
||||||
} XenPTMSIXEntry;
|
} XenPTMSIXEntry;
|
||||||
typedef struct XenPTMSIX {
|
typedef struct XenPTMSIX {
|
||||||
uint32_t ctrl_offset;
|
uint32_t ctrl_offset;
|
||||||
|
@ -196,6 +197,8 @@ struct XenPCIPassthroughState {
|
||||||
|
|
||||||
PCIHostDeviceAddress hostaddr;
|
PCIHostDeviceAddress hostaddr;
|
||||||
bool is_virtfn;
|
bool is_virtfn;
|
||||||
|
bool permissive;
|
||||||
|
bool permissive_warned;
|
||||||
XenHostPCIDevice real_device;
|
XenHostPCIDevice real_device;
|
||||||
XenPTRegion bases[PCI_NUM_REGIONS]; /* Access regions */
|
XenPTRegion bases[PCI_NUM_REGIONS]; /* Access regions */
|
||||||
QLIST_HEAD(, XenPTRegGroup) reg_grps;
|
QLIST_HEAD(, XenPTRegGroup) reg_grps;
|
||||||
|
|
|
@ -95,6 +95,18 @@ XenPTReg *xen_pt_find_reg(XenPTRegGroup *reg_grp, uint32_t address)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint32_t get_throughable_mask(const XenPCIPassthroughState *s,
|
||||||
|
const XenPTRegInfo *reg,
|
||||||
|
uint32_t valid_mask)
|
||||||
|
{
|
||||||
|
uint32_t throughable_mask = ~(reg->emu_mask | reg->ro_mask);
|
||||||
|
|
||||||
|
if (!s->permissive) {
|
||||||
|
throughable_mask &= ~reg->res_mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
return throughable_mask & valid_mask;
|
||||||
|
}
|
||||||
|
|
||||||
/****************
|
/****************
|
||||||
* general register functions
|
* general register functions
|
||||||
|
@ -157,14 +169,13 @@ static int xen_pt_byte_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
|
||||||
{
|
{
|
||||||
XenPTRegInfo *reg = cfg_entry->reg;
|
XenPTRegInfo *reg = cfg_entry->reg;
|
||||||
uint8_t writable_mask = 0;
|
uint8_t writable_mask = 0;
|
||||||
uint8_t throughable_mask = 0;
|
uint8_t throughable_mask = get_throughable_mask(s, reg, valid_mask);
|
||||||
|
|
||||||
/* modify emulate register */
|
/* modify emulate register */
|
||||||
writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
|
writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
|
||||||
cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask);
|
cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask);
|
||||||
|
|
||||||
/* create value for writing to I/O device register */
|
/* create value for writing to I/O device register */
|
||||||
throughable_mask = ~reg->emu_mask & valid_mask;
|
|
||||||
*val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
|
*val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -175,14 +186,13 @@ static int xen_pt_word_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
|
||||||
{
|
{
|
||||||
XenPTRegInfo *reg = cfg_entry->reg;
|
XenPTRegInfo *reg = cfg_entry->reg;
|
||||||
uint16_t writable_mask = 0;
|
uint16_t writable_mask = 0;
|
||||||
uint16_t throughable_mask = 0;
|
uint16_t throughable_mask = get_throughable_mask(s, reg, valid_mask);
|
||||||
|
|
||||||
/* modify emulate register */
|
/* modify emulate register */
|
||||||
writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
|
writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
|
||||||
cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask);
|
cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask);
|
||||||
|
|
||||||
/* create value for writing to I/O device register */
|
/* create value for writing to I/O device register */
|
||||||
throughable_mask = ~reg->emu_mask & valid_mask;
|
|
||||||
*val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
|
*val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -193,14 +203,13 @@ static int xen_pt_long_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
|
||||||
{
|
{
|
||||||
XenPTRegInfo *reg = cfg_entry->reg;
|
XenPTRegInfo *reg = cfg_entry->reg;
|
||||||
uint32_t writable_mask = 0;
|
uint32_t writable_mask = 0;
|
||||||
uint32_t throughable_mask = 0;
|
uint32_t throughable_mask = get_throughable_mask(s, reg, valid_mask);
|
||||||
|
|
||||||
/* modify emulate register */
|
/* modify emulate register */
|
||||||
writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
|
writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
|
||||||
cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask);
|
cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask);
|
||||||
|
|
||||||
/* create value for writing to I/O device register */
|
/* create value for writing to I/O device register */
|
||||||
throughable_mask = ~reg->emu_mask & valid_mask;
|
|
||||||
*val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
|
*val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -292,15 +301,13 @@ static int xen_pt_cmd_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
|
||||||
{
|
{
|
||||||
XenPTRegInfo *reg = cfg_entry->reg;
|
XenPTRegInfo *reg = cfg_entry->reg;
|
||||||
uint16_t writable_mask = 0;
|
uint16_t writable_mask = 0;
|
||||||
uint16_t throughable_mask = 0;
|
uint16_t throughable_mask = get_throughable_mask(s, reg, valid_mask);
|
||||||
|
|
||||||
/* modify emulate register */
|
/* modify emulate register */
|
||||||
writable_mask = ~reg->ro_mask & valid_mask;
|
writable_mask = ~reg->ro_mask & valid_mask;
|
||||||
cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask);
|
cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask);
|
||||||
|
|
||||||
/* create value for writing to I/O device register */
|
/* create value for writing to I/O device register */
|
||||||
throughable_mask = ~reg->emu_mask & valid_mask;
|
|
||||||
|
|
||||||
if (*val & PCI_COMMAND_INTX_DISABLE) {
|
if (*val & PCI_COMMAND_INTX_DISABLE) {
|
||||||
throughable_mask |= PCI_COMMAND_INTX_DISABLE;
|
throughable_mask |= PCI_COMMAND_INTX_DISABLE;
|
||||||
} else {
|
} else {
|
||||||
|
@ -454,7 +461,6 @@ static int xen_pt_bar_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
|
||||||
PCIDevice *d = &s->dev;
|
PCIDevice *d = &s->dev;
|
||||||
const PCIIORegion *r;
|
const PCIIORegion *r;
|
||||||
uint32_t writable_mask = 0;
|
uint32_t writable_mask = 0;
|
||||||
uint32_t throughable_mask = 0;
|
|
||||||
uint32_t bar_emu_mask = 0;
|
uint32_t bar_emu_mask = 0;
|
||||||
uint32_t bar_ro_mask = 0;
|
uint32_t bar_ro_mask = 0;
|
||||||
uint32_t r_size = 0;
|
uint32_t r_size = 0;
|
||||||
|
@ -511,8 +517,7 @@ static int xen_pt_bar_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* create value for writing to I/O device register */
|
/* create value for writing to I/O device register */
|
||||||
throughable_mask = ~bar_emu_mask & valid_mask;
|
*val = XEN_PT_MERGE_VALUE(*val, dev_value, 0);
|
||||||
*val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -526,9 +531,8 @@ static int xen_pt_exp_rom_bar_reg_write(XenPCIPassthroughState *s,
|
||||||
XenPTRegion *base = NULL;
|
XenPTRegion *base = NULL;
|
||||||
PCIDevice *d = (PCIDevice *)&s->dev;
|
PCIDevice *d = (PCIDevice *)&s->dev;
|
||||||
uint32_t writable_mask = 0;
|
uint32_t writable_mask = 0;
|
||||||
uint32_t throughable_mask = 0;
|
uint32_t throughable_mask = get_throughable_mask(s, reg, valid_mask);
|
||||||
pcibus_t r_size = 0;
|
pcibus_t r_size = 0;
|
||||||
uint32_t bar_emu_mask = 0;
|
|
||||||
uint32_t bar_ro_mask = 0;
|
uint32_t bar_ro_mask = 0;
|
||||||
|
|
||||||
r_size = d->io_regions[PCI_ROM_SLOT].size;
|
r_size = d->io_regions[PCI_ROM_SLOT].size;
|
||||||
|
@ -537,7 +541,6 @@ static int xen_pt_exp_rom_bar_reg_write(XenPCIPassthroughState *s,
|
||||||
r_size = xen_pt_get_emul_size(base->bar_flag, r_size);
|
r_size = xen_pt_get_emul_size(base->bar_flag, r_size);
|
||||||
|
|
||||||
/* set emulate mask and read-only mask */
|
/* set emulate mask and read-only mask */
|
||||||
bar_emu_mask = reg->emu_mask;
|
|
||||||
bar_ro_mask = (reg->ro_mask | (r_size - 1)) & ~PCI_ROM_ADDRESS_ENABLE;
|
bar_ro_mask = (reg->ro_mask | (r_size - 1)) & ~PCI_ROM_ADDRESS_ENABLE;
|
||||||
|
|
||||||
/* modify emulate register */
|
/* modify emulate register */
|
||||||
|
@ -545,7 +548,6 @@ static int xen_pt_exp_rom_bar_reg_write(XenPCIPassthroughState *s,
|
||||||
cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask);
|
cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask);
|
||||||
|
|
||||||
/* create value for writing to I/O device register */
|
/* create value for writing to I/O device register */
|
||||||
throughable_mask = ~bar_emu_mask & valid_mask;
|
|
||||||
*val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
|
*val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -580,7 +582,7 @@ static XenPTRegInfo xen_pt_emu_reg_header0[] = {
|
||||||
.offset = PCI_COMMAND,
|
.offset = PCI_COMMAND,
|
||||||
.size = 2,
|
.size = 2,
|
||||||
.init_val = 0x0000,
|
.init_val = 0x0000,
|
||||||
.ro_mask = 0xF880,
|
.res_mask = 0xF880,
|
||||||
.emu_mask = 0x0743,
|
.emu_mask = 0x0743,
|
||||||
.init = xen_pt_common_reg_init,
|
.init = xen_pt_common_reg_init,
|
||||||
.u.w.read = xen_pt_word_reg_read,
|
.u.w.read = xen_pt_word_reg_read,
|
||||||
|
@ -605,7 +607,8 @@ static XenPTRegInfo xen_pt_emu_reg_header0[] = {
|
||||||
.offset = PCI_STATUS,
|
.offset = PCI_STATUS,
|
||||||
.size = 2,
|
.size = 2,
|
||||||
.init_val = 0x0000,
|
.init_val = 0x0000,
|
||||||
.ro_mask = 0x06FF,
|
.res_mask = 0x0007,
|
||||||
|
.ro_mask = 0x06F8,
|
||||||
.emu_mask = 0x0010,
|
.emu_mask = 0x0010,
|
||||||
.init = xen_pt_status_reg_init,
|
.init = xen_pt_status_reg_init,
|
||||||
.u.w.read = xen_pt_word_reg_read,
|
.u.w.read = xen_pt_word_reg_read,
|
||||||
|
@ -754,6 +757,15 @@ static XenPTRegInfo xen_pt_emu_reg_vpd[] = {
|
||||||
.u.b.read = xen_pt_byte_reg_read,
|
.u.b.read = xen_pt_byte_reg_read,
|
||||||
.u.b.write = xen_pt_byte_reg_write,
|
.u.b.write = xen_pt_byte_reg_write,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.offset = PCI_VPD_ADDR,
|
||||||
|
.size = 2,
|
||||||
|
.ro_mask = 0x0003,
|
||||||
|
.emu_mask = 0x0003,
|
||||||
|
.init = xen_pt_common_reg_init,
|
||||||
|
.u.w.read = xen_pt_word_reg_read,
|
||||||
|
.u.w.write = xen_pt_word_reg_write,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.size = 0,
|
.size = 0,
|
||||||
},
|
},
|
||||||
|
@ -873,7 +885,7 @@ static XenPTRegInfo xen_pt_emu_reg_pcie[] = {
|
||||||
.offset = PCI_EXP_DEVCAP,
|
.offset = PCI_EXP_DEVCAP,
|
||||||
.size = 4,
|
.size = 4,
|
||||||
.init_val = 0x00000000,
|
.init_val = 0x00000000,
|
||||||
.ro_mask = 0x1FFCFFFF,
|
.ro_mask = 0xFFFFFFFF,
|
||||||
.emu_mask = 0x10000000,
|
.emu_mask = 0x10000000,
|
||||||
.init = xen_pt_common_reg_init,
|
.init = xen_pt_common_reg_init,
|
||||||
.u.dw.read = xen_pt_long_reg_read,
|
.u.dw.read = xen_pt_long_reg_read,
|
||||||
|
@ -890,6 +902,16 @@ static XenPTRegInfo xen_pt_emu_reg_pcie[] = {
|
||||||
.u.w.read = xen_pt_word_reg_read,
|
.u.w.read = xen_pt_word_reg_read,
|
||||||
.u.w.write = xen_pt_word_reg_write,
|
.u.w.write = xen_pt_word_reg_write,
|
||||||
},
|
},
|
||||||
|
/* Device Status reg */
|
||||||
|
{
|
||||||
|
.offset = PCI_EXP_DEVSTA,
|
||||||
|
.size = 2,
|
||||||
|
.res_mask = 0xFFC0,
|
||||||
|
.ro_mask = 0x0030,
|
||||||
|
.init = xen_pt_common_reg_init,
|
||||||
|
.u.w.read = xen_pt_word_reg_read,
|
||||||
|
.u.w.write = xen_pt_word_reg_write,
|
||||||
|
},
|
||||||
/* Link Control reg */
|
/* Link Control reg */
|
||||||
{
|
{
|
||||||
.offset = PCI_EXP_LNKCTL,
|
.offset = PCI_EXP_LNKCTL,
|
||||||
|
@ -901,6 +923,15 @@ static XenPTRegInfo xen_pt_emu_reg_pcie[] = {
|
||||||
.u.w.read = xen_pt_word_reg_read,
|
.u.w.read = xen_pt_word_reg_read,
|
||||||
.u.w.write = xen_pt_word_reg_write,
|
.u.w.write = xen_pt_word_reg_write,
|
||||||
},
|
},
|
||||||
|
/* Link Status reg */
|
||||||
|
{
|
||||||
|
.offset = PCI_EXP_LNKSTA,
|
||||||
|
.size = 2,
|
||||||
|
.ro_mask = 0x3FFF,
|
||||||
|
.init = xen_pt_common_reg_init,
|
||||||
|
.u.w.read = xen_pt_word_reg_read,
|
||||||
|
.u.w.write = xen_pt_word_reg_write,
|
||||||
|
},
|
||||||
/* Device Control 2 reg */
|
/* Device Control 2 reg */
|
||||||
{
|
{
|
||||||
.offset = 0x28,
|
.offset = 0x28,
|
||||||
|
@ -933,39 +964,22 @@ static XenPTRegInfo xen_pt_emu_reg_pcie[] = {
|
||||||
* Power Management Capability
|
* Power Management Capability
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* read Power Management Control/Status register */
|
|
||||||
static int xen_pt_pmcsr_reg_read(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
|
|
||||||
uint16_t *value, uint16_t valid_mask)
|
|
||||||
{
|
|
||||||
XenPTRegInfo *reg = cfg_entry->reg;
|
|
||||||
uint16_t valid_emu_mask = reg->emu_mask;
|
|
||||||
|
|
||||||
valid_emu_mask |= PCI_PM_CTRL_STATE_MASK | PCI_PM_CTRL_NO_SOFT_RESET;
|
|
||||||
|
|
||||||
valid_emu_mask = valid_emu_mask & valid_mask;
|
|
||||||
*value = XEN_PT_MERGE_VALUE(*value, cfg_entry->data, ~valid_emu_mask);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
/* write Power Management Control/Status register */
|
/* write Power Management Control/Status register */
|
||||||
static int xen_pt_pmcsr_reg_write(XenPCIPassthroughState *s,
|
static int xen_pt_pmcsr_reg_write(XenPCIPassthroughState *s,
|
||||||
XenPTReg *cfg_entry, uint16_t *val,
|
XenPTReg *cfg_entry, uint16_t *val,
|
||||||
uint16_t dev_value, uint16_t valid_mask)
|
uint16_t dev_value, uint16_t valid_mask)
|
||||||
{
|
{
|
||||||
XenPTRegInfo *reg = cfg_entry->reg;
|
XenPTRegInfo *reg = cfg_entry->reg;
|
||||||
uint16_t emu_mask = reg->emu_mask;
|
|
||||||
uint16_t writable_mask = 0;
|
uint16_t writable_mask = 0;
|
||||||
uint16_t throughable_mask = 0;
|
uint16_t throughable_mask = get_throughable_mask(s, reg, valid_mask);
|
||||||
|
|
||||||
emu_mask |= PCI_PM_CTRL_STATE_MASK | PCI_PM_CTRL_NO_SOFT_RESET;
|
|
||||||
|
|
||||||
/* modify emulate register */
|
/* modify emulate register */
|
||||||
writable_mask = emu_mask & ~reg->ro_mask & valid_mask;
|
writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
|
||||||
cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask);
|
cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask);
|
||||||
|
|
||||||
/* create value for writing to I/O device register */
|
/* create value for writing to I/O device register */
|
||||||
throughable_mask = ~emu_mask & valid_mask;
|
*val = XEN_PT_MERGE_VALUE(*val, dev_value & ~PCI_PM_CTRL_PME_STATUS,
|
||||||
*val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
|
throughable_mask);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -999,10 +1013,11 @@ static XenPTRegInfo xen_pt_emu_reg_pm[] = {
|
||||||
.offset = PCI_PM_CTRL,
|
.offset = PCI_PM_CTRL,
|
||||||
.size = 2,
|
.size = 2,
|
||||||
.init_val = 0x0008,
|
.init_val = 0x0008,
|
||||||
.ro_mask = 0xE1FC,
|
.res_mask = 0x00F0,
|
||||||
.emu_mask = 0x8100,
|
.ro_mask = 0xE10C,
|
||||||
|
.emu_mask = 0x810B,
|
||||||
.init = xen_pt_common_reg_init,
|
.init = xen_pt_common_reg_init,
|
||||||
.u.w.read = xen_pt_pmcsr_reg_read,
|
.u.w.read = xen_pt_word_reg_read,
|
||||||
.u.w.write = xen_pt_pmcsr_reg_write,
|
.u.w.write = xen_pt_pmcsr_reg_write,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -1016,13 +1031,9 @@ static XenPTRegInfo xen_pt_emu_reg_pm[] = {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Helper */
|
/* Helper */
|
||||||
static bool xen_pt_msgdata_check_type(uint32_t offset, uint16_t flags)
|
#define xen_pt_msi_check_type(offset, flags, what) \
|
||||||
{
|
((offset) == ((flags) & PCI_MSI_FLAGS_64BIT ? \
|
||||||
/* check the offset whether matches the type or not */
|
PCI_MSI_##what##_64 : PCI_MSI_##what##_32))
|
||||||
bool is_32 = (offset == PCI_MSI_DATA_32) && !(flags & PCI_MSI_FLAGS_64BIT);
|
|
||||||
bool is_64 = (offset == PCI_MSI_DATA_64) && (flags & PCI_MSI_FLAGS_64BIT);
|
|
||||||
return is_32 || is_64;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Message Control register */
|
/* Message Control register */
|
||||||
static int xen_pt_msgctrl_reg_init(XenPCIPassthroughState *s,
|
static int xen_pt_msgctrl_reg_init(XenPCIPassthroughState *s,
|
||||||
|
@ -1056,8 +1067,7 @@ static int xen_pt_msgctrl_reg_write(XenPCIPassthroughState *s,
|
||||||
XenPTRegInfo *reg = cfg_entry->reg;
|
XenPTRegInfo *reg = cfg_entry->reg;
|
||||||
XenPTMSI *msi = s->msi;
|
XenPTMSI *msi = s->msi;
|
||||||
uint16_t writable_mask = 0;
|
uint16_t writable_mask = 0;
|
||||||
uint16_t throughable_mask = 0;
|
uint16_t throughable_mask = get_throughable_mask(s, reg, valid_mask);
|
||||||
uint16_t raw_val;
|
|
||||||
|
|
||||||
/* Currently no support for multi-vector */
|
/* Currently no support for multi-vector */
|
||||||
if (*val & PCI_MSI_FLAGS_QSIZE) {
|
if (*val & PCI_MSI_FLAGS_QSIZE) {
|
||||||
|
@ -1070,12 +1080,10 @@ static int xen_pt_msgctrl_reg_write(XenPCIPassthroughState *s,
|
||||||
msi->flags |= cfg_entry->data & ~PCI_MSI_FLAGS_ENABLE;
|
msi->flags |= cfg_entry->data & ~PCI_MSI_FLAGS_ENABLE;
|
||||||
|
|
||||||
/* create value for writing to I/O device register */
|
/* create value for writing to I/O device register */
|
||||||
raw_val = *val;
|
|
||||||
throughable_mask = ~reg->emu_mask & valid_mask;
|
|
||||||
*val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
|
*val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
|
||||||
|
|
||||||
/* update MSI */
|
/* update MSI */
|
||||||
if (raw_val & PCI_MSI_FLAGS_ENABLE) {
|
if (*val & PCI_MSI_FLAGS_ENABLE) {
|
||||||
/* setup MSI pirq for the first time */
|
/* setup MSI pirq for the first time */
|
||||||
if (!msi->initialized) {
|
if (!msi->initialized) {
|
||||||
/* Init physical one */
|
/* Init physical one */
|
||||||
|
@ -1103,10 +1111,6 @@ static int xen_pt_msgctrl_reg_write(XenPCIPassthroughState *s,
|
||||||
xen_pt_msi_disable(s);
|
xen_pt_msi_disable(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* pass through MSI_ENABLE bit */
|
|
||||||
*val &= ~PCI_MSI_FLAGS_ENABLE;
|
|
||||||
*val |= raw_val & PCI_MSI_FLAGS_ENABLE;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1134,7 +1138,45 @@ static int xen_pt_msgdata_reg_init(XenPCIPassthroughState *s,
|
||||||
uint32_t offset = reg->offset;
|
uint32_t offset = reg->offset;
|
||||||
|
|
||||||
/* check the offset whether matches the type or not */
|
/* check the offset whether matches the type or not */
|
||||||
if (xen_pt_msgdata_check_type(offset, flags)) {
|
if (xen_pt_msi_check_type(offset, flags, DATA)) {
|
||||||
|
*data = reg->init_val;
|
||||||
|
} else {
|
||||||
|
*data = XEN_PT_INVALID_REG;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* this function will be called twice (for 32 bit and 64 bit type) */
|
||||||
|
/* initialize Mask register */
|
||||||
|
static int xen_pt_mask_reg_init(XenPCIPassthroughState *s,
|
||||||
|
XenPTRegInfo *reg, uint32_t real_offset,
|
||||||
|
uint32_t *data)
|
||||||
|
{
|
||||||
|
uint32_t flags = s->msi->flags;
|
||||||
|
|
||||||
|
/* check the offset whether matches the type or not */
|
||||||
|
if (!(flags & PCI_MSI_FLAGS_MASKBIT)) {
|
||||||
|
*data = XEN_PT_INVALID_REG;
|
||||||
|
} else if (xen_pt_msi_check_type(reg->offset, flags, MASK)) {
|
||||||
|
*data = reg->init_val;
|
||||||
|
} else {
|
||||||
|
*data = XEN_PT_INVALID_REG;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* this function will be called twice (for 32 bit and 64 bit type) */
|
||||||
|
/* initialize Pending register */
|
||||||
|
static int xen_pt_pending_reg_init(XenPCIPassthroughState *s,
|
||||||
|
XenPTRegInfo *reg, uint32_t real_offset,
|
||||||
|
uint32_t *data)
|
||||||
|
{
|
||||||
|
uint32_t flags = s->msi->flags;
|
||||||
|
|
||||||
|
/* check the offset whether matches the type or not */
|
||||||
|
if (!(flags & PCI_MSI_FLAGS_MASKBIT)) {
|
||||||
|
*data = XEN_PT_INVALID_REG;
|
||||||
|
} else if (xen_pt_msi_check_type(reg->offset, flags, PENDING)) {
|
||||||
*data = reg->init_val;
|
*data = reg->init_val;
|
||||||
} else {
|
} else {
|
||||||
*data = XEN_PT_INVALID_REG;
|
*data = XEN_PT_INVALID_REG;
|
||||||
|
@ -1149,7 +1191,6 @@ static int xen_pt_msgaddr32_reg_write(XenPCIPassthroughState *s,
|
||||||
{
|
{
|
||||||
XenPTRegInfo *reg = cfg_entry->reg;
|
XenPTRegInfo *reg = cfg_entry->reg;
|
||||||
uint32_t writable_mask = 0;
|
uint32_t writable_mask = 0;
|
||||||
uint32_t throughable_mask = 0;
|
|
||||||
uint32_t old_addr = cfg_entry->data;
|
uint32_t old_addr = cfg_entry->data;
|
||||||
|
|
||||||
/* modify emulate register */
|
/* modify emulate register */
|
||||||
|
@ -1158,8 +1199,7 @@ static int xen_pt_msgaddr32_reg_write(XenPCIPassthroughState *s,
|
||||||
s->msi->addr_lo = cfg_entry->data;
|
s->msi->addr_lo = cfg_entry->data;
|
||||||
|
|
||||||
/* create value for writing to I/O device register */
|
/* create value for writing to I/O device register */
|
||||||
throughable_mask = ~reg->emu_mask & valid_mask;
|
*val = XEN_PT_MERGE_VALUE(*val, dev_value, 0);
|
||||||
*val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
|
|
||||||
|
|
||||||
/* update MSI */
|
/* update MSI */
|
||||||
if (cfg_entry->data != old_addr) {
|
if (cfg_entry->data != old_addr) {
|
||||||
|
@ -1177,7 +1217,6 @@ static int xen_pt_msgaddr64_reg_write(XenPCIPassthroughState *s,
|
||||||
{
|
{
|
||||||
XenPTRegInfo *reg = cfg_entry->reg;
|
XenPTRegInfo *reg = cfg_entry->reg;
|
||||||
uint32_t writable_mask = 0;
|
uint32_t writable_mask = 0;
|
||||||
uint32_t throughable_mask = 0;
|
|
||||||
uint32_t old_addr = cfg_entry->data;
|
uint32_t old_addr = cfg_entry->data;
|
||||||
|
|
||||||
/* check whether the type is 64 bit or not */
|
/* check whether the type is 64 bit or not */
|
||||||
|
@ -1194,8 +1233,7 @@ static int xen_pt_msgaddr64_reg_write(XenPCIPassthroughState *s,
|
||||||
s->msi->addr_hi = cfg_entry->data;
|
s->msi->addr_hi = cfg_entry->data;
|
||||||
|
|
||||||
/* create value for writing to I/O device register */
|
/* create value for writing to I/O device register */
|
||||||
throughable_mask = ~reg->emu_mask & valid_mask;
|
*val = XEN_PT_MERGE_VALUE(*val, dev_value, 0);
|
||||||
*val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
|
|
||||||
|
|
||||||
/* update MSI */
|
/* update MSI */
|
||||||
if (cfg_entry->data != old_addr) {
|
if (cfg_entry->data != old_addr) {
|
||||||
|
@ -1217,12 +1255,11 @@ static int xen_pt_msgdata_reg_write(XenPCIPassthroughState *s,
|
||||||
XenPTRegInfo *reg = cfg_entry->reg;
|
XenPTRegInfo *reg = cfg_entry->reg;
|
||||||
XenPTMSI *msi = s->msi;
|
XenPTMSI *msi = s->msi;
|
||||||
uint16_t writable_mask = 0;
|
uint16_t writable_mask = 0;
|
||||||
uint16_t throughable_mask = 0;
|
|
||||||
uint16_t old_data = cfg_entry->data;
|
uint16_t old_data = cfg_entry->data;
|
||||||
uint32_t offset = reg->offset;
|
uint32_t offset = reg->offset;
|
||||||
|
|
||||||
/* check the offset whether matches the type or not */
|
/* check the offset whether matches the type or not */
|
||||||
if (!xen_pt_msgdata_check_type(offset, msi->flags)) {
|
if (!xen_pt_msi_check_type(offset, msi->flags, DATA)) {
|
||||||
/* exit I/O emulator */
|
/* exit I/O emulator */
|
||||||
XEN_PT_ERR(&s->dev, "the offset does not match the 32/64 bit type!\n");
|
XEN_PT_ERR(&s->dev, "the offset does not match the 32/64 bit type!\n");
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -1235,8 +1272,7 @@ static int xen_pt_msgdata_reg_write(XenPCIPassthroughState *s,
|
||||||
msi->data = cfg_entry->data;
|
msi->data = cfg_entry->data;
|
||||||
|
|
||||||
/* create value for writing to I/O device register */
|
/* create value for writing to I/O device register */
|
||||||
throughable_mask = ~reg->emu_mask & valid_mask;
|
*val = XEN_PT_MERGE_VALUE(*val, dev_value, 0);
|
||||||
*val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
|
|
||||||
|
|
||||||
/* update MSI */
|
/* update MSI */
|
||||||
if (cfg_entry->data != old_data) {
|
if (cfg_entry->data != old_data) {
|
||||||
|
@ -1266,8 +1302,9 @@ static XenPTRegInfo xen_pt_emu_reg_msi[] = {
|
||||||
.offset = PCI_MSI_FLAGS,
|
.offset = PCI_MSI_FLAGS,
|
||||||
.size = 2,
|
.size = 2,
|
||||||
.init_val = 0x0000,
|
.init_val = 0x0000,
|
||||||
.ro_mask = 0xFF8E,
|
.res_mask = 0xFE00,
|
||||||
.emu_mask = 0x007F,
|
.ro_mask = 0x018E,
|
||||||
|
.emu_mask = 0x017E,
|
||||||
.init = xen_pt_msgctrl_reg_init,
|
.init = xen_pt_msgctrl_reg_init,
|
||||||
.u.w.read = xen_pt_word_reg_read,
|
.u.w.read = xen_pt_word_reg_read,
|
||||||
.u.w.write = xen_pt_msgctrl_reg_write,
|
.u.w.write = xen_pt_msgctrl_reg_write,
|
||||||
|
@ -1279,7 +1316,6 @@ static XenPTRegInfo xen_pt_emu_reg_msi[] = {
|
||||||
.init_val = 0x00000000,
|
.init_val = 0x00000000,
|
||||||
.ro_mask = 0x00000003,
|
.ro_mask = 0x00000003,
|
||||||
.emu_mask = 0xFFFFFFFF,
|
.emu_mask = 0xFFFFFFFF,
|
||||||
.no_wb = 1,
|
|
||||||
.init = xen_pt_common_reg_init,
|
.init = xen_pt_common_reg_init,
|
||||||
.u.dw.read = xen_pt_long_reg_read,
|
.u.dw.read = xen_pt_long_reg_read,
|
||||||
.u.dw.write = xen_pt_msgaddr32_reg_write,
|
.u.dw.write = xen_pt_msgaddr32_reg_write,
|
||||||
|
@ -1291,7 +1327,6 @@ static XenPTRegInfo xen_pt_emu_reg_msi[] = {
|
||||||
.init_val = 0x00000000,
|
.init_val = 0x00000000,
|
||||||
.ro_mask = 0x00000000,
|
.ro_mask = 0x00000000,
|
||||||
.emu_mask = 0xFFFFFFFF,
|
.emu_mask = 0xFFFFFFFF,
|
||||||
.no_wb = 1,
|
|
||||||
.init = xen_pt_msgaddr64_reg_init,
|
.init = xen_pt_msgaddr64_reg_init,
|
||||||
.u.dw.read = xen_pt_long_reg_read,
|
.u.dw.read = xen_pt_long_reg_read,
|
||||||
.u.dw.write = xen_pt_msgaddr64_reg_write,
|
.u.dw.write = xen_pt_msgaddr64_reg_write,
|
||||||
|
@ -1303,7 +1338,6 @@ static XenPTRegInfo xen_pt_emu_reg_msi[] = {
|
||||||
.init_val = 0x0000,
|
.init_val = 0x0000,
|
||||||
.ro_mask = 0x0000,
|
.ro_mask = 0x0000,
|
||||||
.emu_mask = 0xFFFF,
|
.emu_mask = 0xFFFF,
|
||||||
.no_wb = 1,
|
|
||||||
.init = xen_pt_msgdata_reg_init,
|
.init = xen_pt_msgdata_reg_init,
|
||||||
.u.w.read = xen_pt_word_reg_read,
|
.u.w.read = xen_pt_word_reg_read,
|
||||||
.u.w.write = xen_pt_msgdata_reg_write,
|
.u.w.write = xen_pt_msgdata_reg_write,
|
||||||
|
@ -1315,11 +1349,54 @@ static XenPTRegInfo xen_pt_emu_reg_msi[] = {
|
||||||
.init_val = 0x0000,
|
.init_val = 0x0000,
|
||||||
.ro_mask = 0x0000,
|
.ro_mask = 0x0000,
|
||||||
.emu_mask = 0xFFFF,
|
.emu_mask = 0xFFFF,
|
||||||
.no_wb = 1,
|
|
||||||
.init = xen_pt_msgdata_reg_init,
|
.init = xen_pt_msgdata_reg_init,
|
||||||
.u.w.read = xen_pt_word_reg_read,
|
.u.w.read = xen_pt_word_reg_read,
|
||||||
.u.w.write = xen_pt_msgdata_reg_write,
|
.u.w.write = xen_pt_msgdata_reg_write,
|
||||||
},
|
},
|
||||||
|
/* Mask reg (if PCI_MSI_FLAGS_MASKBIT set, for 32-bit devices) */
|
||||||
|
{
|
||||||
|
.offset = PCI_MSI_MASK_32,
|
||||||
|
.size = 4,
|
||||||
|
.init_val = 0x00000000,
|
||||||
|
.ro_mask = 0xFFFFFFFF,
|
||||||
|
.emu_mask = 0xFFFFFFFF,
|
||||||
|
.init = xen_pt_mask_reg_init,
|
||||||
|
.u.dw.read = xen_pt_long_reg_read,
|
||||||
|
.u.dw.write = xen_pt_long_reg_write,
|
||||||
|
},
|
||||||
|
/* Mask reg (if PCI_MSI_FLAGS_MASKBIT set, for 64-bit devices) */
|
||||||
|
{
|
||||||
|
.offset = PCI_MSI_MASK_64,
|
||||||
|
.size = 4,
|
||||||
|
.init_val = 0x00000000,
|
||||||
|
.ro_mask = 0xFFFFFFFF,
|
||||||
|
.emu_mask = 0xFFFFFFFF,
|
||||||
|
.init = xen_pt_mask_reg_init,
|
||||||
|
.u.dw.read = xen_pt_long_reg_read,
|
||||||
|
.u.dw.write = xen_pt_long_reg_write,
|
||||||
|
},
|
||||||
|
/* Pending reg (if PCI_MSI_FLAGS_MASKBIT set, for 32-bit devices) */
|
||||||
|
{
|
||||||
|
.offset = PCI_MSI_MASK_32 + 4,
|
||||||
|
.size = 4,
|
||||||
|
.init_val = 0x00000000,
|
||||||
|
.ro_mask = 0xFFFFFFFF,
|
||||||
|
.emu_mask = 0x00000000,
|
||||||
|
.init = xen_pt_pending_reg_init,
|
||||||
|
.u.dw.read = xen_pt_long_reg_read,
|
||||||
|
.u.dw.write = xen_pt_long_reg_write,
|
||||||
|
},
|
||||||
|
/* Pending reg (if PCI_MSI_FLAGS_MASKBIT set, for 64-bit devices) */
|
||||||
|
{
|
||||||
|
.offset = PCI_MSI_MASK_64 + 4,
|
||||||
|
.size = 4,
|
||||||
|
.init_val = 0x00000000,
|
||||||
|
.ro_mask = 0xFFFFFFFF,
|
||||||
|
.emu_mask = 0x00000000,
|
||||||
|
.init = xen_pt_pending_reg_init,
|
||||||
|
.u.dw.read = xen_pt_long_reg_read,
|
||||||
|
.u.dw.write = xen_pt_long_reg_write,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.size = 0,
|
.size = 0,
|
||||||
},
|
},
|
||||||
|
@ -1358,7 +1435,7 @@ static int xen_pt_msixctrl_reg_write(XenPCIPassthroughState *s,
|
||||||
{
|
{
|
||||||
XenPTRegInfo *reg = cfg_entry->reg;
|
XenPTRegInfo *reg = cfg_entry->reg;
|
||||||
uint16_t writable_mask = 0;
|
uint16_t writable_mask = 0;
|
||||||
uint16_t throughable_mask = 0;
|
uint16_t throughable_mask = get_throughable_mask(s, reg, valid_mask);
|
||||||
int debug_msix_enabled_old;
|
int debug_msix_enabled_old;
|
||||||
|
|
||||||
/* modify emulate register */
|
/* modify emulate register */
|
||||||
|
@ -1366,7 +1443,6 @@ static int xen_pt_msixctrl_reg_write(XenPCIPassthroughState *s,
|
||||||
cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask);
|
cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask);
|
||||||
|
|
||||||
/* create value for writing to I/O device register */
|
/* create value for writing to I/O device register */
|
||||||
throughable_mask = ~reg->emu_mask & valid_mask;
|
|
||||||
*val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
|
*val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
|
||||||
|
|
||||||
/* update MSI-X */
|
/* update MSI-X */
|
||||||
|
@ -1405,7 +1481,8 @@ static XenPTRegInfo xen_pt_emu_reg_msix[] = {
|
||||||
.offset = PCI_MSI_FLAGS,
|
.offset = PCI_MSI_FLAGS,
|
||||||
.size = 2,
|
.size = 2,
|
||||||
.init_val = 0x0000,
|
.init_val = 0x0000,
|
||||||
.ro_mask = 0x3FFF,
|
.res_mask = 0x3800,
|
||||||
|
.ro_mask = 0x07FF,
|
||||||
.emu_mask = 0x0000,
|
.emu_mask = 0x0000,
|
||||||
.init = xen_pt_msixctrl_reg_init,
|
.init = xen_pt_msixctrl_reg_init,
|
||||||
.u.w.read = xen_pt_word_reg_read,
|
.u.w.read = xen_pt_word_reg_read,
|
||||||
|
|
|
@ -434,11 +434,10 @@ static void pci_msix_write(void *opaque, hwaddr addr,
|
||||||
XenPCIPassthroughState *s = opaque;
|
XenPCIPassthroughState *s = opaque;
|
||||||
XenPTMSIX *msix = s->msix;
|
XenPTMSIX *msix = s->msix;
|
||||||
XenPTMSIXEntry *entry;
|
XenPTMSIXEntry *entry;
|
||||||
int entry_nr, offset;
|
unsigned int entry_nr, offset;
|
||||||
|
|
||||||
entry_nr = addr / PCI_MSIX_ENTRY_SIZE;
|
entry_nr = addr / PCI_MSIX_ENTRY_SIZE;
|
||||||
if (entry_nr < 0 || entry_nr >= msix->total_entries) {
|
if (entry_nr >= msix->total_entries) {
|
||||||
XEN_PT_ERR(&s->dev, "asked MSI-X entry '%i' invalid!\n", entry_nr);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
entry = &msix->msix_entry[entry_nr];
|
entry = &msix->msix_entry[entry_nr];
|
||||||
|
@ -460,8 +459,11 @@ static void pci_msix_write(void *opaque, hwaddr addr,
|
||||||
+ PCI_MSIX_ENTRY_VECTOR_CTRL;
|
+ PCI_MSIX_ENTRY_VECTOR_CTRL;
|
||||||
|
|
||||||
if (msix->enabled && !(*vec_ctrl & PCI_MSIX_ENTRY_CTRL_MASKBIT)) {
|
if (msix->enabled && !(*vec_ctrl & PCI_MSIX_ENTRY_CTRL_MASKBIT)) {
|
||||||
XEN_PT_ERR(&s->dev, "Can't update msix entry %d since MSI-X is"
|
if (!entry->warned) {
|
||||||
" already enabled.\n", entry_nr);
|
entry->warned = true;
|
||||||
|
XEN_PT_ERR(&s->dev, "Can't update msix entry %d since MSI-X is"
|
||||||
|
" already enabled.\n", entry_nr);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -298,8 +298,10 @@
|
||||||
#define PCI_MSI_ADDRESS_HI 8 /* Upper 32 bits (if PCI_MSI_FLAGS_64BIT set) */
|
#define PCI_MSI_ADDRESS_HI 8 /* Upper 32 bits (if PCI_MSI_FLAGS_64BIT set) */
|
||||||
#define PCI_MSI_DATA_32 8 /* 16 bits of data for 32-bit devices */
|
#define PCI_MSI_DATA_32 8 /* 16 bits of data for 32-bit devices */
|
||||||
#define PCI_MSI_MASK_32 12 /* Mask bits register for 32-bit devices */
|
#define PCI_MSI_MASK_32 12 /* Mask bits register for 32-bit devices */
|
||||||
|
#define PCI_MSI_PENDING_32 16 /* Pending bits register for 32-bit devices */
|
||||||
#define PCI_MSI_DATA_64 12 /* 16 bits of data for 64-bit devices */
|
#define PCI_MSI_DATA_64 12 /* 16 bits of data for 64-bit devices */
|
||||||
#define PCI_MSI_MASK_64 16 /* Mask bits register for 64-bit devices */
|
#define PCI_MSI_MASK_64 16 /* Mask bits register for 64-bit devices */
|
||||||
|
#define PCI_MSI_PENDING_64 20 /* Pending bits register for 32-bit devices */
|
||||||
|
|
||||||
/* MSI-X registers */
|
/* MSI-X registers */
|
||||||
#define PCI_MSIX_FLAGS 2
|
#define PCI_MSIX_FLAGS 2
|
||||||
|
|
Loading…
Reference in New Issue