WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-devel

Re: [Xen-devel] [PATCH V3 07/10] Introduce Xen PCI Passthrough, qdevice

To: Anthony PERARD <anthony.perard@xxxxxxxxxx>
Subject: Re: [Xen-devel] [PATCH V3 07/10] Introduce Xen PCI Passthrough, qdevice (1/3)
From: Konrad Rzeszutek Wilk <konrad.wilk@xxxxxxxxxx>
Date: Thu, 10 Nov 2011 16:28:40 -0500
Cc: Guy Zana <guy@xxxxxxxxxxxx>, Xen Devel <xen-devel@xxxxxxxxxxxxxxxxxxx>, Allen Kay <allen.m.kay@xxxxxxxxx>, QEMU-devel <qemu-devel@xxxxxxxxxx>, Stefano Stabellini <stefano.stabellini@xxxxxxxxxxxxx>
Delivery-date: Thu, 10 Nov 2011 13:29:57 -0800
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
In-reply-to: <1319814456-8158-8-git-send-email-anthony.perard@xxxxxxxxxx>
List-help: <mailto:xen-devel-request@lists.xensource.com?subject=help>
List-id: Xen developer discussion <xen-devel.lists.xensource.com>
List-post: <mailto:xen-devel@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=unsubscribe>
References: <1319814456-8158-1-git-send-email-anthony.perard@xxxxxxxxxx> <1319814456-8158-8-git-send-email-anthony.perard@xxxxxxxxxx>
Sender: xen-devel-bounces@xxxxxxxxxxxxxxxxxxx
User-agent: Mutt/1.5.21 (2010-09-15)
On Fri, Oct 28, 2011 at 04:07:33PM +0100, Anthony PERARD wrote:
> From: Allen Kay <allen.m.kay@xxxxxxxxx>
> 

This is going to be a bit lame review..

> +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");

during
> +        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 */

Perhaps 'loop around the 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 */

based 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 
> "

So.. it is called PT_LOG, but the first thing it says is Warning. So should it 
be
PT_WARN?

> +               "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.

until
> +         * so finished previous request here.

finish
> +         */
> +        PT_LOG("Warning: guest want to write durring power state 
> transition\n");

during
> +        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);

There isn't a PT_ERR? Hm, looking at the code there is only PT_LOG. Perhaps
declearing PT_ERR and PT_WARN might be a good idea? In case in the future
one wants different levels of this? Or do we really not care much about that?

> +        memset(&read_val, 0xff, len);
> +    }
> +
> +    /* pass directly to libpci for passthrough type register group */

Um, is the libpci requirement a certain thing?

> +    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 */

loop around what the guest requested..

> +    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 */

based 
> +            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);

Oh. I hadn't realized this, but you are using hw_error. Which is
calling 'abort'! Yikes. Is there no way to recover from this? Say return 
0xfffff?

> +            }
> +
> +            /* 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);
> +    }
> +}
> +
> +/* 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) {

old_ebase != PCI_BAR_UNMAPPED ?

> +        /* 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) {

PCI_BAR_UNMAPPED

> +        /* 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) {

PCI_BAR_UNMAPPED
> +        /* 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;

PCI_BAR_UNMAPPED

> +    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;

PCI_BAR_UNMAPPED

> +            }
> +        }
> +    }
> +
> +    /* 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) {

So should you check for PCI_BAR_UNMAPPED or is that not really
required here as the pci_register_bar would do it?

> +            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);

You can make the "xen_pci-pt-bar" be a #define somewhere and reuse that.

> +                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);
> +
> +    /* Bind interrupt */
> +    if (!s->dev.config[PCI_INTERRUPT_PIN]) {
> +        PT_LOG("no pin interrupt\n");

Perhaps include some details of which device failed?

> +        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);

Can you also include the IRQ it tried to map (both machine and pirq).

> +
> +        /* 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);

A bit details - name of the device, the IRQ,..

> +
> +            /* 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);

And here too. It would be beneficial to have on the error paths lots of 
nice details so that in the field it will be easier to find out what
went wrong (and match up PIRQ with the GSI).


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel

<Prev in Thread] Current Thread [Next in Thread>