Yuji Shimada
2009-Mar-13 04:57 UTC
[Xen-devel] [PATCH] ioemu: Fix MSI/MSI-X capability structure virtualization code
This patch fixes MSI/MSI-X capability structure virtualization code. Currently, xen does not support multiple message (multiple vector). So multiple message capable field should be emulated and fixed to 0 (single vector). With the patch, my FC-HBA works when I assign it to guest domain where windows 2008 runs. In addition to this, initial values of emulated registers should be the same with initial values defined in PCI spec. If initial values are not defined, they should be 0. The emulated field mask and read-only field mask are also fixed. Thanks, -- Yuji Shimada Signed-off-by: Yuji Shimada <shimada-yxb@necst.nec.co.jp> diff --git a/hw/pass-through.c b/hw/pass-through.c index 308bcc3..487b08d 100644 --- a/hw/pass-through.c +++ b/hw/pass-through.c @@ -73,8 +73,6 @@ static uint32_t pt_linkctrl2_reg_init(struct pt_dev *ptdev, struct pt_reg_info_tbl *reg, uint32_t real_offset); static uint32_t pt_msgctrl_reg_init(struct pt_dev *ptdev, struct pt_reg_info_tbl *reg, uint32_t real_offset); -static uint32_t pt_msgaddr32_reg_init(struct pt_dev *ptdev, - struct pt_reg_info_tbl *reg, uint32_t real_offset); static uint32_t pt_msgaddr64_reg_init(struct pt_dev *ptdev, struct pt_reg_info_tbl *reg, uint32_t real_offset); static uint32_t pt_msgdata_reg_init(struct pt_dev *ptdev, @@ -552,8 +550,8 @@ static struct pt_reg_info_tbl pt_emu_reg_msi_tbl[] = { .offset = PCI_MSI_FLAGS, // 2 .size = 2, .init_val = 0x0000, - .ro_mask = 0x018E, - .emu_mask = 0xFFFF, + .ro_mask = 0xFF8E, + .emu_mask = 0x007F, .init = pt_msgctrl_reg_init, .u.w.read = pt_word_reg_read, .u.w.write = pt_msgctrl_reg_write, @@ -564,9 +562,9 @@ static struct pt_reg_info_tbl pt_emu_reg_msi_tbl[] = { .offset = PCI_MSI_ADDRESS_LO, // 4 .size = 4, .init_val = 0x00000000, - .ro_mask = 0x00000FF0, /* bit 4~11 is reserved for MSI in x86 */ + .ro_mask = 0x00000003, .emu_mask = 0xFFFFFFFF, - .init = pt_msgaddr32_reg_init, + .init = pt_common_reg_init, .u.dw.read = pt_long_reg_read, .u.dw.write = pt_msgaddr32_reg_write, .u.dw.restore = NULL, @@ -588,7 +586,7 @@ static struct pt_reg_info_tbl pt_emu_reg_msi_tbl[] = { .offset = PCI_MSI_DATA_32, // 8 .size = 2, .init_val = 0x0000, - .ro_mask = 0x3800, + .ro_mask = 0x0000, .emu_mask = 0xFFFF, .init = pt_msgdata_reg_init, .u.w.read = pt_word_reg_read, @@ -600,7 +598,7 @@ static struct pt_reg_info_tbl pt_emu_reg_msi_tbl[] = { .offset = PCI_MSI_DATA_64, // 12 .size = 2, .init_val = 0x0000, - .ro_mask = 0x3800, + .ro_mask = 0x0000, .emu_mask = 0xFFFF, .init = pt_msgdata_reg_init, .u.w.read = pt_word_reg_read, @@ -2456,7 +2454,7 @@ static uint32_t pt_msgctrl_reg_init(struct pt_dev *ptdev, uint32_t reg_field = 0; /* use I/O device register''s value as initial value */ - reg_field |= *((uint16_t*)(d->config + real_offset)); + reg_field = *((uint16_t*)(d->config + real_offset)); if (reg_field & PCI_MSI_FLAGS_ENABLE) { @@ -2466,40 +2464,18 @@ static uint32_t pt_msgctrl_reg_init(struct pt_dev *ptdev, ptdev->msi->flags |= (reg_field | MSI_FLAG_UNINIT); ptdev->msi->ctrl_offset = real_offset; - /* All register is 0 after reset, except first 4 byte */ - reg_field &= reg->ro_mask; - - return reg_field; -} - -/* initialize Message Address register */ -static uint32_t pt_msgaddr32_reg_init(struct pt_dev *ptdev, - struct pt_reg_info_tbl *reg, uint32_t real_offset) -{ - PCIDevice *d = (struct PCIDevice *)ptdev; - uint32_t reg_field = 0; - - /* use I/O device register''s value as initial value */ - reg_field |= *((uint32_t*)(d->config + real_offset)); - - return reg_field; + return reg->init_val; } /* initialize Message Upper Address register */ static uint32_t pt_msgaddr64_reg_init(struct pt_dev *ptdev, struct pt_reg_info_tbl *reg, uint32_t real_offset) { - PCIDevice *d = (struct PCIDevice *)ptdev; - uint32_t reg_field = 0; - /* no need to initialize in case of 32 bit type */ if (!(ptdev->msi->flags & PCI_MSI_FLAGS_64BIT)) return PT_INVALID_REG; - /* use I/O device register''s value as initial value */ - reg_field |= *((uint32_t*)(d->config + real_offset)); - - return reg_field; + return reg->init_val; } /* this function will be called twice (for 32 bit and 64 bit type) */ @@ -2507,14 +2483,13 @@ static uint32_t pt_msgaddr64_reg_init(struct pt_dev *ptdev, static uint32_t pt_msgdata_reg_init(struct pt_dev *ptdev, struct pt_reg_info_tbl *reg, uint32_t real_offset) { - PCIDevice *d = (struct PCIDevice *)ptdev; uint32_t flags = ptdev->msi->flags; uint32_t offset = reg->offset; /* check the offset whether matches the type or not */ if (((offset == PCI_MSI_DATA_64) && (flags & PCI_MSI_FLAGS_64BIT)) || ((offset == PCI_MSI_DATA_32) && !(flags & PCI_MSI_FLAGS_64BIT))) - return *((uint16_t*)(d->config + real_offset)); + return reg->init_val; else return PT_INVALID_REG; } @@ -2528,18 +2503,17 @@ static uint32_t pt_msixctrl_reg_init(struct pt_dev *ptdev, uint16_t reg_field = 0; /* use I/O device register''s value as initial value */ - reg_field |= *((uint16_t*)(d->config + real_offset)); + reg_field = *((uint16_t*)(d->config + real_offset)); if (reg_field & PCI_MSIX_ENABLE) { PT_LOG("MSIX enabled already, disable first\n"); pci_write_word(pdev, real_offset, reg_field & ~PCI_MSIX_ENABLE); - reg_field &= ~(PCI_MSIX_ENABLE | PCI_MSIX_MASK); } ptdev->msix->ctrl_offset = real_offset; - return reg_field; + return reg->init_val; } /* get register group size */ _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Yuji Shimada
2009-Mar-24 06:43 UTC
Re: [Xen-devel] [PATCH] ioemu: Fix MSI/MSI-X capability structure virtualization code
Could you consider applying the following patches? They fix the bugs of PCI pass-through. [PATCH] ioemu: Fix MSI/MSI-X capability structure virtualization code [PATCH] ioemu: fix pt_chk_bar_overlap [PATCH] ioemu: unmap INTx interrupt on hot-remove Thanks, -- Yuji Shimada On Fri, 13 Mar 2009 13:57:58 +0900 Yuji Shimada <shimada-yxb@necst.nec.co.jp> wrote:> This patch fixes MSI/MSI-X capability structure virtualization code. > > Currently, xen does not support multiple message (multiple vector). > So multiple message capable field should be emulated and fixed to 0 > (single vector). > > With the patch, my FC-HBA works when I assign it to guest domain where > windows 2008 runs. > > > In addition to this, initial values of emulated registers should be > the same with initial values defined in PCI spec. If initial values > are not defined, they should be 0. The emulated field mask and > read-only field mask are also fixed. > > Thanks, > -- > Yuji Shimada > > > Signed-off-by: Yuji Shimada <shimada-yxb@necst.nec.co.jp> > > diff --git a/hw/pass-through.c b/hw/pass-through.c > index 308bcc3..487b08d 100644 > --- a/hw/pass-through.c > +++ b/hw/pass-through.c > @@ -73,8 +73,6 @@ static uint32_t pt_linkctrl2_reg_init(struct pt_dev *ptdev, > struct pt_reg_info_tbl *reg, uint32_t real_offset); > static uint32_t pt_msgctrl_reg_init(struct pt_dev *ptdev, > struct pt_reg_info_tbl *reg, uint32_t real_offset); > -static uint32_t pt_msgaddr32_reg_init(struct pt_dev *ptdev, > - struct pt_reg_info_tbl *reg, uint32_t real_offset); > static uint32_t pt_msgaddr64_reg_init(struct pt_dev *ptdev, > struct pt_reg_info_tbl *reg, uint32_t real_offset); > static uint32_t pt_msgdata_reg_init(struct pt_dev *ptdev, > @@ -552,8 +550,8 @@ static struct pt_reg_info_tbl pt_emu_reg_msi_tbl[] = { > .offset = PCI_MSI_FLAGS, // 2 > .size = 2, > .init_val = 0x0000, > - .ro_mask = 0x018E, > - .emu_mask = 0xFFFF, > + .ro_mask = 0xFF8E, > + .emu_mask = 0x007F, > .init = pt_msgctrl_reg_init, > .u.w.read = pt_word_reg_read, > .u.w.write = pt_msgctrl_reg_write, > @@ -564,9 +562,9 @@ static struct pt_reg_info_tbl pt_emu_reg_msi_tbl[] = { > .offset = PCI_MSI_ADDRESS_LO, // 4 > .size = 4, > .init_val = 0x00000000, > - .ro_mask = 0x00000FF0, /* bit 4~11 is reserved for MSI in x86 */ > + .ro_mask = 0x00000003, > .emu_mask = 0xFFFFFFFF, > - .init = pt_msgaddr32_reg_init, > + .init = pt_common_reg_init, > .u.dw.read = pt_long_reg_read, > .u.dw.write = pt_msgaddr32_reg_write, > .u.dw.restore = NULL, > @@ -588,7 +586,7 @@ static struct pt_reg_info_tbl pt_emu_reg_msi_tbl[] = { > .offset = PCI_MSI_DATA_32, // 8 > .size = 2, > .init_val = 0x0000, > - .ro_mask = 0x3800, > + .ro_mask = 0x0000, > .emu_mask = 0xFFFF, > .init = pt_msgdata_reg_init, > .u.w.read = pt_word_reg_read, > @@ -600,7 +598,7 @@ static struct pt_reg_info_tbl pt_emu_reg_msi_tbl[] = { > .offset = PCI_MSI_DATA_64, // 12 > .size = 2, > .init_val = 0x0000, > - .ro_mask = 0x3800, > + .ro_mask = 0x0000, > .emu_mask = 0xFFFF, > .init = pt_msgdata_reg_init, > .u.w.read = pt_word_reg_read, > @@ -2456,7 +2454,7 @@ static uint32_t pt_msgctrl_reg_init(struct pt_dev *ptdev, > uint32_t reg_field = 0; > > /* use I/O device register''s value as initial value */ > - reg_field |= *((uint16_t*)(d->config + real_offset)); > + reg_field = *((uint16_t*)(d->config + real_offset)); > > if (reg_field & PCI_MSI_FLAGS_ENABLE) > { > @@ -2466,40 +2464,18 @@ static uint32_t pt_msgctrl_reg_init(struct pt_dev *ptdev, > ptdev->msi->flags |= (reg_field | MSI_FLAG_UNINIT); > ptdev->msi->ctrl_offset = real_offset; > > - /* All register is 0 after reset, except first 4 byte */ > - reg_field &= reg->ro_mask; > - > - return reg_field; > -} > - > -/* initialize Message Address register */ > -static uint32_t pt_msgaddr32_reg_init(struct pt_dev *ptdev, > - struct pt_reg_info_tbl *reg, uint32_t real_offset) > -{ > - PCIDevice *d = (struct PCIDevice *)ptdev; > - uint32_t reg_field = 0; > - > - /* use I/O device register''s value as initial value */ > - reg_field |= *((uint32_t*)(d->config + real_offset)); > - > - return reg_field; > + return reg->init_val; > } > > /* initialize Message Upper Address register */ > static uint32_t pt_msgaddr64_reg_init(struct pt_dev *ptdev, > struct pt_reg_info_tbl *reg, uint32_t real_offset) > { > - PCIDevice *d = (struct PCIDevice *)ptdev; > - uint32_t reg_field = 0; > - > /* no need to initialize in case of 32 bit type */ > if (!(ptdev->msi->flags & PCI_MSI_FLAGS_64BIT)) > return PT_INVALID_REG; > > - /* use I/O device register''s value as initial value */ > - reg_field |= *((uint32_t*)(d->config + real_offset)); > - > - return reg_field; > + return reg->init_val; > } > > /* this function will be called twice (for 32 bit and 64 bit type) */ > @@ -2507,14 +2483,13 @@ static uint32_t pt_msgaddr64_reg_init(struct pt_dev *ptdev, > static uint32_t pt_msgdata_reg_init(struct pt_dev *ptdev, > struct pt_reg_info_tbl *reg, uint32_t real_offset) > { > - PCIDevice *d = (struct PCIDevice *)ptdev; > uint32_t flags = ptdev->msi->flags; > uint32_t offset = reg->offset; > > /* check the offset whether matches the type or not */ > if (((offset == PCI_MSI_DATA_64) && (flags & PCI_MSI_FLAGS_64BIT)) || > ((offset == PCI_MSI_DATA_32) && !(flags & PCI_MSI_FLAGS_64BIT))) > - return *((uint16_t*)(d->config + real_offset)); > + return reg->init_val; > else > return PT_INVALID_REG; > } > @@ -2528,18 +2503,17 @@ static uint32_t pt_msixctrl_reg_init(struct pt_dev *ptdev, > uint16_t reg_field = 0; > > /* use I/O device register''s value as initial value */ > - reg_field |= *((uint16_t*)(d->config + real_offset)); > + reg_field = *((uint16_t*)(d->config + real_offset)); > > if (reg_field & PCI_MSIX_ENABLE) > { > PT_LOG("MSIX enabled already, disable first\n"); > pci_write_word(pdev, real_offset, reg_field & ~PCI_MSIX_ENABLE); > - reg_field &= ~(PCI_MSIX_ENABLE | PCI_MSIX_MASK); > } > > ptdev->msix->ctrl_offset = real_offset; > > - return reg_field; > + return reg->init_val; > } > > /* get register group size */_______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel