[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] Re: [Qemu-devel] [PATCH V3 07/10] Introduce Xen PCI Passthrough, qdevice (1/3)
On Tue, Nov 8, 2011 at 12:56, Stefano Stabellini <stefano.stabellini@xxxxxxxxxxxxx> wrote: > On Fri, 28 Oct 2011, Anthony PERARD wrote: >> From: Allen Kay <allen.m.kay@xxxxxxxxx> >> >> Signed-off-by: Allen Kay <allen.m.kay@xxxxxxxxx> >> Signed-off-by: Guy Zana <guy@xxxxxxxxxxxx> >> Signed-off-by: Anthony PERARD <anthony.perard@xxxxxxxxxx> >> --- >> ÂMakefile.target         Â|  Â2 + >> Âhw/xen_pci_passthrough.c     | Â838 >> ++++++++++++++++++++++++++++++++++++++ >> Âhw/xen_pci_passthrough.h     | Â223 ++++++++++ >> Âhw/xen_pci_passthrough_helpers.c |  46 ++ >> Â4 files changed, 1109 insertions(+), 0 deletions(-) >> Âcreate mode 100644 hw/xen_pci_passthrough.c >> Âcreate mode 100644 hw/xen_pci_passthrough.h >> Âcreate mode 100644 hw/xen_pci_passthrough_helpers.c >> >> diff --git a/Makefile.target b/Makefile.target >> index 243f9f2..36ea47d 100644 >> --- a/Makefile.target >> +++ b/Makefile.target >> @@ -217,6 +217,8 @@ obj-i386-$(CONFIG_XEN) += xen_platform.o >> >> Â# Xen PCI Passthrough >> Âobj-i386-$(CONFIG_XEN_PCI_PASSTHROUGH) += host-pci-device.o >> +obj-i386-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen_pci_passthrough.o >> +obj-i386-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen_pci_passthrough_helpers.o >> >> Â# Inter-VM PCI shared memory >> ÂCONFIG_IVSHMEM = >> diff --git a/hw/xen_pci_passthrough.c b/hw/xen_pci_passthrough.c >> new file mode 100644 >> index 0000000..b97c5b6 >> --- /dev/null >> +++ b/hw/xen_pci_passthrough.c >> @@ -0,0 +1,838 @@ >> +/* >> + * Copyright (c) 2007, Neocleus Corporation. >> + * Copyright (c) 2007, Intel Corporation. >> + * >> + * This work is licensed under the terms of the GNU GPL, version 2. ÂSee >> + * the COPYING file in the top-level directory. >> + * >> + * Alex Novik <alex@xxxxxxxxxxxx> >> + * Allen Kay <allen.m.kay@xxxxxxxxx> >> + * Guy Zana <guy@xxxxxxxxxxxx> >> + * >> + * This file implements direct PCI assignment to a HVM guest >> + */ >> + >> +/* >> + * Interrupt Disable policy: >> + * >> + * INTx interrupt: >> + *  Initialize(register_real_device) >> + *   Map INTx(xc_physdev_map_pirq): >> + *    <fail> >> + *     - Set real Interrupt Disable bit to '1'. >> + *     - Set machine_irq and assigned_device->machine_irq to '0'. >> + *     * Don't bind INTx. >> + * >> + *   Bind INTx(xc_domain_bind_pt_pci_irq): >> + *    <fail> >> + *     - Set real Interrupt Disable bit to '1'. >> + *     - Unmap INTx. >> + *     - Decrement mapped_machine_irq[machine_irq] >> + *     - Set assigned_device->machine_irq to '0'. >> + * >> + *  Write to Interrupt Disable bit by guest software(pt_cmd_reg_write) >> + *   Write '0' >> + *    <ptdev->msi_trans_en is false> >> + *     - Set real bit to '0' if assigned_device->machine_irq isn't '0'. >> + * >> + *   Write '1' >> + *    <ptdev->msi_trans_en is false> >> + *     - Set real bit to '1'. >> + * >> + * MSI-INTx translation. >> + *  Initialize(xc_physdev_map_pirq_msi/pt_msi_setup) >> + *   Bind MSI-INTx(xc_domain_bind_pt_irq) >> + *    <fail> >> + *     - Unmap MSI. >> + *      <success> >> + *       - Set dev->msi->pirq to '-1'. >> + *      <fail> >> + *       - Do nothing. >> + * >> + *  Write to Interrupt Disable bit by guest software(pt_cmd_reg_write) >> + *   Write '0' >> + *    <ptdev->msi_trans_en is true> >> + *     - Set MSI Enable bit to '1'. >> + * >> + *   Write '1' >> + *    <ptdev->msi_trans_en is true> >> + *     - Set MSI Enable bit to '0'. >> + * >> + * MSI interrupt: >> + *  Initialize MSI register(pt_msi_setup, pt_msi_update) >> + *   Bind MSI(xc_domain_update_msi_irq) >> + *    <fail> >> + *     - Unmap MSI. >> + *     - Set dev->msi->pirq to '-1'. >> + * >> + * MSI-X interrupt: >> + *  Initialize MSI-X register(pt_msix_update_one) >> + *   Bind MSI-X(xc_domain_update_msi_irq) >> + *    <fail> >> + *     - Unmap MSI-X. >> + *     - Set entry->pirq to '-1'. >> + */ >> + > > you should move all the MSI related comments to the MSI patch OK, I will move MSI comments. >> +#include <sys/ioctl.h> >> + >> +#include "pci.h" >> +#include "xen.h" >> +#include "xen_backend.h" >> +#include "xen_pci_passthrough.h" >> + >> +#define PCI_BAR_ENTRIES (6) >> + >> +#define PT_NR_IRQS     Â(256) >> +char mapped_machine_irq[PT_NR_IRQS] = {0}; >> + >> +/* Config Space */ >> +static int pt_pci_config_access_check(PCIDevice *d, uint32_t address, int >> len) >> +{ >> +  Â/* check offset range */ >> +  Âif (address >= 0xFF) { >> +    ÂPT_LOG("Error: Failed to access register with offset exceeding FFh. >> " >> +        "[%02x:%02x.%x][Offset:%02xh][Length:%d]\n", >> +        pci_bus_num(d->bus), PCI_SLOT(d->devfn), PCI_FUNC(d->devfn), >> +        address, len); >> +    Âreturn -1; >> +  Â} >> + >> +  Â/* check read size */ >> +  Âif ((len != 1) && (len != 2) && (len != 4)) { >> +    ÂPT_LOG("Error: Failed to access register with invalid access >> length. " >> +        "[%02x:%02x.%x][Offset:%02xh][Length:%d]\n", >> +        pci_bus_num(d->bus), PCI_SLOT(d->devfn), PCI_FUNC(d->devfn), >> +        address, len); >> +    Âreturn -1; >> +  Â} >> + >> +  Â/* check offset alignment */ >> +  Âif (address & (len - 1)) { >> +    ÂPT_LOG("Error: Failed to access register with invalid access size " >> +      Â"alignment. [%02x:%02x.%x][Offset:%02xh][Length:%d]\n", >> +      Âpci_bus_num(d->bus), PCI_SLOT(d->devfn), PCI_FUNC(d->devfn), >> +      Âaddress, len); >> +    Âreturn -1; >> +  Â} >> + >> +  Âreturn 0; >> +} >> + >> +int pt_bar_offset_to_index(uint32_t offset) >> +{ >> +  Âint index = 0; >> + >> +  Â/* check Exp ROM BAR */ >> +  Âif (offset == PCI_ROM_ADDRESS) { >> +    Âreturn PCI_ROM_SLOT; >> +  Â} >> + >> +  Â/* calculate BAR index */ >> +  Âindex = (offset - PCI_BASE_ADDRESS_0) >> 2; >> +  Âif (index >= PCI_NUM_REGIONS) { >> +    Âreturn -1; >> +  Â} >> + >> +  Âreturn index; >> +} >> + >> +static uint32_t pt_pci_read_config(PCIDevice *d, uint32_t address, int len) >> +{ >> +  ÂXenPCIPassthroughState *s = DO_UPCAST(XenPCIPassthroughState, dev, d); >> +  Âuint32_t val = 0; >> +  ÂXenPTRegGroup *reg_grp_entry = NULL; >> +  ÂXenPTReg *reg_entry = NULL; >> +  Âint rc = 0; >> +  Âint emul_len = 0; >> +  Âuint32_t find_addr = address; >> + >> +  Âif (pt_pci_config_access_check(d, address, len)) { >> +    Âgoto exit; >> +  Â} >> + >> +  Â/* check power state transition flags */ >> +  Âif (s->pm_state != NULL && s->pm_state->flags & PT_FLAG_TRANSITING) { >> +    Â/* can't accept until previous power state transition is completed. >> +     * so finished previous request here. >> +     */ >> +    ÂPT_LOG("Warning: guest want to write durring power state >> transition\n"); >> +    Âgoto exit; >> +  Â} >> + >> +  Â/* find register group entry */ >> +  Âreg_grp_entry = pt_find_reg_grp(s, address); >> +  Âif (reg_grp_entry) { >> +    Â/* check 0 Hardwired register group */ >> +    Âif (reg_grp_entry->reg_grp->grp_type == GRP_TYPE_HARDWIRED) { >> +      Â/* no need to emulate, just return 0 */ >> +      Âval = 0; >> +      Âgoto exit; >> +    Â} >> +  Â} >> + >> +  Â/* read I/O device register value */ >> +  Ârc = host_pci_get_block(s->real_device, address, (uint8_t *)&val, len); >> +  Âif (!rc) { >> +    ÂPT_LOG("Error: pci_read_block failed. return value[%d].\n", rc); >> +    Âmemset(&val, 0xff, len); >> +  Â} >> + >> +  Â/* just return the I/O device register value for >> +   * passthrough type register group */ >> +  Âif (reg_grp_entry == NULL) { >> +    Âgoto exit; >> +  Â} >> + >> +  Â/* adjust the read value to appropriate CFC-CFF window */ >> +  Âval <<= (address & 3) << 3; >> +  Âemul_len = len; >> + >> +  Â/* loop Guest request size */ >> +  Âwhile (emul_len > 0) { >> +    Â/* find register entry to be emulated */ >> +    Âreg_entry = pt_find_reg(reg_grp_entry, find_addr); >> +    Âif (reg_entry) { >> +      ÂXenPTRegInfo *reg = reg_entry->reg; >> +      Âuint32_t real_offset = reg_grp_entry->base_offset + reg->offset; >> +      Âuint32_t valid_mask = 0xFFFFFFFF >> ((4 - emul_len) << 3); >> +      Âuint8_t *ptr_val = NULL; >> + >> +      Âvalid_mask <<= (find_addr - real_offset) << 3; >> +      Âptr_val = (uint8_t *)&val + (real_offset & 3); >> + >> +      Â/* do emulation depend on register size */ >> +      Âswitch (reg->size) { >> +      Âcase 1: >> +        Âif (reg->u.b.read) { >> +          Ârc = reg->u.b.read(s, reg_entry, ptr_val, valid_mask); >> +        Â} >> +        Âbreak; >> +      Âcase 2: >> +        Âif (reg->u.w.read) { >> +          Ârc = reg->u.w.read(s, reg_entry, >> +                    (uint16_t *)ptr_val, valid_mask); >> +        Â} >> +        Âbreak; >> +      Âcase 4: >> +        Âif (reg->u.dw.read) { >> +          Ârc = reg->u.dw.read(s, reg_entry, >> +                    Â(uint32_t *)ptr_val, valid_mask); >> +        Â} >> +        Âbreak; >> +      Â} >> + >> +      Âif (rc < 0) { >> +        Âhw_error("Internal error: Invalid read emulation " >> +             "return value[%d]. I/O emulator exit.\n", rc); >> +      Â} >> + >> +      Â/* calculate next address to find */ >> +      Âemul_len -= reg->size; >> +      Âif (emul_len > 0) { >> +        Âfind_addr = real_offset + reg->size; >> +      Â} >> +    Â} else { >> +      Â/* nothing to do with passthrough type register, >> +       * continue to find next byte */ >> +      Âemul_len--; >> +      Âfind_addr++; >> +    Â} >> +  Â} >> + >> +  Â/* need to shift back before returning them to pci bus emulator */ >> +  Âval >>= ((address & 3) << 3); >> + >> +exit: >> +  ÂPT_LOG_CONFIG("[%02x:%02x.%x]: address=%04x val=0x%08x len=%d\n", >> +         Âpci_bus_num(d->bus), PCI_SLOT(d->devfn), >> PCI_FUNC(d->devfn), >> +         Âaddress, val, len); >> +  Âreturn val; >> +} >> + >> +static void pt_pci_write_config(PCIDevice *d, uint32_t address, >> +                Âuint32_t val, int len) >> +{ >> +  ÂXenPCIPassthroughState *s = DO_UPCAST(XenPCIPassthroughState, dev, d); >> +  Âint index = 0; >> +  ÂXenPTRegGroup *reg_grp_entry = NULL; >> +  Âint rc = 0; >> +  Âuint32_t read_val = 0; >> +  Âint emul_len = 0; >> +  ÂXenPTReg *reg_entry = NULL; >> +  Âuint32_t find_addr = address; >> +  ÂXenPTRegInfo *reg = NULL; >> + >> +  Âif (pt_pci_config_access_check(d, address, len)) { >> +    Âreturn; >> +  Â} >> + >> +  ÂPT_LOG_CONFIG("[%02x:%02x.%x]: address=%04x val=0x%08x len=%d\n", >> +         Âpci_bus_num(d->bus), PCI_SLOT(d->devfn), >> PCI_FUNC(d->devfn), >> +         Âaddress, val, len); >> + >> +  Â/* check unused BAR register */ >> +  Âindex = pt_bar_offset_to_index(address); >> +  Âif ((index >= 0) && (val > 0 && val < PT_BAR_ALLF) && >> +    Â(s->bases[index].bar_flag == PT_BAR_FLAG_UNUSED)) { >> +    ÂPT_LOG("Warning: Guest attempt to set address to unused Base >> Address " >> +        "Register. [%02x:%02x.%x][Offset:%02xh][Length:%d]\n", >> +        pci_bus_num(d->bus), PCI_SLOT(d->devfn), PCI_FUNC(d->devfn), >> +        address, len); >> +  Â} >> + >> +  Â/* check power state transition flags */ >> +  Âif (s->pm_state != NULL && s->pm_state->flags & PT_FLAG_TRANSITING) { >> +    Â/* can't accept untill previous power state transition is completed. >> +     * so finished previous request here. >> +     */ >> +    ÂPT_LOG("Warning: guest want to write durring power state >> transition\n"); >> +    Âreturn; >> +  Â} >> + >> +  Â/* find register group entry */ >> +  Âreg_grp_entry = pt_find_reg_grp(s, address); >> +  Âif (reg_grp_entry) { >> +    Â/* check 0 Hardwired register group */ >> +    Âif (reg_grp_entry->reg_grp->grp_type == GRP_TYPE_HARDWIRED) { >> +      Â/* ignore silently */ >> +      ÂPT_LOG("Warning: Access to 0 Hardwired register. " >> +          "[%02x:%02x.%x][Offset:%02xh][Length:%d]\n", >> +          pci_bus_num(d->bus), PCI_SLOT(d->devfn), >> PCI_FUNC(d->devfn), >> +          address, len); >> +      Âreturn; >> +    Â} >> +  Â} >> + >> +  Â/* read I/O device register value */ >> +  Ârc = host_pci_get_block(s->real_device, address, >> +               (uint8_t *)&read_val, len); >> +  Âif (!rc) { >> +    ÂPT_LOG("Error: pci_read_block failed. return value[%d].\n", rc); >> +    Âmemset(&read_val, 0xff, len); >> +  Â} >> + >> +  Â/* pass directly to libpci for passthrough type register group */ >> +  Âif (reg_grp_entry == NULL) { >> +    Âgoto out; >> +  Â} >> + >> +  Â/* adjust the read and write value to appropriate CFC-CFF window */ >> +  Âread_val <<= (address & 3) << 3; >> +  Âval <<= (address & 3) << 3; >> +  Âemul_len = len; >> + >> +  Â/* loop Guest request size */ >> +  Âwhile (emul_len > 0) { >> +    Â/* find register entry to be emulated */ >> +    Âreg_entry = pt_find_reg(reg_grp_entry, find_addr); >> +    Âif (reg_entry) { >> +      Âreg = reg_entry->reg; >> +      Âuint32_t real_offset = reg_grp_entry->base_offset + reg->offset; >> +      Âuint32_t valid_mask = 0xFFFFFFFF >> ((4 - emul_len) << 3); >> +      Âuint8_t *ptr_val = NULL; >> + >> +      Âvalid_mask <<= (find_addr - real_offset) << 3; >> +      Âptr_val = (uint8_t *)&val + (real_offset & 3); >> + >> +      Â/* do emulation depend on register size */ >> +      Âswitch (reg->size) { >> +      Âcase 1: >> +        Âif (reg->u.b.write) { >> +          Ârc = reg->u.b.write(s, reg_entry, ptr_val, >> +                    Âread_val >> ((real_offset & 3) << >> 3), >> +                    Âvalid_mask); >> +        Â} >> +        Âbreak; >> +      Âcase 2: >> +        Âif (reg->u.w.write) { >> +          Ârc = reg->u.w.write(s, reg_entry, (uint16_t *)ptr_val, >> +                    Â(read_val >> ((real_offset & 3) << >> 3)), >> +                    Âvalid_mask); >> +        Â} >> +        Âbreak; >> +      Âcase 4: >> +        Âif (reg->u.dw.write) { >> +          Ârc = reg->u.dw.write(s, reg_entry, (uint32_t *)ptr_val, >> +                     (read_val >> ((real_offset & 3) << >> 3)), >> +                     valid_mask); >> +        Â} >> +        Âbreak; >> +      Â} >> + >> +      Âif (rc < 0) { >> +        Âhw_error("Internal error: Invalid write emulation " >> +             "return value[%d]. I/O emulator exit.\n", rc); >> +      Â} >> + >> +      Â/* calculate next address to find */ >> +      Âemul_len -= reg->size; >> +      Âif (emul_len > 0) { >> +        Âfind_addr = real_offset + reg->size; >> +      Â} >> +    Â} else { >> +      Â/* nothing to do with passthrough type register, >> +       * continue to find next byte */ >> +      Âemul_len--; >> +      Âfind_addr++; >> +    Â} >> +  Â} >> + >> +  Â/* need to shift back before passing them to libpci */ >> +  Âval >>= (address & 3) << 3; >> + >> +out: >> +  Âif (!(reg && reg->no_wb)) { >> +    Â/* unknown regs are passed through */ >> +    Ârc = host_pci_set_block(s->real_device, address, (uint8_t *)&val, >> len); >> + >> +    Âif (!rc) { >> +      ÂPT_LOG("Error: pci_write_block failed. return value[%d].\n", >> rc); >> +    Â} >> +  Â} >> + >> +  Âif (s->pm_state != NULL && s->pm_state->flags & PT_FLAG_TRANSITING) { >> +    Âqemu_mod_timer(s->pm_state->pm_timer, >> +            qemu_get_clock_ms(rt_clock) + s->pm_state->pm_delay); >> +  Â} >> +} > > Where is this timer allocated and initialized? In the next patch, I will move this lines to the releated patch. >> +/* ioport/iomem space*/ >> +static void pt_iomem_map(XenPCIPassthroughState *s, int i, >> +             pcibus_t e_phys, pcibus_t e_size, int type) >> +{ >> +  Âuint32_t old_ebase = s->bases[i].e_physbase; >> +  Âbool first_map = s->bases[i].e_size == 0; >> +  Âint ret = 0; >> + >> +  Âs->bases[i].e_physbase = e_phys; >> +  Âs->bases[i].e_size = e_size; >> + >> +  ÂPT_LOG("e_phys=%#"PRIx64" maddr=%#"PRIx64" type=%%d" >> +      " len=%#"PRIx64" index=%d first_map=%d\n", >> +      e_phys, s->bases[i].access.maddr, /*type,*/ >> +      e_size, i, first_map); >> + >> +  Âif (e_size == 0) { >> +    Âreturn; >> +  Â} >> + >> +  Âif (!first_map && old_ebase != -1) { >> +    Â/* Remove old mapping */ >> +    Âret = xc_domain_memory_mapping(xen_xc, xen_domid, >> +                old_ebase >> XC_PAGE_SHIFT, >> +                s->bases[i].access.maddr >> XC_PAGE_SHIFT, >> +                (e_size + XC_PAGE_SIZE - 1) >> XC_PAGE_SHIFT, >> +                DPCI_REMOVE_MAPPING); >> +    Âif (ret != 0) { >> +      ÂPT_LOG("Error: remove old mapping failed!\n"); >> +      Âreturn; >> +    Â} >> +  Â} >> + >> +  Â/* map only valid guest address */ >> +  Âif (e_phys != -1) { >> +    Â/* Create new mapping */ >> +    Âret = xc_domain_memory_mapping(xen_xc, xen_domid, >> +                  s->bases[i].e_physbase >> XC_PAGE_SHIFT, >> +                  s->bases[i].access.maddr >> >> XC_PAGE_SHIFT, >> +                  (e_size+XC_PAGE_SIZE-1) >> XC_PAGE_SHIFT, >> +                  DPCI_ADD_MAPPING); >> + >> +    Âif (ret != 0) { >> +      ÂPT_LOG("Error: create new mapping failed!\n"); >> +    Â} >> +  Â} >> +} >> + >> +static void pt_ioport_map(XenPCIPassthroughState *s, int i, >> +             Âpcibus_t e_phys, pcibus_t e_size, int type) >> +{ >> +  Âuint32_t old_ebase = s->bases[i].e_physbase; >> +  Âbool first_map = s->bases[i].e_size == 0; >> +  Âint ret = 0; >> + >> +  Âs->bases[i].e_physbase = e_phys; >> +  Âs->bases[i].e_size = e_size; >> + >> +  ÂPT_LOG("e_phys=%#04"PRIx64" pio_base=%#04"PRIx64" len=%"PRId64" >> index=%d" >> +      " first_map=%d\n", >> +      e_phys, s->bases[i].access.pio_base, e_size, i, first_map); >> + >> +  Âif (e_size == 0) { >> +    Âreturn; >> +  Â} >> + >> +  Âif (!first_map && old_ebase != -1) { >> +    Â/* Remove old mapping */ >> +    Âret = xc_domain_ioport_mapping(xen_xc, xen_domid, old_ebase, >> +                    s->bases[i].access.pio_base, e_size, >> +                    DPCI_REMOVE_MAPPING); >> +    Âif (ret != 0) { >> +      ÂPT_LOG("Error: remove old mapping failed!\n"); >> +      Âreturn; >> +    Â} >> +  Â} >> + >> +  Â/* map only valid guest address (include 0) */ >> +  Âif (e_phys != -1) { >> +    Â/* Create new mapping */ >> +    Âret = xc_domain_ioport_mapping(xen_xc, xen_domid, e_phys, >> +                    s->bases[i].access.pio_base, e_size, >> +                    DPCI_ADD_MAPPING); >> +    Âif (ret != 0) { >> +      ÂPT_LOG("Error: create new mapping failed!\n"); >> +    Â} >> +  Â} >> + >> +} >> + >> + >> +/* mapping BAR */ >> + >> +void pt_bar_mapping_one(XenPCIPassthroughState *s, int bar, >> +            Âint io_enable, int mem_enable) >> +{ >> +  ÂPCIDevice *dev = &s->dev; >> +  ÂPCIIORegion *r; >> +  ÂXenPTRegGroup *reg_grp_entry = NULL; >> +  ÂXenPTReg *reg_entry = NULL; >> +  ÂXenPTRegion *base = NULL; >> +  Âpcibus_t r_size = 0, r_addr = -1; >> +  Âint rc = 0; >> + >> +  Âr = &dev->io_regions[bar]; >> + >> +  Â/* check valid region */ >> +  Âif (!r->size) { >> +    Âreturn; >> +  Â} >> + >> +  Âbase = &s->bases[bar]; >> +  Â/* skip unused BAR or upper 64bit BAR */ >> +  Âif ((base->bar_flag == PT_BAR_FLAG_UNUSED) >> +    Â|| (base->bar_flag == PT_BAR_FLAG_UPPER)) { >> +      return; >> +  Â} >> + >> +  Â/* copy region address to temporary */ >> +  Âr_addr = r->addr; >> + >> +  Â/* need unmapping in case I/O Space or Memory Space disable */ >> +  Âif (((base->bar_flag == PT_BAR_FLAG_IO) && !io_enable) || >> +    Â((base->bar_flag == PT_BAR_FLAG_MEM) && !mem_enable)) { >> +    Âr_addr = -1; >> +  Â} >> +  Âif ((bar == PCI_ROM_SLOT) && (r_addr != -1)) { >> +    Âreg_grp_entry = pt_find_reg_grp(s, PCI_ROM_ADDRESS); >> +    Âif (reg_grp_entry) { >> +      Âreg_entry = pt_find_reg(reg_grp_entry, PCI_ROM_ADDRESS); >> +      Âif (reg_entry && !(reg_entry->data & PCI_ROM_ADDRESS_ENABLE)) { >> +        Âr_addr = -1; >> +      Â} >> +    Â} >> +  Â} >> + >> +  Â/* prevent guest software mapping memory resource to 00000000h */ >> +  Âif ((base->bar_flag == PT_BAR_FLAG_MEM) && (r_addr == 0)) { >> +    Âr_addr = -1; >> +  Â} >> + >> +  Âr_size = pt_get_emul_size(base->bar_flag, r->size); >> + >> +  Ârc = pci_check_bar_overlap(dev, r_addr, r_size, r->type); >> +  Âif (rc > 0) { >> +    ÂPT_LOG("Warning: s[%02x:%02x.%x][Region:%d][Address:%"FMT_PCIBUS"h]" >> +        "[Size:%"FMT_PCIBUS"h] is overlapped.\n", >> pci_bus_num(dev->bus), >> +        PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), bar, >> +        r_addr, r_size); >> +  Â} >> + >> +  Â/* check whether we need to update the mapping or not */ >> +  Âif (r_addr != s->bases[bar].e_physbase) { >> +    Â/* mapping BAR */ >> +    Âif (base->bar_flag == PT_BAR_FLAG_IO) { >> +      Âpt_ioport_map(s, bar, r_addr, r_size, r->type); >> +    Â} else { >> +      Âpt_iomem_map(s, bar, r_addr, r_size, r->type); >> +    Â} >> +  Â} >> +} >> + >> +void pt_bar_mapping(XenPCIPassthroughState *s, int io_enable, int >> mem_enable) >> +{ >> +  Âint i; >> + >> +  Âfor (i = 0; i < PCI_NUM_REGIONS; i++) { >> +    Âpt_bar_mapping_one(s, i, io_enable, mem_enable); >> +  Â} >> +} >> + >> +/* register regions */ >> +static int pt_register_regions(XenPCIPassthroughState *s) >> +{ >> +  Âint i = 0; >> +  Âuint32_t bar_data = 0; >> +  ÂHostPCIDevice *d = s->real_device; >> + >> +  Â/* Register PIO/MMIO BARs */ >> +  Âfor (i = 0; i < PCI_BAR_ENTRIES; i++) { >> +    ÂHostPCIIORegion *r = &d->io_regions[i]; >> + >> +    Âif (r->base_addr) { >> +      Âs->bases[i].e_physbase = r->base_addr; >> +      Âs->bases[i].access.u = r->base_addr; >> + >> +      Â/* Register current region */ >> +      Âif (r->flags & IORESOURCE_IO) { >> +        Âmemory_region_init_io(&s->bar[i], NULL, NULL, >> +                   Â"xen-pci-pt-bar", r->size); >> +        Âpci_register_bar(&s->dev, i, PCI_BASE_ADDRESS_SPACE_IO, >> +                 &s->bar[i]); >> +      Â} else if (r->flags & IORESOURCE_PREFETCH) { >> +        Âmemory_region_init_io(&s->bar[i], NULL, NULL, >> +                   Â"xen-pci-pt-bar", r->size); >> +        Âpci_register_bar(&s->dev, i, PCI_BASE_ADDRESS_MEM_PREFETCH, >> +                 &s->bar[i]); >> +      Â} else { >> +        Âmemory_region_init_io(&s->bar[i], NULL, NULL, >> +                   Â"xen-pci-pt-bar", r->size); >> +        Âpci_register_bar(&s->dev, i, PCI_BASE_ADDRESS_SPACE_MEMORY, >> +                 &s->bar[i]); >> +      Â} >> + >> +      ÂPT_LOG("IO region registered (size=0x%08"PRIx64 >> +          " base_addr=0x%08"PRIx64")\n", >> +          r->size, r->base_addr); >> +    Â} >> +  Â} >> + >> +  Â/* Register expansion ROM address */ >> +  Âif (d->rom.base_addr && d->rom.size) { >> +    Â/* Re-set BAR reported by OS, otherwise ROM can't be read. */ >> +    Âbar_data = host_pci_get_long(d, PCI_ROM_ADDRESS); >> +    Âif ((bar_data & PCI_ROM_ADDRESS_MASK) == 0) { >> +      Âbar_data |= d->rom.base_addr & PCI_ROM_ADDRESS_MASK; >> +      Âhost_pci_set_long(d, PCI_ROM_ADDRESS, bar_data); >> +    Â} >> + >> +    Âs->bases[PCI_ROM_SLOT].e_physbase = d->rom.base_addr; >> +    Âs->bases[PCI_ROM_SLOT].access.maddr = d->rom.base_addr; >> + >> +    Âmemory_region_init_rom_device(&s->rom, NULL, NULL, &s->dev.qdev, >> +                   Â"xen-pci-pt-rom", d->rom.size); >> +    Âpci_register_bar(&s->dev, PCI_ROM_SLOT, >> PCI_BASE_ADDRESS_MEM_PREFETCH, >> +             &s->rom); >> + >> +    ÂPT_LOG("Expansion ROM registered (size=0x%08"PRIx64 >> +        " base_addr=0x%08"PRIx64")\n", >> +        d->rom.size, d->rom.base_addr); >> +  Â} >> + >> +  Âreturn 0; >> +} >> + >> +static void pt_unregister_regions(XenPCIPassthroughState *s) >> +{ >> +  Âint i, type, rc; >> +  Âuint32_t e_size; >> +  ÂPCIDevice *d = &s->dev; >> + >> +  Âfor (i = 0; i < PCI_NUM_REGIONS; i++) { >> +    Âe_size = s->bases[i].e_size; >> +    Âif ((e_size == 0) || (s->bases[i].e_physbase == -1)) { >> +      Âcontinue; >> +    Â} >> + >> +    Âtype = d->io_regions[i].type; >> + >> +    Âif (type == PCI_BASE_ADDRESS_SPACE_MEMORY >> +      Â|| type == PCI_BASE_ADDRESS_MEM_PREFETCH) { >> +      Ârc = xc_domain_memory_mapping(xen_xc, xen_domid, >> +          Âs->bases[i].e_physbase >> XC_PAGE_SHIFT, >> +          Âs->bases[i].access.maddr >> XC_PAGE_SHIFT, >> +          Â(e_size+XC_PAGE_SIZE-1) >> XC_PAGE_SHIFT, >> +          ÂDPCI_REMOVE_MAPPING); >> +      Âif (rc != 0) { >> +        ÂPT_LOG("Error: remove old mem mapping failed!\n"); >> +        Âcontinue; >> +      Â} >> + >> +    Â} else if (type == PCI_BASE_ADDRESS_SPACE_IO) { >> +      Ârc = xc_domain_ioport_mapping(xen_xc, xen_domid, >> +            Âs->bases[i].e_physbase, >> +            Âs->bases[i].access.pio_base, >> +            Âe_size, >> +            ÂDPCI_REMOVE_MAPPING); >> +      Âif (rc != 0) { >> +        ÂPT_LOG("Error: remove old io mapping failed!\n"); >> +        Âcontinue; >> +      Â} >> +    Â} >> +  Â} >> +} >> + >> +static int pt_initfn(PCIDevice *pcidev) >> +{ >> +  ÂXenPCIPassthroughState *s = DO_UPCAST(XenPCIPassthroughState, dev, >> pcidev); >> +  Âint dom, bus; >> +  Âunsigned slot, func; >> +  Âint rc = 0; >> +  Âuint32_t machine_irq; >> +  Âint pirq = -1; >> + >> +  Âif (pci_parse_devaddr(s->hostaddr, &dom, &bus, &slot, &func) < 0) { >> +    Âfprintf(stderr, "error parse bdf: %s\n", s->hostaddr); >> +    Âreturn -1; >> +  Â} >> + >> +  Â/* register real device */ >> +  ÂPT_LOG("Assigning real physical device %02x:%02x.%x to devfn %i ...\n", >> +      bus, slot, func, s->dev.devfn); >> + >> +  Âs->real_device = host_pci_device_get(bus, slot, func); >> +  Âif (!s->real_device) { >> +    Âreturn -1; >> +  Â} >> + >> +  Âs->is_virtfn = s->real_device->is_virtfn; >> +  Âif (s->is_virtfn) { >> +    ÂPT_LOG("%04x:%02x:%02x.%x is a SR-IOV Virtual Function\n", >> +        s->real_device->domain, bus, slot, func); >> +  Â} >> + >> +  Â/* Initialize virtualized PCI configuration (Extended 256 Bytes) */ >> +  Âif (host_pci_get_block(s->real_device, 0, pcidev->config, >> +              PCI_CONFIG_SPACE_SIZE) == -1) { >> +    Âreturn -1; >> +  Â} >> + >> +  Â/* Handle real device's MMIO/PIO BARs */ >> +  Âpt_register_regions(s); >> + >> +  Â/* reinitialize each config register to be emulated */ >> +  Âpt_config_init(s); > > this function is implemented in the next patch, so you might as well add > this call there Ok, I will move this. >> +  Â/* Bind interrupt */ >> +  Âif (!s->dev.config[PCI_INTERRUPT_PIN]) { >> +    ÂPT_LOG("no pin interrupt\n"); >> +    Âgoto out; >> +  Â} >> + >> +  Âmachine_irq = host_pci_get_byte(s->real_device, PCI_INTERRUPT_LINE); >> +  Ârc = xc_physdev_map_pirq(xen_xc, xen_domid, machine_irq, &pirq); >> + >> +  Âif (rc) { >> +    ÂPT_LOG("Error: Mapping irq failed, rc = %d\n", rc); >> + >> +    Â/* Disable PCI intx assertion (turn on bit10 of devctl) */ >> +    Âhost_pci_set_word(s->real_device, >> +             ÂPCI_COMMAND, >> +             Âpci_get_word(s->dev.config + PCI_COMMAND) >> +             Â| PCI_COMMAND_INTX_DISABLE); >> +    Âmachine_irq = 0; >> +    Âs->machine_irq = 0; >> +  Â} else { >> +    Âmachine_irq = pirq; >> +    Âs->machine_irq = pirq; >> +    Âmapped_machine_irq[machine_irq]++; >> +  Â} >> + >> +  Â/* bind machine_irq to device */ >> +  Âif (rc < 0 && machine_irq != 0) { >> +    Âuint8_t e_device = PCI_SLOT(s->dev.devfn); >> +    Âuint8_t e_intx = pci_intx(s); >> + >> +    Ârc = xc_domain_bind_pt_pci_irq(xen_xc, xen_domid, machine_irq, 0, >> +                    e_device, e_intx); >> +    Âif (rc < 0) { >> +      ÂPT_LOG("Error: Binding of interrupt failed! rc=%d\n", rc); >> + >> +      Â/* Disable PCI intx assertion (turn on bit10 of devctl) */ >> +      Âhost_pci_set_word(s->real_device, PCI_COMMAND, >> +               Â*(uint16_t *)(&s->dev.config[PCI_COMMAND]) >> +               Â| PCI_COMMAND_INTX_DISABLE); >> +      Âmapped_machine_irq[machine_irq]--; >> + >> +      Âif (mapped_machine_irq[machine_irq] == 0) { >> +        Âif (xc_physdev_unmap_pirq(xen_xc, xen_domid, machine_irq)) { >> +          ÂPT_LOG("Error: Unmapping of interrupt failed! rc=%d\n", >> +              rc); >> +        Â} >> +      Â} >> +      Âs->machine_irq = 0; >> +    Â} >> +  Â} >> + >> +out: >> +  ÂPT_LOG("Real physical device %02x:%02x.%x registered successfuly!\n" >> +      "IRQ type = %s\n", bus, slot, func, "INTx"); >> + >> +  Âreturn 0; >> +} >> + >> +static int pt_unregister_device(PCIDevice *pcidev) >> +{ >> +  ÂXenPCIPassthroughState *s = DO_UPCAST(XenPCIPassthroughState, dev, >> pcidev); >> +  Âuint8_t e_device, e_intx; >> +  Âuint32_t machine_irq; >> +  Âint rc; >> + >> +  Â/* Unbind interrupt */ >> +  Âe_device = PCI_SLOT(s->dev.devfn); >> +  Âe_intx = pci_intx(s); >> +  Âmachine_irq = s->machine_irq; >> + >> +  Âif (machine_irq) { >> +    Ârc = xc_domain_unbind_pt_irq(xen_xc, xen_domid, machine_irq, >> +                   PT_IRQ_TYPE_PCI, 0, e_device, e_intx, >> 0); >> +    Âif (rc < 0) { >> +      ÂPT_LOG("Error: Unbinding of interrupt failed! rc=%d\n", rc); >> +    Â} >> +  Â} >> + >> +  Âif (machine_irq) { >> +    Âmapped_machine_irq[machine_irq]--; >> + >> +    Âif (mapped_machine_irq[machine_irq] == 0) { >> +      Ârc = xc_physdev_unmap_pirq(xen_xc, xen_domid, machine_irq); >> + >> +      Âif (rc < 0) { >> +        ÂPT_LOG("Error: Unmaping of interrupt failed! rc=%d\n", rc); >> +      Â} >> +    Â} >> +  Â} >> + >> +  Â/* delete all emulated config registers */ >> +  Âpt_config_delete(s); >> + >> +  Â/* unregister real device's MMIO/PIO BARs */ >> +  Âpt_unregister_regions(s); >> + >> +  Âhost_pci_device_put(s->real_device); >> + >> +  Âreturn 0; >> +} >> + >> +static PCIDeviceInfo xen_pci_passthrough = { >> +  Â.init = pt_initfn, >> +  Â.exit = pt_unregister_device, >> +  Â.qdev.name = "xen-pci-passthrough", >> +  Â.qdev.desc = "Assign an host pci device with Xen", >> +  Â.qdev.size = sizeof(XenPCIPassthroughState), >> +  Â.config_read = pt_pci_read_config, >> +  Â.config_write = pt_pci_write_config, >> +  Â.is_express = 0, >> +  Â.qdev.props = (Property[]) { >> +    ÂDEFINE_PROP_STRING("hostaddr", XenPCIPassthroughState, hostaddr), >> +    ÂDEFINE_PROP_BIT("power-mgmt", XenPCIPassthroughState, power_mgmt, >> +            Â0, false), >> +    ÂDEFINE_PROP_END_OF_LIST(), >> +  Â} >> +}; >> + >> +static void xen_passthrough_register(void) >> +{ >> +  Âpci_qdev_register(&xen_pci_passthrough); >> +} >> + >> +device_init(xen_passthrough_register); >> diff --git a/hw/xen_pci_passthrough.h b/hw/xen_pci_passthrough.h >> new file mode 100644 >> index 0000000..2d1979d >> --- /dev/null >> +++ b/hw/xen_pci_passthrough.h >> @@ -0,0 +1,223 @@ >> +#ifndef QEMU_HW_XEN_PCI_PASSTHROUGH_H >> +# Âdefine QEMU_HW_XEN_PCI_PASSTHROUGH_H >> + >> +#include "qemu-common.h" >> +#include "xen_common.h" >> +#include "pci.h" >> +#include "host-pci-device.h" >> + >> +#define PT_LOGGING_ENABLED >> +#define PT_DEBUG_PCI_CONFIG_ACCESS >> + >> +#ifdef PT_LOGGING_ENABLED >> +# Âdefine PT_LOG(_f, _a...)  fprintf(stderr, "%s: " _f, __func__, ##_a) >> +#else >> +# Âdefine PT_LOG(_f, _a...) >> +#endif >> + >> +#ifdef PT_DEBUG_PCI_CONFIG_ACCESS >> +# Âdefine PT_LOG_CONFIG(_f, _a...) PT_LOG(_f, ##_a) >> +#else >> +# Âdefine PT_LOG_CONFIG(_f, _a...) >> +#endif >> + >> + >> +typedef struct XenPTRegInfo XenPTRegInfo; >> +typedef struct XenPTReg XenPTReg; >> + >> +typedef struct XenPCIPassthroughState XenPCIPassthroughState; >> + >> +/* function type for config reg */ >> +typedef uint32_t (*conf_reg_init) >> +  Â(XenPCIPassthroughState *, XenPTRegInfo *, uint32_t real_offset); >> +typedef int (*conf_dword_write) >> +  Â(XenPCIPassthroughState *, XenPTReg *cfg_entry, >> +   uint32_t *val, uint32_t dev_value, uint32_t valid_mask); >> +typedef int (*conf_word_write) >> +  Â(XenPCIPassthroughState *, XenPTReg *cfg_entry, >> +   uint16_t *val, uint16_t dev_value, uint16_t valid_mask); >> +typedef int (*conf_byte_write) >> +  Â(XenPCIPassthroughState *, XenPTReg *cfg_entry, >> +   uint8_t *val, uint8_t dev_value, uint8_t valid_mask); >> +typedef int (*conf_dword_read) >> +  Â(XenPCIPassthroughState *, XenPTReg *cfg_entry, >> +   uint32_t *val, uint32_t valid_mask); >> +typedef int (*conf_word_read) >> +  Â(XenPCIPassthroughState *, XenPTReg *cfg_entry, >> +   uint16_t *val, uint16_t valid_mask); >> +typedef int (*conf_byte_read) >> +  Â(XenPCIPassthroughState *, XenPTReg *cfg_entry, >> +   uint8_t *val, uint8_t valid_mask); >> +typedef int (*conf_dword_restore) >> +  Â(XenPCIPassthroughState *, XenPTReg *cfg_entry, uint32_t real_offset, >> +   uint32_t dev_value, uint32_t *val); >> +typedef int (*conf_word_restore) >> +  Â(XenPCIPassthroughState *, XenPTReg *cfg_entry, uint32_t real_offset, >> +   uint16_t dev_value, uint16_t *val); >> +typedef int (*conf_byte_restore) >> +  Â(XenPCIPassthroughState *, XenPTReg *cfg_entry, uint32_t real_offset, >> +   uint8_t dev_value, uint8_t *val); >> + >> +/* power state transition */ >> +#define PT_FLAG_TRANSITING 0x0001 >> + >> + >> +typedef enum { >> +  ÂGRP_TYPE_HARDWIRED = 0,           /* 0 Hardwired reg group */ >> +  ÂGRP_TYPE_EMU,                /* emul reg group */ >> +} RegisterGroupType; >> + >> +typedef enum { >> +  ÂPT_BAR_FLAG_MEM = 0,            Â/* Memory type BAR */ >> +  ÂPT_BAR_FLAG_IO,               /* I/O type BAR */ >> +  ÂPT_BAR_FLAG_UPPER,             Â/* upper 64bit BAR */ >> +  ÂPT_BAR_FLAG_UNUSED,             /* unused BAR */ >> +} PTBarFlag; >> + >> + >> +typedef struct XenPTRegion { >> +  Â/* Virtual phys base & size */ >> +  Âuint32_t e_physbase; >> +  Âuint32_t e_size; >> +  Â/* Index of region in qemu */ >> +  Âuint32_t memory_index; >> +  Â/* BAR flag */ >> +  ÂPTBarFlag bar_flag; >> +  Â/* Translation of the emulated address */ >> +  Âunion { >> +    Âuint64_t maddr; >> +    Âuint64_t pio_base; >> +    Âuint64_t u; >> +  Â} access; >> +} XenPTRegion; >> + >> +/* XenPTRegInfo declaration >> + * - only for emulated register (either a part or whole bit). >> + * - for passthrough register that need special behavior (like interacting >> with >> + *  other component), set emu_mask to all 0 and specify r/w func properly. >> + * - do NOT use ALL F for init_val, otherwise the tbl will not be >> registered. >> + */ >> + >> +/* emulated register infomation */ >> +struct XenPTRegInfo { >> +  Âuint32_t offset; >> +  Âuint32_t size; >> +  Âuint32_t init_val; >> +  Â/* reg read only field mask (ON:RO/ROS, OFF:other) */ >> +  Âuint32_t ro_mask; >> +  Â/* reg emulate field mask (ON:emu, OFF:passthrough) */ >> +  Âuint32_t emu_mask; >> +  Â/* no write back allowed */ >> +  Âuint32_t no_wb; >> +  Âconf_reg_init init; >> +  Â/* read/write/restore function pointer >> +   * for double_word/word/byte size */ >> +  Âunion { >> +    Âstruct { >> +      Âconf_dword_write write; >> +      Âconf_dword_read read; >> +      Âconf_dword_restore restore; >> +    Â} dw; >> +    Âstruct { >> +      Âconf_word_write write; >> +      Âconf_word_read read; >> +      Âconf_word_restore restore; >> +    Â} w; >> +    Âstruct { >> +      Âconf_byte_write write; >> +      Âconf_byte_read read; >> +      Âconf_byte_restore restore; >> +    Â} b; >> +  Â} u; >> +}; >> + >> +/* emulated register management */ >> +struct XenPTReg { >> +  ÂQLIST_ENTRY(XenPTReg) entries; >> +  ÂXenPTRegInfo *reg; >> +  Âuint32_t data; >> +}; >> + >> +typedef struct XenPTRegGroupInfo XenPTRegGroupInfo; >> + >> +/* emul reg group size initialize method */ >> +typedef uint8_t (*pt_reg_size_init_fn) >> +  Â(XenPCIPassthroughState *, const XenPTRegGroupInfo *, >> +   uint32_t base_offset); >> + >> +/* emulated register group infomation */ >> +struct XenPTRegGroupInfo { >> +  Âuint8_t grp_id; >> +  ÂRegisterGroupType grp_type; >> +  Âuint8_t grp_size; >> +  Âpt_reg_size_init_fn size_init; >> +  ÂXenPTRegInfo *emu_reg_tbl; >> +}; >> + >> +/* emul register group management table */ >> +typedef struct XenPTRegGroup { >> +  ÂQLIST_ENTRY(XenPTRegGroup) entries; >> +  Âconst XenPTRegGroupInfo *reg_grp; >> +  Âuint32_t base_offset; >> +  Âuint8_t size; >> +  ÂQLIST_HEAD(, XenPTReg) reg_tbl_list; >> +} XenPTRegGroup; >> + >> + >> +typedef struct XenPTPM { >> +  ÂQEMUTimer *pm_timer; Â/* QEMUTimer struct */ >> +  Âint no_soft_reset;  Â/* No Soft Reset flags */ >> +  Âuint16_t flags;    /* power state transition flags */ >> +  Âuint16_t pmc_field;  /* Power Management Capabilities field */ >> +  Âint pm_delay;     /* power state transition delay */ >> +  Âuint16_t cur_state;  /* current power state */ >> +  Âuint16_t req_state;  /* requested power state */ >> +  Âuint32_t pm_base;   /* Power Management Capability reg base offset */ >> +  Âuint32_t aer_base;  Â/* AER Capability reg base offset */ >> +} XenPTPM; >> + >> +struct XenPCIPassthroughState { >> +  ÂPCIDevice dev; >> + >> +  Âchar *hostaddr; >> +  Âbool is_virtfn; >> +  ÂHostPCIDevice *real_device; >> +  ÂXenPTRegion bases[PCI_NUM_REGIONS]; /* Access regions */ >> +  ÂQLIST_HEAD(, XenPTRegGroup) reg_grp_tbl; >> + >> +  Âuint32_t machine_irq; >> + >> +  Âuint32_t power_mgmt; >> +  ÂXenPTPM *pm_state; >> + >> +  ÂMemoryRegion bar[PCI_NUM_REGIONS - 1]; >> +  ÂMemoryRegion rom; >> +}; >> + >> +void pt_config_init(XenPCIPassthroughState *s); >> +void pt_config_delete(XenPCIPassthroughState *s); >> +void pt_bar_mapping(XenPCIPassthroughState *s, int io_enable, int >> mem_enable); >> +void pt_bar_mapping_one(XenPCIPassthroughState *s, int bar, >> +            Âint io_enable, int mem_enable); >> +XenPTRegGroup *pt_find_reg_grp(XenPCIPassthroughState *s, uint32_t address); >> +XenPTReg *pt_find_reg(XenPTRegGroup *reg_grp, uint32_t address); >> +int pt_bar_offset_to_index(uint32_t offset); >> + >> +static inline pcibus_t pt_get_emul_size(PTBarFlag flag, pcibus_t r_size) >> +{ >> +  Â/* align resource size (memory type only) */ >> +  Âif (flag == PT_BAR_FLAG_MEM) { >> +    Âreturn (r_size + XC_PAGE_SIZE - 1) & XC_PAGE_MASK; >> +  Â} else { >> +    Âreturn r_size; >> +  Â} >> +} >> + >> +/* INTx */ >> +static inline uint8_t pci_read_intx(XenPCIPassthroughState *s) >> +{ >> +  Âreturn host_pci_get_byte(s->real_device, PCI_INTERRUPT_PIN); >> +} >> +uint8_t pci_intx(XenPCIPassthroughState *ptdev); >> + >> +#endif /* !QEMU_HW_XEN_PCI_PASSTHROUGH_H */ >> diff --git a/hw/xen_pci_passthrough_helpers.c >> b/hw/xen_pci_passthrough_helpers.c >> new file mode 100644 >> index 0000000..192e918 >> --- /dev/null >> +++ b/hw/xen_pci_passthrough_helpers.c >> @@ -0,0 +1,46 @@ >> +#include "xen_pci_passthrough.h" >> + >> +/* The PCI Local Bus Specification, Rev. 3.0, { >> + * Section 6.2.4 Miscellaneous Registers, pp 223 >> + * outlines 5 valid values for the intertupt pin (intx). >> + * Â0: For devices (or device functions) that don't use an interrupt in >> + * Â1: INTA# >> + * Â2: INTB# >> + * Â3: INTC# >> + * Â4: INTD# >> + * >> + * Xen uses the following 4 values for intx >> + * Â0: INTA# >> + * Â1: INTB# >> + * Â2: INTC# >> + * Â3: INTD# >> + * >> + * Observing that these list of values are not the same, pci_read_intx() >> + * uses the following mapping from hw to xen values. >> + * This seems to reflect the current usage within Xen. >> + * >> + * PCI hardware  Â| Xen | Notes >> + * >> ----------------+-----+---------------------------------------------------- >> + * 0        | 0  | No interrupt >> + * 1        | 0  | INTA# >> + * 2        | 1  | INTB# >> + * 3        | 2  | INTC# >> + * 4        | 3  | INTD# >> + * any other value | 0  | This should never happen, log error message >> +} >> + */ >> +uint8_t pci_intx(XenPCIPassthroughState *ptdev) >> +{ >> +  Âuint8_t r_val = pci_read_intx(ptdev); >> + >> +  ÂPT_LOG("intx=%i\n", r_val); >> +  Âif (r_val < 1 || r_val > 4) { >> +    ÂPT_LOG("Interrupt pin read from hardware is out of range: " >> +        "value=%i, acceptable range is 1 - 4\n", r_val); >> +    Âr_val = 0; >> +  Â} else { >> +    Âr_val -= 1; >> +  Â} >> + >> +  Âreturn r_val; >> +} > > if xen_pci_passthrough_helpers.c is only going to contain this function > you might as well declared it static inline and move it to > xen_pci_passthrough.h Ok, I will. -- Anthony PERARD _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |