Xen 2015/12/22

-----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.12 (GNU/Linux)
 
 iQIcBAABAgAGBQJWeXe1AAoJEIlPj0hw4a6QpTUQAPirj6gWanKtVTRGPnOhClMW
 h9inFwkoAxQj5KGYeiI8RYzrWhFKDooOe4T+qIenp6HYMzQdSpM1A/wEeO6UnyVw
 j3hEI6bi+ZNG27yEJV2mygSY4ivNG7gk2dbKRwqaA2pmbrNEtMTdv45MQYrQeqjC
 vd6uy+VoZSuG/spQGhGc5JhoYiFFWHzprueqfHsFO8nM+7htRxBne7zw2iB17o9q
 pptOoETfV6mjbdqxDHKlRnm5DtvXpyszDFtFp3utzjAbsTkrMTxb2iaS+p359fav
 6QweJQgrnDKIR1v3VWhs054OmoY9jcW4Q6lnqu7TJbVuOKnlS9Hoe70A0s+knZsz
 7HDz73GEjB2rgK0KArK7sOS2/M5lQRj1JbtbzLLkWmq9lndRLgRj6+QoZ72gLs2S
 +s5X5c1iXLhZtBmGAz/sH6u5A1Bk7YVGHuEN9evfDsIC/uxVGhNX+exXgy0pADG0
 iT0+BPKGVTKbZmxYiyfhhMsEiTdcQTI9/KYT+sDHy/9PTaqS6D8rFRHnrZi6PWRn
 get5L3ZRQ686KcyEh8pQVYpki+HUWStqVlvufvbPkJ0Wpaj9yi6KdlmQOA3IrWni
 syFd6KJuumtUrX/xISuY+kpG6FlsDHQzh318NEmjU9jFhoKE34JHqtd/C/RMAWKF
 FdbVufoH+Rq/yQy2QNqE
 =FXtN
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/sstabellini/tags/xen-2015-12-22' into staging

Xen 2015/12/22

# gpg: Signature made Tue 22 Dec 2015 16:17:57 GMT using RSA key ID 70E1AE90
# gpg: Good signature from "Stefano Stabellini <stefano.stabellini@eu.citrix.com>"

* remotes/sstabellini/tags/xen-2015-12-22:
  xen_disk: treat "vhd" as "vpc"
  xen/pass-through: correctly deal with RW1C bits
  xen/MSI-X: really enforce alignment
  xen/MSI-X: latch MSI-X table writes

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2015-12-23 12:04:01 +00:00
commit 05bec7eb0e
4 changed files with 60 additions and 75 deletions

View File

@ -825,6 +825,9 @@ static int blk_init(struct XenDevice *xendev)
if (!strcmp("aio", blkdev->fileproto)) {
blkdev->fileproto = "raw";
}
if (!strcmp("vhd", blkdev->fileproto)) {
blkdev->fileproto = "vpc";
}
if (blkdev->mode == NULL) {
blkdev->mode = xenstore_read_be_str(&blkdev->xendev, "mode");
}

View File

