提交 05bec7eb 编写于 作者: P Peter Maydell

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: NPeter Maydell <peter.maydell@linaro.org>
...@@ -825,6 +825,9 @@ static int blk_init(struct XenDevice *xendev) ...@@ -825,6 +825,9 @@ static int blk_init(struct XenDevice *xendev)
if (!strcmp("aio", blkdev->fileproto)) { if (!strcmp("aio", blkdev->fileproto)) {
blkdev->fileproto = "raw"; blkdev->fileproto = "raw";
} }
if (!strcmp("vhd", blkdev->fileproto)) {
blkdev->fileproto = "vpc";
}
if (blkdev->mode == NULL) { if (blkdev->mode == NULL) {
blkdev->mode = xenstore_read_be_str(&blkdev->xendev, "mode"); blkdev->mode = xenstore_read_be_str(&blkdev->xendev, "mode");
} }
......
...@@ -113,6 +113,8 @@ struct XenPTRegInfo { ...@@ -113,6 +113,8 @@ struct XenPTRegInfo {
uint32_t res_mask; 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 read/write-1-clear field mask (ON:RW1C/RW1CS, OFF:other) */
uint32_t rw1c_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;
xen_pt_conf_reg_init init; xen_pt_conf_reg_init init;
...@@ -187,13 +189,13 @@ typedef struct XenPTMSIXEntry { ...@@ -187,13 +189,13 @@ typedef struct XenPTMSIXEntry {
int pirq; int pirq;
uint64_t addr; uint64_t addr;
uint32_t data; uint32_t data;
uint32_t vector_ctrl; uint32_t latch[4];
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;
bool enabled; bool enabled;
bool maskall;
int total_entries; int total_entries;
int bar_index; int bar_index;
uint64_t table_base; uint64_t table_base;
......
...@@ -179,7 +179,8 @@ static int xen_pt_byte_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry, ...@@ -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); *data = XEN_PT_MERGE_VALUE(*val, *data, writable_mask);
/* create value for writing to I/O device register */ /* 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; return 0;
} }
...@@ -197,7 +198,8 @@ static int xen_pt_word_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry, ...@@ -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); *data = XEN_PT_MERGE_VALUE(*val, *data, writable_mask);
/* create value for writing to I/O device register */ /* 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; return 0;
} }
...@@ -215,7 +217,8 @@ static int xen_pt_long_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry, ...@@ -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); *data = XEN_PT_MERGE_VALUE(*val, *data, writable_mask);
/* create value for writing to I/O device register */ /* 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; return 0;
} }
...@@ -633,6 +636,7 @@ static XenPTRegInfo xen_pt_emu_reg_header0[] = { ...@@ -633,6 +636,7 @@ static XenPTRegInfo xen_pt_emu_reg_header0[] = {
.init_val = 0x0000, .init_val = 0x0000,
.res_mask = 0x0007, .res_mask = 0x0007,
.ro_mask = 0x06F8, .ro_mask = 0x06F8,
.rw1c_mask = 0xF900,
.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,
...@@ -944,6 +948,7 @@ static XenPTRegInfo xen_pt_emu_reg_pcie[] = { ...@@ -944,6 +948,7 @@ static XenPTRegInfo xen_pt_emu_reg_pcie[] = {
.size = 2, .size = 2,
.res_mask = 0xFFC0, .res_mask = 0xFFC0,
.ro_mask = 0x0030, .ro_mask = 0x0030,
.rw1c_mask = 0x000F,
.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,
.u.w.write = xen_pt_word_reg_write, .u.w.write = xen_pt_word_reg_write,
...@@ -964,6 +969,7 @@ static XenPTRegInfo xen_pt_emu_reg_pcie[] = { ...@@ -964,6 +969,7 @@ static XenPTRegInfo xen_pt_emu_reg_pcie[] = {
.offset = PCI_EXP_LNKSTA, .offset = PCI_EXP_LNKSTA,
.size = 2, .size = 2,
.ro_mask = 0x3FFF, .ro_mask = 0x3FFF,
.rw1c_mask = 0xC000,
.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,
.u.w.write = xen_pt_word_reg_write, .u.w.write = xen_pt_word_reg_write,
...@@ -1000,27 +1006,6 @@ static XenPTRegInfo xen_pt_emu_reg_pcie[] = { ...@@ -1000,27 +1006,6 @@ static XenPTRegInfo xen_pt_emu_reg_pcie[] = {
* Power Management Capability * 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 */ /* Power Management Capability reg static information table */
static XenPTRegInfo xen_pt_emu_reg_pm[] = { static XenPTRegInfo xen_pt_emu_reg_pm[] = {
/* Next Pointer reg */ /* Next Pointer reg */
...@@ -1051,11 +1036,12 @@ static XenPTRegInfo xen_pt_emu_reg_pm[] = { ...@@ -1051,11 +1036,12 @@ static XenPTRegInfo xen_pt_emu_reg_pm[] = {
.size = 2, .size = 2,
.init_val = 0x0008, .init_val = 0x0008,
.res_mask = 0x00F0, .res_mask = 0x00F0,
.ro_mask = 0xE10C, .ro_mask = 0x610C,
.rw1c_mask = 0x8000,
.emu_mask = 0x810B, .emu_mask = 0x810B,
.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,
.u.w.write = xen_pt_pmcsr_reg_write, .u.w.write = xen_pt_word_reg_write,
}, },
{ {
.size = 0, .size = 0,
...@@ -1499,6 +1485,8 @@ static int xen_pt_msixctrl_reg_write(XenPCIPassthroughState *s, ...@@ -1499,6 +1485,8 @@ static int xen_pt_msixctrl_reg_write(XenPCIPassthroughState *s,
xen_pt_msix_disable(s); xen_pt_msix_disable(s);
} }
s->msix->maskall = *val & PCI_MSIX_FLAGS_MASKALL;
debug_msix_enabled_old = s->msix->enabled; debug_msix_enabled_old = s->msix->enabled;
s->msix->enabled = !!(*val & PCI_MSIX_FLAGS_ENABLE); s->msix->enabled = !!(*val & PCI_MSIX_FLAGS_ENABLE);
if (s->msix->enabled != debug_msix_enabled_old) { if (s->msix->enabled != debug_msix_enabled_old) {
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#define XEN_PT_GFLAGSSHIFT_DELIV_MODE 12 #define XEN_PT_GFLAGSSHIFT_DELIV_MODE 12
#define XEN_PT_GFLAGSSHIFT_TRG_MODE 15 #define XEN_PT_GFLAGSSHIFT_TRG_MODE 15
#define latch(fld) latch[PCI_MSIX_ENTRY_##fld / sizeof(uint32_t)]
/* /*
* Helpers * Helpers
...@@ -314,7 +315,8 @@ static int msix_set_enable(XenPCIPassthroughState *s, bool enabled) ...@@ -314,7 +315,8 @@ static int msix_set_enable(XenPCIPassthroughState *s, bool enabled)
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; XenPTMSIXEntry *entry = NULL;
int pirq; int pirq;
...@@ -332,6 +334,19 @@ static int xen_pt_msix_update_one(XenPCIPassthroughState *s, int entry_nr) ...@@ -332,6 +334,19 @@ static int xen_pt_msix_update_one(XenPCIPassthroughState *s, int entry_nr)
pirq = entry->pirq; 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, rc = msi_msix_setup(s, entry->addr, entry->data, &pirq, true, entry_nr,
entry->pirq == XEN_PT_UNASSIGNED_PIRQ); entry->pirq == XEN_PT_UNASSIGNED_PIRQ);
if (rc) { if (rc) {
...@@ -357,7 +372,7 @@ int xen_pt_msix_update(XenPCIPassthroughState *s) ...@@ -357,7 +372,7 @@ int xen_pt_msix_update(XenPCIPassthroughState *s)
int i; int i;
for (i = 0; i < msix->total_entries; 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; return 0;
...@@ -406,36 +421,14 @@ int xen_pt_msix_update_remap(XenPCIPassthroughState *s, int bar_index) ...@@ -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) static uint32_t get_entry_value(XenPTMSIXEntry *e, int offset)
{ {
switch (offset) { assert(!(offset % sizeof(*e->latch)));
case PCI_MSIX_ENTRY_LOWER_ADDR: return e->latch[offset / sizeof(*e->latch)];
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;
}
} }
static void set_entry_value(XenPTMSIXEntry *e, int offset, uint32_t val) static void set_entry_value(XenPTMSIXEntry *e, int offset, uint32_t val)
{ {
switch (offset) { assert(!(offset % sizeof(*e->latch)));
case PCI_MSIX_ENTRY_LOWER_ADDR: e->latch[offset / sizeof(*e->latch)] = val;
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;
}
} }
static void pci_msix_write(void *opaque, hwaddr addr, static void pci_msix_write(void *opaque, hwaddr addr,
...@@ -454,39 +447,26 @@ 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; offset = addr % PCI_MSIX_ENTRY_SIZE;
if (offset != PCI_MSIX_ENTRY_VECTOR_CTRL) { if (offset != PCI_MSIX_ENTRY_VECTOR_CTRL) {
const volatile uint32_t *vec_ctrl;
if (get_entry_value(entry, offset) == val if (get_entry_value(entry, offset) == val
&& entry->pirq != XEN_PT_UNASSIGNED_PIRQ) { && entry->pirq != XEN_PT_UNASSIGNED_PIRQ) {
return; 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 * If Xen intercepts the mask bit access, entry->vec_ctrl may not be
* up-to-date. Read from hardware directly. * up-to-date. Read from hardware directly.
*/ */
vec_ctrl = s->msix->phys_iomem_base + entry_nr * PCI_MSIX_ENTRY_SIZE vec_ctrl = s->msix->phys_iomem_base + entry_nr * PCI_MSIX_ENTRY_SIZE
+ PCI_MSIX_ENTRY_VECTOR_CTRL; + PCI_MSIX_ENTRY_VECTOR_CTRL;
xen_pt_msix_update_one(s, entry_nr, *vec_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;
} }
set_entry_value(entry, offset, val); 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, static uint64_t pci_msix_read(void *opaque, hwaddr addr,
...@@ -512,6 +492,12 @@ 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 = { static const MemoryRegionOps pci_msix_ops = {
.read = pci_msix_read, .read = pci_msix_read,
.write = pci_msix_write, .write = pci_msix_write,
...@@ -520,7 +506,13 @@ static const MemoryRegionOps pci_msix_ops = { ...@@ -520,7 +506,13 @@ static const MemoryRegionOps pci_msix_ops = {
.min_access_size = 4, .min_access_size = 4,
.max_access_size = 4, .max_access_size = 4,
.unaligned = false, .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) int xen_pt_msix_init(XenPCIPassthroughState *s, uint32_t base)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册