[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [Xen-devel] [PATCH V11 5/8] Introduce Xen PCI Passthrou
From: |
Konrad Rzeszutek Wilk |
Subject: |
Re: [Qemu-devel] [Xen-devel] [PATCH V11 5/8] Introduce Xen PCI Passthrough, qdevice (1/3) |
Date: |
Wed, 16 May 2012 07:31:43 -0400 |
User-agent: |
Mutt/1.5.9i |
> +void xen_pt_log(const PCIDevice *d, const char *f, ...)
> +{
> + va_list ap;
> +
> + va_start(ap, f);
> + if (d) {
> + fprintf(stderr, "[%02x:%02x.%x] ", pci_bus_num(d->bus),
%d at the end and in the other location pls fix it up..
> + PCI_SLOT(d->devfn), PCI_FUNC(d->devfn));
> + }
> + vfprintf(stderr, f, ap);
> + va_end(ap);
> +}
> +
> +/* Config Space */
> +
.. Is there a way to make this function (and the following one) squahed?
> +static uint32_t xen_pt_pci_read_config(PCIDevice *d, uint32_t addr, 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 = addr;
> +
> + if (xen_pt_pci_config_access_check(d, addr, len)) {
> + goto exit;
> + }
> +
> + /* find register group entry */
> + reg_grp_entry = xen_pt_find_reg_grp(s, addr);
> + if (reg_grp_entry) {
> + /* check 0-Hardwired register group */
> + if (reg_grp_entry->reg_grp->grp_type == XEN_PT_GRP_TYPE_HARDWIRED) {
> + /* no need to emulate, just return 0 */
> + val = 0;
> + goto exit;
> + }
> + }
> +
> + /* read I/O device register value */
> + rc = xen_host_pci_get_block(&s->real_device, addr, (uint8_t *)&val, len);
> + if (rc < 0) {
> + XEN_PT_ERR(d, "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 <<= (addr & 3) << 3;
> + emul_len = len;
> +
> + /* loop around the guest requested size */
> + while (emul_len > 0) {
> + /* find register entry to be emulated */
> + reg_entry = xen_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 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) {
> + xen_shutdown_fatal_error("Internal error: Invalid read "
> + "emulation. (%s, rc: %d)\n",
> + __func__, rc);
> + return 0;
> + }
> +
> + /* 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 >>= ((addr & 3) << 3);
> +
> +exit:
> + XEN_PT_LOG_CONFIG(d, addr, val, len);
> + return val;
> +}
> +
> +static void xen_pt_pci_write_config(PCIDevice *d, uint32_t addr,
> + 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 = addr;
> + XenPTRegInfo *reg = NULL;
> +
> + if (xen_pt_pci_config_access_check(d, addr, len)) {
> + return;
> + }
> +
> + XEN_PT_LOG_CONFIG(d, addr, val, len);
> +
> + /* check unused BAR register */
> + index = xen_pt_bar_offset_to_index(addr);
> + if ((index >= 0) && (val > 0 && val < XEN_PT_BAR_ALLF) &&
> + (s->bases[index].bar_flag == XEN_PT_BAR_FLAG_UNUSED)) {
> + XEN_PT_WARN(d, "Guest attempt to set address to unused Base Address "
> + "Register. (addr: 0x%02x, len: %d)\n", addr, len);
> + }
> +
> + /* find register group entry */
> + reg_grp_entry = xen_pt_find_reg_grp(s, addr);
> + if (reg_grp_entry) {
> + /* check 0-Hardwired register group */
> + if (reg_grp_entry->reg_grp->grp_type == XEN_PT_GRP_TYPE_HARDWIRED) {
> + /* ignore silently */
> + XEN_PT_WARN(d, "Access to 0-Hardwired register. "
> + "(addr: 0x%02x, len: %d)\n", addr, len);
> + return;
> + }
> + }
> +
> + rc = xen_host_pci_get_block(&s->real_device, addr,
> + (uint8_t *)&read_val, len);
> + if (rc < 0) {
> + XEN_PT_ERR(d, "pci_read_block failed. return value: %d.\n", rc);
> + memset(&read_val, 0xff, len);
> + }
> +
> + /* pass directly to the real device for passthrough type register group
> */
> + if (reg_grp_entry == NULL) {
> + goto out;
> + }
> +
> + memory_region_transaction_begin();
> + pci_default_write_config(d, addr, val, len);
> +
> + /* adjust the read and write value to appropriate CFC-CFF window */
> + read_val <<= (addr & 3) << 3;
> + val <<= (addr & 3) << 3;
> + emul_len = len;
> +
> + /* loop around the guest requested size */
> + while (emul_len > 0) {
> + /* find register entry to be emulated */
> + reg_entry = xen_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 based 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) {
> + xen_shutdown_fatal_error("Internal error: Invalid write"
> + " emulation. (%s, rc: %d)\n",
> + __func__, rc);
> + return;
> + }
> +
> + /* 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 xen_host_pci_device */
> + val >>= (addr & 3) << 3;
> +
> + memory_region_transaction_commit();
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- Re: [Qemu-devel] [Xen-devel] [PATCH V11 5/8] Introduce Xen PCI Passthrough, qdevice (1/3),
Konrad Rzeszutek Wilk <=