@ -113,6 +113,8 @@ struct XenPTRegInfo {
uint32_t res_mask;
/* reg read only field mask (ON:RO/ROS, OFF:other) */
uint32_t ro_mask;
/* reg read/write-1-clear field mask (ON:RW1C/RW1CS, OFF:other) */
uint32_t rw1c_mask;
/* reg emulate field mask (ON:emu, OFF:passthrough) */
uint32_t emu_mask;
xen_pt_conf_reg_init init;
@ -187,13 +189,13 @@ typedef struct XenPTMSIXEntry {
int pirq;
uint64_t addr;
uint32_t data;
uint32_t vector_ctrl;
uint32_t latch[4];
bool updated; /* indicate whether MSI ADDR or DATA is updated */
bool warned; /* avoid issuing (bogus) warning more than once */
} XenPTMSIXEntry;
typedef struct XenPTMSIX {
uint32_t ctrl_offset;
bool enabled;
bool maskall;
int total_entries;
int bar_index;
uint64_t table_base;

View File

@ -179,7 +179,8 @@ static int xen_pt_byte_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
*data = XEN_PT_MERGE_VALUE(*val, *data, writable_mask);
/* create value for writing to I/O device register */
*val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
*val = XEN_PT_MERGE_VALUE(*val, dev_value & ~reg->rw1c_mask,
throughable_mask);
return 0;
}
@ -197,7 +198,8 @@ static int xen_pt_word_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
*data = XEN_PT_MERGE_VALUE(*val, *data, writable_mask);
/* create value for writing to I/O device register */
*val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
*val = XEN_PT_MERGE_VALUE(*val, dev_value & ~reg->rw1c_mask,
throughable_mask);
return 0;
}
@ -215,7 +217,8 @@ static int xen_pt_long_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
*data = XEN_PT_MERGE_VALUE(*val, *data, writable_mask);
/* create value for writing to I/O device register */
*val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
*val = XEN_PT_MERGE_VALUE(*val, dev_value & ~reg->rw1c_mask,
throughable_mask);
return 0;
}
@ -633,6 +636,7 @@ static XenPTRegInfo xen_pt_emu_reg_header0[] = {
.init_val = 0x0000,
.res_mask = 0x0007,
.ro_mask = 0x06F8,
.rw1c_mask = 0xF900,
.emu_mask = 0x0010,
.init = xen_pt_status_reg_init,
.u.w.read = xen_pt_word_reg_read,
@ -944,6 +948,7 @@ static XenPTRegInfo xen_pt_emu_reg_pcie[] = {
.size = 2,
.res_mask = 0xFFC0,
.ro_mask = 0x0030,
.rw1c_mask = 0x000F,
.init = xen_pt_common_reg_init,
.u.w.read = xen_pt_word_reg_read,
.u.w.write = xen_pt_word_reg_write,
@ -964,6 +969,7 @@ static XenPTRegInfo xen_pt_emu_reg_pcie[] = {
.offset = PCI_EXP_LNKSTA,
.size = 2,
.ro_mask = 0x3FFF,
.rw1c_mask = 0xC000,
.init = xen_pt_common_reg_init,
.u.w.read = xen_pt_word_reg_read,
.u.w.write = xen_pt_word_reg_write,
@ -1000,27 +1006,6 @@ static XenPTRegInfo xen_pt_emu_reg_pcie[] = {
* Power Management Capability
*/
/* write Power Management Control/Status register */
static int xen_pt_pmcsr_reg_write(XenPCIPassthroughState *s,
XenPTReg *cfg_entry, uint16_t *val,
uint16_t dev_value, uint16_t valid_mask)
{
XenPTRegInfo *reg = cfg_entry->reg;
uint16_t writable_mask = 0;
uint16_t throughable_mask = get_throughable_mask(s, reg, valid_mask);
uint16_t *data = cfg_entry->ptr.half_word;
/* modify emulate register */
writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
*data = XEN_PT_MERGE_VALUE(*val, *data, writable_mask);
/* create value for writing to I/O device register */
*val = XEN_PT_MERGE_VALUE(*val, dev_value & ~PCI_PM_CTRL_PME_STATUS,
throughable_mask);
return 0;
}
/* Power Management Capability reg static information table */
static XenPTRegInfo xen_pt_emu_reg_pm[] = {
/* Next Pointer reg */
@ -1051,11 +1036,12 @@ static XenPTRegInfo xen_pt_emu_reg_pm[] = {
.size = 2,
.init_val = 0x0008,
.res_mask = 0x00F0,
.ro_mask = 0xE10C,
.ro_mask = 0x610C,
.rw1c_mask = 0x8000,
.emu_mask = 0x810B,
.init = xen_pt_common_reg_init,
.u.w.read = xen_pt_word_reg_read,
.u.w.write = xen_pt_pmcsr_reg_write,
.u.w.write = xen_pt_word_reg_write,
},
{
.size = 0,
@ -1499,6 +1485,8 @@ static int xen_pt_msixctrl_reg_write(XenPCIPassthroughState *s,
xen_pt_msix_disable(s);
}
s->msix->maskall = *val & PCI_MSIX_FLAGS_MASKALL;
debug_msix_enabled_old = s->msix->enabled;
s->msix->enabled = !!(*val & PCI_MSIX_FLAGS_ENABLE);
if (s->msix->enabled != debug_msix_enabled_old) {

View File

@ -25,6 +25,7 @@
#define XEN_PT_GFLAGSSHIFT_DELIV_MODE 12
#define XEN_PT_GFLAGSSHIFT_TRG_MODE 15
#define latch(fld) latch[PCI_MSIX_ENTRY_##fld / sizeof(uint32_t)]
/*
* Helpers
@ -314,7 +315,8 @@ static int msix_set_enable(XenPCIPassthroughState *s, bool enabled)
enabled);
}
static int xen_pt_msix_update_one(XenPCIPassthroughState *s, int entry_nr)
static int xen_pt_msix_update_one(XenPCIPassthroughState *s, int entry_nr,
uint32_t vec_ctrl)
{
XenPTMSIXEntry *entry = NULL;
int pirq;
@ -332,6 +334,19 @@ static int xen_pt_msix_update_one(XenPCIPassthroughState *s, int entry_nr)
pirq = entry->pirq;
/*
* Update the entry addr and data to the latest values only when the
* entry is masked or they are all masked, as required by the spec.
* Addr and data changes while the MSI-X entry is unmasked get deferred
* until the next masked -> unmasked transition.
*/
if (pirq == XEN_PT_UNASSIGNED_PIRQ || s->msix->maskall ||
(vec_ctrl & PCI_MSIX_ENTRY_CTRL_MASKBIT)) {
entry->addr = entry->latch(LOWER_ADDR) |
((uint64_t)entry->latch(UPPER_ADDR) << 32);
entry->data = entry->latch(DATA);
}
rc = msi_msix_setup(s, entry->addr, entry->data, &pirq, true, entry_nr,
entry->pirq == XEN_PT_UNASSIGNED_PIRQ);
if (rc) {
@ -357,7 +372,7 @@ int xen_pt_msix_update(XenPCIPassthroughState *s)
int i;
for (i = 0; i < msix->total_entries; i++) {
xen_pt_msix_update_one(s, i);
xen_pt_msix_update_one(s, i, msix->msix_entry[i].latch(VECTOR_CTRL));
}
return 0;
@ -406,36 +421,14 @@ int xen_pt_msix_update_remap(XenPCIPassthroughState *s, int bar_index)
static uint32_t get_entry_value(XenPTMSIXEntry *e, int offset)
{
switch (offset) {
case PCI_MSIX_ENTRY_LOWER_ADDR:
return e->addr & UINT32_MAX;
case PCI_MSIX_ENTRY_UPPER_ADDR:
return e->addr >> 32;
case PCI_MSIX_ENTRY_DATA:
return e->data;
case PCI_MSIX_ENTRY_VECTOR_CTRL:
return e->vector_ctrl;
default:
return 0;
}
assert(!(offset % sizeof(*e->latch)));
return e->latch[offset / sizeof(*e->latch)];
}
static void set_entry_value(XenPTMSIXEntry *e, int offset, uint32_t val)
{
switch (offset) {
case PCI_MSIX_ENTRY_LOWER_ADDR:
e->addr = (e->addr & ((uint64_t)UINT32_MAX << 32)) | val;
break;
case PCI_MSIX_ENTRY_UPPER_ADDR:
e->addr = (uint64_t)val << 32 | (e->addr & UINT32_MAX);
break;
case PCI_MSIX_ENTRY_DATA:
e->data = val;
break;
case PCI_MSIX_ENTRY_VECTOR_CTRL:
e->vector_ctrl = val;
break;
}
assert(!(offset % sizeof(*e->latch)));
e->latch[offset / sizeof(*e->latch)] = val;
}
static void pci_msix_write(void *opaque, hwaddr addr,
@ -454,39 +447,26 @@ static void pci_msix_write(void *opaque, hwaddr addr,
offset = addr % PCI_MSIX_ENTRY_SIZE;
if (offset != PCI_MSIX_ENTRY_VECTOR_CTRL) {
const volatile uint32_t *vec_ctrl;
if (get_entry_value(entry, offset) == val
&& entry->pirq != XEN_PT_UNASSIGNED_PIRQ) {
return;
}
entry->updated = true;
} else if (msix->enabled && entry->updated &&
!(val & PCI_MSIX_ENTRY_CTRL_MASKBIT)) {
const volatile uint32_t *vec_ctrl;
/*
* If Xen intercepts the mask bit access, entry->vec_ctrl may not be
* up-to-date. Read from hardware directly.
*/
vec_ctrl = s->msix->phys_iomem_base + entry_nr * PCI_MSIX_ENTRY_SIZE
+ PCI_MSIX_ENTRY_VECTOR_CTRL;
if (msix->enabled && !(*vec_ctrl & PCI_MSIX_ENTRY_CTRL_MASKBIT)) {
if (!entry->warned) {
entry->warned = true;
XEN_PT_ERR(&s->dev, "Can't update msix entry %d since MSI-X is"
" already enabled.\n", entry_nr);
}
return;
}
entry->updated = true;
xen_pt_msix_update_one(s, entry_nr, *vec_ctrl);
}
set_entry_value(entry, offset, val);
if (offset == PCI_MSIX_ENTRY_VECTOR_CTRL) {
if (msix->enabled && !(val & PCI_MSIX_ENTRY_CTRL_MASKBIT)) {
xen_pt_msix_update_one(s, entry_nr);
}
}
}
static uint64_t pci_msix_read(void *opaque, hwaddr addr,
@ -512,6 +492,12 @@ static uint64_t pci_msix_read(void *opaque, hwaddr addr,
}
}
static bool pci_msix_accepts(void *opaque, hwaddr addr,
unsigned size, bool is_write)
{
return !(addr & (size - 1));
}
static const MemoryRegionOps pci_msix_ops = {
.read = pci_msix_read,
.write = pci_msix_write,
@ -520,7 +506,13 @@ static const MemoryRegionOps pci_msix_ops = {
.min_access_size = 4,
.max_access_size = 4,
.unaligned = false,
.accepts = pci_msix_accepts
},
.impl = {
.min_access_size = 4,
.max_access_size = 4,
.unaligned = false
}
};
int xen_pt_msix_init(XenPCIPassthroughState *s, uint32_t base)