diff options
author | Paolo Bonzini <pbonzini@redhat.com> | 2013-02-05 13:25:08 +0100 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2013-04-08 18:13:14 +0200 |
commit | 80b4ecc86dd5ccd779f96c8bd11feb031d327614 (patch) | |
tree | 8ee50e34fdb12139fede5ec0a53a2e61ff32635f /hw/xen_pt_config_init.c | |
parent | 53a5500244a9d38505174bac56d81a8be2979f39 (diff) |
hw: move more files to hw/xen/
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'hw/xen_pt_config_init.c')
-rw-r--r-- | hw/xen_pt_config_init.c | 1882 |
1 files changed, 0 insertions, 1882 deletions
diff --git a/hw/xen_pt_config_init.c b/hw/xen_pt_config_init.c deleted file mode 100644 index 3ee2adfb9e..0000000000 --- a/hw/xen_pt_config_init.c +++ /dev/null @@ -1,1882 +0,0 @@ -/* - * 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@neocleus.com> - * Allen Kay <allen.m.kay@intel.com> - * Guy Zana <guy@neocleus.com> - * - * This file implements direct PCI assignment to a HVM guest - */ - -#include "qemu/timer.h" -#include "hw/xen/xen_backend.h" -#include "hw/xen_pt.h" - -#define XEN_PT_MERGE_VALUE(value, data, val_mask) \ - (((value) & (val_mask)) | ((data) & ~(val_mask))) - -#define XEN_PT_INVALID_REG 0xFFFFFFFF /* invalid register value */ - -/* prototype */ - -static int xen_pt_ptr_reg_init(XenPCIPassthroughState *s, XenPTRegInfo *reg, - uint32_t real_offset, uint32_t *data); - - -/* helper */ - -/* A return value of 1 means the capability should NOT be exposed to guest. */ -static int xen_pt_hide_dev_cap(const XenHostPCIDevice *d, uint8_t grp_id) -{ - switch (grp_id) { - case PCI_CAP_ID_EXP: - /* The PCI Express Capability Structure of the VF of Intel 82599 10GbE - * Controller looks trivial, e.g., the PCI Express Capabilities - * Register is 0. We should not try to expose it to guest. - * - * The datasheet is available at - * http://download.intel.com/design/network/datashts/82599_datasheet.pdf - * - * See 'Table 9.7. VF PCIe Configuration Space' of the datasheet, the - * PCI Express Capability Structure of the VF of Intel 82599 10GbE - * Controller looks trivial, e.g., the PCI Express Capabilities - * Register is 0, so the Capability Version is 0 and - * xen_pt_pcie_size_init() would fail. - */ - if (d->vendor_id == PCI_VENDOR_ID_INTEL && - d->device_id == PCI_DEVICE_ID_INTEL_82599_SFP_VF) { - return 1; - } - break; - } - return 0; -} - -/* find emulate register group entry */ -XenPTRegGroup *xen_pt_find_reg_grp(XenPCIPassthroughState *s, uint32_t address) -{ - XenPTRegGroup *entry = NULL; - - /* find register group entry */ - QLIST_FOREACH(entry, &s->reg_grps, entries) { - /* check address */ - if ((entry->base_offset <= address) - && ((entry->base_offset + entry->size) > address)) { - return entry; - } - } - - /* group entry not found */ - return NULL; -} - -/* find emulate register entry */ -XenPTReg *xen_pt_find_reg(XenPTRegGroup *reg_grp, uint32_t address) -{ - XenPTReg *reg_entry = NULL; - XenPTRegInfo *reg = NULL; - uint32_t real_offset = 0; - - /* find register entry */ - QLIST_FOREACH(reg_entry, ®_grp->reg_tbl_list, entries) { - reg = reg_entry->reg; - real_offset = reg_grp->base_offset + reg->offset; - /* check address */ - if ((real_offset <= address) - && ((real_offset + reg->size) > address)) { - return reg_entry; - } - } - - return NULL; -} - - -/**************** - * general register functions - */ - -/* register initialization function */ - -static int xen_pt_common_reg_init(XenPCIPassthroughState *s, - XenPTRegInfo *reg, uint32_t real_offset, - uint32_t *data) -{ - *data = reg->init_val; - return 0; -} - -/* Read register functions */ - -static int xen_pt_byte_reg_read(XenPCIPassthroughState *s, XenPTReg *cfg_entry, - uint8_t *value, uint8_t valid_mask) -{ - XenPTRegInfo *reg = cfg_entry->reg; - uint8_t valid_emu_mask = 0; - - /* emulate byte register */ - valid_emu_mask = reg->emu_mask & valid_mask; - *value = XEN_PT_MERGE_VALUE(*value, cfg_entry->data, ~valid_emu_mask); - - return 0; -} -static int xen_pt_word_reg_read(XenPCIPassthroughState *s, XenPTReg *cfg_entry, - uint16_t *value, uint16_t valid_mask) -{ - XenPTRegInfo *reg = cfg_entry->reg; - uint16_t valid_emu_mask = 0; - - /* emulate word register */ - valid_emu_mask = reg->emu_mask & valid_mask; - *value = XEN_PT_MERGE_VALUE(*value, cfg_entry->data, ~valid_emu_mask); - - return 0; -} -static int xen_pt_long_reg_read(XenPCIPassthroughState *s, XenPTReg *cfg_entry, - uint32_t *value, uint32_t valid_mask) -{ - XenPTRegInfo *reg = cfg_entry->reg; - uint32_t valid_emu_mask = 0; - - /* emulate long register */ - valid_emu_mask = reg->emu_mask & valid_mask; - *value = XEN_PT_MERGE_VALUE(*value, cfg_entry->data, ~valid_emu_mask); - - return 0; -} - -/* Write register functions */ - -static int xen_pt_byte_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry, - uint8_t *val, uint8_t dev_value, - uint8_t valid_mask) -{ - XenPTRegInfo *reg = cfg_entry->reg; - uint8_t writable_mask = 0; - uint8_t throughable_mask = 0; - - /* modify emulate register */ - writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask; - cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask); - - /* create value for writing to I/O device register */ - throughable_mask = ~reg->emu_mask & valid_mask; - *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask); - - return 0; -} -static int xen_pt_word_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 = 0; - - /* modify emulate register */ - writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask; - cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask); - - /* create value for writing to I/O device register */ - throughable_mask = ~reg->emu_mask & valid_mask; - *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask); - - return 0; -} -static int xen_pt_long_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry, - uint32_t *val, uint32_t dev_value, - uint32_t valid_mask) -{ - XenPTRegInfo *reg = cfg_entry->reg; - uint32_t writable_mask = 0; - uint32_t throughable_mask = 0; - - /* modify emulate register */ - writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask; - cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask); - - /* create value for writing to I/O device register */ - throughable_mask = ~reg->emu_mask & valid_mask; - *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask); - - return 0; -} - - -/* 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. - */ - -/******************** - * Header Type0 - */ - -static int xen_pt_vendor_reg_init(XenPCIPassthroughState *s, - XenPTRegInfo *reg, uint32_t real_offset, - uint32_t *data) -{ - *data = s->real_device.vendor_id; - return 0; -} -static int xen_pt_device_reg_init(XenPCIPassthroughState *s, - XenPTRegInfo *reg, uint32_t real_offset, - uint32_t *data) -{ - *data = s->real_device.device_id; - return 0; -} -static int xen_pt_status_reg_init(XenPCIPassthroughState *s, - XenPTRegInfo *reg, uint32_t real_offset, - uint32_t *data) -{ - XenPTRegGroup *reg_grp_entry = NULL; - XenPTReg *reg_entry = NULL; - uint32_t reg_field = 0; - - /* find Header register group */ - reg_grp_entry = xen_pt_find_reg_grp(s, PCI_CAPABILITY_LIST); - if (reg_grp_entry) { - /* find Capabilities Pointer register */ - reg_entry = xen_pt_find_reg(reg_grp_entry, PCI_CAPABILITY_LIST); - if (reg_entry) { - /* check Capabilities Pointer register */ - if (reg_entry->data) { - reg_field |= PCI_STATUS_CAP_LIST; - } else { - reg_field &= ~PCI_STATUS_CAP_LIST; - } - } else { - xen_shutdown_fatal_error("Internal error: Couldn't find XenPTReg*" - " for Capabilities Pointer register." - " (%s)\n", __func__); - return -1; - } - } else { - xen_shutdown_fatal_error("Internal error: Couldn't find XenPTRegGroup" - " for Header. (%s)\n", __func__); - return -1; - } - - *data = reg_field; - return 0; -} -static int xen_pt_header_type_reg_init(XenPCIPassthroughState *s, - XenPTRegInfo *reg, uint32_t real_offset, - uint32_t *data) -{ - /* read PCI_HEADER_TYPE */ - *data = reg->init_val | 0x80; - return 0; -} - -/* initialize Interrupt Pin register */ -static int xen_pt_irqpin_reg_init(XenPCIPassthroughState *s, - XenPTRegInfo *reg, uint32_t real_offset, - uint32_t *data) -{ - *data = xen_pt_pci_read_intx(s); - return 0; -} - -/* Command register */ -static int xen_pt_cmd_reg_read(XenPCIPassthroughState *s, XenPTReg *cfg_entry, - uint16_t *value, uint16_t valid_mask) -{ - XenPTRegInfo *reg = cfg_entry->reg; - uint16_t valid_emu_mask = 0; - uint16_t emu_mask = reg->emu_mask; - - if (s->is_virtfn) { - emu_mask |= PCI_COMMAND_MEMORY; - } - - /* emulate word register */ - valid_emu_mask = emu_mask & valid_mask; - *value = XEN_PT_MERGE_VALUE(*value, cfg_entry->data, ~valid_emu_mask); - - return 0; -} -static int xen_pt_cmd_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 = 0; - uint16_t emu_mask = reg->emu_mask; - - if (s->is_virtfn) { - emu_mask |= PCI_COMMAND_MEMORY; - } - - /* modify emulate register */ - writable_mask = ~reg->ro_mask & valid_mask; - cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask); - - /* create value for writing to I/O device register */ - throughable_mask = ~emu_mask & valid_mask; - - if (*val & PCI_COMMAND_INTX_DISABLE) { - throughable_mask |= PCI_COMMAND_INTX_DISABLE; - } else { - if (s->machine_irq) { - throughable_mask |= PCI_COMMAND_INTX_DISABLE; - } - } - - *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask); - - return 0; -} - -/* BAR */ -#define XEN_PT_BAR_MEM_RO_MASK 0x0000000F /* BAR ReadOnly mask(Memory) */ -#define XEN_PT_BAR_MEM_EMU_MASK 0xFFFFFFF0 /* BAR emul mask(Memory) */ -#define XEN_PT_BAR_IO_RO_MASK 0x00000003 /* BAR ReadOnly mask(I/O) */ -#define XEN_PT_BAR_IO_EMU_MASK 0xFFFFFFFC /* BAR emul mask(I/O) */ - -static bool is_64bit_bar(PCIIORegion *r) -{ - return !!(r->type & PCI_BASE_ADDRESS_MEM_TYPE_64); -} - -static uint64_t xen_pt_get_bar_size(PCIIORegion *r) -{ - if (is_64bit_bar(r)) { - uint64_t size64; - size64 = (r + 1)->size; - size64 <<= 32; - size64 += r->size; - return size64; - } - return r->size; -} - -static XenPTBarFlag xen_pt_bar_reg_parse(XenPCIPassthroughState *s, - XenPTRegInfo *reg) -{ - PCIDevice *d = &s->dev; - XenPTRegion *region = NULL; - PCIIORegion *r; - int index = 0; - - /* check 64bit BAR */ - index = xen_pt_bar_offset_to_index(reg->offset); - if ((0 < index) && (index < PCI_ROM_SLOT)) { - int type = s->real_device.io_regions[index - 1].type; - - if ((type & XEN_HOST_PCI_REGION_TYPE_MEM) - && (type & XEN_HOST_PCI_REGION_TYPE_MEM_64)) { - region = &s->bases[index - 1]; - if (region->bar_flag != XEN_PT_BAR_FLAG_UPPER) { - return XEN_PT_BAR_FLAG_UPPER; - } - } - } - - /* check unused BAR */ - r = &d->io_regions[index]; - if (!xen_pt_get_bar_size(r)) { - return XEN_PT_BAR_FLAG_UNUSED; - } - - /* for ExpROM BAR */ - if (index == PCI_ROM_SLOT) { - return XEN_PT_BAR_FLAG_MEM; - } - - /* check BAR I/O indicator */ - if (s->real_device.io_regions[index].type & XEN_HOST_PCI_REGION_TYPE_IO) { - return XEN_PT_BAR_FLAG_IO; - } else { - return XEN_PT_BAR_FLAG_MEM; - } -} - -static inline uint32_t base_address_with_flags(XenHostPCIIORegion *hr) -{ - if (hr->type & XEN_HOST_PCI_REGION_TYPE_IO) { - return hr->base_addr | (hr->bus_flags & ~PCI_BASE_ADDRESS_IO_MASK); - } else { - return hr->base_addr | (hr->bus_flags & ~PCI_BASE_ADDRESS_MEM_MASK); - } -} - -static int xen_pt_bar_reg_init(XenPCIPassthroughState *s, XenPTRegInfo *reg, - uint32_t real_offset, uint32_t *data) -{ - uint32_t reg_field = 0; - int index; - - index = xen_pt_bar_offset_to_index(reg->offset); - if (index < 0 || index >= PCI_NUM_REGIONS) { - XEN_PT_ERR(&s->dev, "Internal error: Invalid BAR index [%d].\n", index); - return -1; - } - - /* set BAR flag */ - s->bases[index].bar_flag = xen_pt_bar_reg_parse(s, reg); - if (s->bases[index].bar_flag == XEN_PT_BAR_FLAG_UNUSED) { - reg_field = XEN_PT_INVALID_REG; - } - - *data = reg_field; - return 0; -} -static int xen_pt_bar_reg_read(XenPCIPassthroughState *s, XenPTReg *cfg_entry, - uint32_t *value, uint32_t valid_mask) -{ - XenPTRegInfo *reg = cfg_entry->reg; - uint32_t valid_emu_mask = 0; - uint32_t bar_emu_mask = 0; - int index; - - /* get BAR index */ - index = xen_pt_bar_offset_to_index(reg->offset); - if (index < 0 || index >= PCI_NUM_REGIONS) { - XEN_PT_ERR(&s->dev, "Internal error: Invalid BAR index [%d].\n", index); - return -1; - } - - /* use fixed-up value from kernel sysfs */ - *value = base_address_with_flags(&s->real_device.io_regions[index]); - - /* set emulate mask depend on BAR flag */ - switch (s->bases[index].bar_flag) { - case XEN_PT_BAR_FLAG_MEM: - bar_emu_mask = XEN_PT_BAR_MEM_EMU_MASK; - break; - case XEN_PT_BAR_FLAG_IO: - bar_emu_mask = XEN_PT_BAR_IO_EMU_MASK; - break; - case XEN_PT_BAR_FLAG_UPPER: - bar_emu_mask = XEN_PT_BAR_ALLF; - break; - default: - break; - } - - /* emulate BAR */ - valid_emu_mask = bar_emu_mask & valid_mask; - *value = XEN_PT_MERGE_VALUE(*value, cfg_entry->data, ~valid_emu_mask); - - return 0; -} -static int xen_pt_bar_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry, - uint32_t *val, uint32_t dev_value, - uint32_t valid_mask) -{ - XenPTRegInfo *reg = cfg_entry->reg; - XenPTRegion *base = NULL; - PCIDevice *d = &s->dev; - const PCIIORegion *r; - uint32_t writable_mask = 0; - uint32_t throughable_mask = 0; - uint32_t bar_emu_mask = 0; - uint32_t bar_ro_mask = 0; - uint32_t r_size = 0; - int index = 0; - - index = xen_pt_bar_offset_to_index(reg->offset); - if (index < 0 || index >= PCI_NUM_REGIONS) { - XEN_PT_ERR(d, "Internal error: Invalid BAR index [%d].\n", index); - return -1; - } - - r = &d->io_regions[index]; - base = &s->bases[index]; - r_size = xen_pt_get_emul_size(base->bar_flag, r->size); - - /* set emulate mask and read-only mask values depend on the BAR flag */ - switch (s->bases[index].bar_flag) { - case XEN_PT_BAR_FLAG_MEM: - bar_emu_mask = XEN_PT_BAR_MEM_EMU_MASK; - if (!r_size) { - /* low 32 bits mask for 64 bit bars */ - bar_ro_mask = XEN_PT_BAR_ALLF; - } else { - bar_ro_mask = XEN_PT_BAR_MEM_RO_MASK | (r_size - 1); - } - break; - case XEN_PT_BAR_FLAG_IO: - bar_emu_mask = XEN_PT_BAR_IO_EMU_MASK; - bar_ro_mask = XEN_PT_BAR_IO_RO_MASK | (r_size - 1); - break; - case XEN_PT_BAR_FLAG_UPPER: - bar_emu_mask = XEN_PT_BAR_ALLF; - bar_ro_mask = r_size ? r_size - 1 : 0; - break; - default: - break; - } - - /* modify emulate register */ - writable_mask = bar_emu_mask & ~bar_ro_mask & valid_mask; - cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask); - - /* check whether we need to update the virtual region address or not */ - switch (s->bases[index].bar_flag) { - case XEN_PT_BAR_FLAG_UPPER: - case XEN_PT_BAR_FLAG_MEM: - /* nothing to do */ - break; - case XEN_PT_BAR_FLAG_IO: - /* nothing to do */ - break; - default: - break; - } - - /* create value for writing to I/O device register */ - throughable_mask = ~bar_emu_mask & valid_mask; - *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask); - - return 0; -} - -/* write Exp ROM BAR */ -static int xen_pt_exp_rom_bar_reg_write(XenPCIPassthroughState *s, - XenPTReg *cfg_entry, uint32_t *val, - uint32_t dev_value, uint32_t valid_mask) -{ - XenPTRegInfo *reg = cfg_entry->reg; - XenPTRegion *base = NULL; - PCIDevice *d = (PCIDevice *)&s->dev; - uint32_t writable_mask = 0; - uint32_t throughable_mask = 0; - pcibus_t r_size = 0; - uint32_t bar_emu_mask = 0; - uint32_t bar_ro_mask = 0; - - r_size = d->io_regions[PCI_ROM_SLOT].size; - base = &s->bases[PCI_ROM_SLOT]; - /* align memory type resource size */ - r_size = xen_pt_get_emul_size(base->bar_flag, r_size); - - /* set emulate mask and read-only mask */ - bar_emu_mask = reg->emu_mask; - bar_ro_mask = (reg->ro_mask | (r_size - 1)) & ~PCI_ROM_ADDRESS_ENABLE; - - /* modify emulate register */ - writable_mask = ~bar_ro_mask & valid_mask; - cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask); - - /* create value for writing to I/O device register */ - throughable_mask = ~bar_emu_mask & valid_mask; - *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask); - - return 0; -} - -/* Header Type0 reg static information table */ -static XenPTRegInfo xen_pt_emu_reg_header0[] = { - /* Vendor ID reg */ - { - .offset = PCI_VENDOR_ID, - .size = 2, - .init_val = 0x0000, - .ro_mask = 0xFFFF, - .emu_mask = 0xFFFF, - .init = xen_pt_vendor_reg_init, - .u.w.read = xen_pt_word_reg_read, - .u.w.write = xen_pt_word_reg_write, - }, - /* Device ID reg */ - { - .offset = PCI_DEVICE_ID, - .size = 2, - .init_val = 0x0000, - .ro_mask = 0xFFFF, - .emu_mask = 0xFFFF, - .init = xen_pt_device_reg_init, - .u.w.read = xen_pt_word_reg_read, - .u.w.write = xen_pt_word_reg_write, - }, - /* Command reg */ - { - .offset = PCI_COMMAND, - .size = 2, - .init_val = 0x0000, - .ro_mask = 0xF880, - .emu_mask = 0x0740, - .init = xen_pt_common_reg_init, - .u.w.read = xen_pt_cmd_reg_read, - .u.w.write = xen_pt_cmd_reg_write, - }, - /* Capabilities Pointer reg */ - { - .offset = PCI_CAPABILITY_LIST, - .size = 1, - .init_val = 0x00, - .ro_mask = 0xFF, - .emu_mask = 0xFF, - .init = xen_pt_ptr_reg_init, - .u.b.read = xen_pt_byte_reg_read, - .u.b.write = xen_pt_byte_reg_write, - }, - /* Status reg */ - /* use emulated Cap Ptr value to initialize, - * so need to be declared after Cap Ptr reg - */ - { - .offset = PCI_STATUS, - .size = 2, - .init_val = 0x0000, - .ro_mask = 0x06FF, - .emu_mask = 0x0010, - .init = xen_pt_status_reg_init, - .u.w.read = xen_pt_word_reg_read, - .u.w.write = xen_pt_word_reg_write, - }, - /* Cache Line Size reg */ - { - .offset = PCI_CACHE_LINE_SIZE, - .size = 1, - .init_val = 0x00, - .ro_mask = 0x00, - .emu_mask = 0xFF, - .init = xen_pt_common_reg_init, - .u.b.read = xen_pt_byte_reg_read, - .u.b.write = xen_pt_byte_reg_write, - }, - /* Latency Timer reg */ - { - .offset = PCI_LATENCY_TIMER, - .size = 1, - .init_val = 0x00, - .ro_mask = 0x00, - .emu_mask = 0xFF, - .init = xen_pt_common_reg_init, - .u.b.read = xen_pt_byte_reg_read, - .u.b.write = xen_pt_byte_reg_write, - }, - /* Header Type reg */ - { - .offset = PCI_HEADER_TYPE, - .size = 1, - .init_val = 0x00, - .ro_mask = 0xFF, - .emu_mask = 0x00, - .init = xen_pt_header_type_reg_init, - .u.b.read = xen_pt_byte_reg_read, - .u.b.write = xen_pt_byte_reg_write, - }, - /* Interrupt Line reg */ - { - .offset = PCI_INTERRUPT_LINE, - .size = 1, - .init_val = 0x00, - .ro_mask = 0x00, - .emu_mask = 0xFF, - .init = xen_pt_common_reg_init, - .u.b.read = xen_pt_byte_reg_read, - .u.b.write = xen_pt_byte_reg_write, - }, - /* Interrupt Pin reg */ - { - .offset = PCI_INTERRUPT_PIN, - .size = 1, - .init_val = 0x00, - .ro_mask = 0xFF, - .emu_mask = 0xFF, - .init = xen_pt_irqpin_reg_init, - .u.b.read = xen_pt_byte_reg_read, - .u.b.write = xen_pt_byte_reg_write, - }, - /* BAR 0 reg */ - /* mask of BAR need to be decided later, depends on IO/MEM type */ - { - .offset = PCI_BASE_ADDRESS_0, - .size = 4, - .init_val = 0x00000000, - .init = xen_pt_bar_reg_init, - .u.dw.read = xen_pt_bar_reg_read, - .u.dw.write = xen_pt_bar_reg_write, - }, - /* BAR 1 reg */ - { - .offset = PCI_BASE_ADDRESS_1, - .size = 4, - .init_val = 0x00000000, - .init = xen_pt_bar_reg_init, - .u.dw.read = xen_pt_bar_reg_read, - .u.dw.write = xen_pt_bar_reg_write, - }, - /* BAR 2 reg */ - { - .offset = PCI_BASE_ADDRESS_2, - .size = 4, - .init_val = 0x00000000, - .init = xen_pt_bar_reg_init, - .u.dw.read = xen_pt_bar_reg_read, - .u.dw.write = xen_pt_bar_reg_write, - }, - /* BAR 3 reg */ - { - .offset = PCI_BASE_ADDRESS_3, - .size = 4, - .init_val = 0x00000000, - .init = xen_pt_bar_reg_init, - .u.dw.read = xen_pt_bar_reg_read, - .u.dw.write = xen_pt_bar_reg_write, - }, - /* BAR 4 reg */ - { - .offset = PCI_BASE_ADDRESS_4, - .size = 4, - .init_val = 0x00000000, - .init = xen_pt_bar_reg_init, - .u.dw.read = xen_pt_bar_reg_read, - .u.dw.write = xen_pt_bar_reg_write, - }, - /* BAR 5 reg */ - { - .offset = PCI_BASE_ADDRESS_5, - .size = 4, - .init_val = 0x00000000, - .init = xen_pt_bar_reg_init, - .u.dw.read = xen_pt_bar_reg_read, - .u.dw.write = xen_pt_bar_reg_write, - }, - /* Expansion ROM BAR reg */ - { - .offset = PCI_ROM_ADDRESS, - .size = 4, - .init_val = 0x00000000, - .ro_mask = 0x000007FE, - .emu_mask = 0xFFFFF800, - .init = xen_pt_bar_reg_init, - .u.dw.read = xen_pt_long_reg_read, - .u.dw.write = xen_pt_exp_rom_bar_reg_write, - }, - { - .size = 0, - }, -}; - - -/********************************* - * Vital Product Data Capability - */ - -/* Vital Product Data Capability Structure reg static information table */ -static XenPTRegInfo xen_pt_emu_reg_vpd[] = { - { - .offset = PCI_CAP_LIST_NEXT, - .size = 1, - .init_val = 0x00, - .ro_mask = 0xFF, - .emu_mask = 0xFF, - .init = xen_pt_ptr_reg_init, - .u.b.read = xen_pt_byte_reg_read, - .u.b.write = xen_pt_byte_reg_write, - }, - { - .size = 0, - }, -}; - - -/************************************** - * Vendor Specific Capability - */ - -/* Vendor Specific Capability Structure reg static information table */ -static XenPTRegInfo xen_pt_emu_reg_vendor[] = { - { - .offset = PCI_CAP_LIST_NEXT, - .size = 1, - .init_val = 0x00, - .ro_mask = 0xFF, - .emu_mask = 0xFF, - .init = xen_pt_ptr_reg_init, - .u.b.read = xen_pt_byte_reg_read, - .u.b.write = xen_pt_byte_reg_write, - }, - { - .size = 0, - }, -}; - - -/***************************** - * PCI Express Capability - */ - -static inline uint8_t get_capability_version(XenPCIPassthroughState *s, - uint32_t offset) -{ - uint8_t flags = pci_get_byte(s->dev.config + offset + PCI_EXP_FLAGS); - return flags & PCI_EXP_FLAGS_VERS; -} - -static inline uint8_t get_device_type(XenPCIPassthroughState *s, - uint32_t offset) -{ - uint8_t flags = pci_get_byte(s->dev.config + offset + PCI_EXP_FLAGS); - return (flags & PCI_EXP_FLAGS_TYPE) >> 4; -} - -/* initialize Link Control register */ -static int xen_pt_linkctrl_reg_init(XenPCIPassthroughState *s, - XenPTRegInfo *reg, uint32_t real_offset, - uint32_t *data) -{ - uint8_t cap_ver = get_capability_version(s, real_offset - reg->offset); - uint8_t dev_type = get_device_type(s, real_offset - reg->offset); - - /* no need to initialize in case of Root Complex Integrated Endpoint - * with cap_ver 1.x - */ - if ((dev_type == PCI_EXP_TYPE_RC_END) && (cap_ver == 1)) { - *data = XEN_PT_INVALID_REG; - } - - *data = reg->init_val; - return 0; -} -/* initialize Device Control 2 register */ -static int xen_pt_devctrl2_reg_init(XenPCIPassthroughState *s, - XenPTRegInfo *reg, uint32_t real_offset, - uint32_t *data) -{ - uint8_t cap_ver = get_capability_version(s, real_offset - reg->offset); - - /* no need to initialize in case of cap_ver 1.x */ - if (cap_ver == 1) { - *data = XEN_PT_INVALID_REG; - } - - *data = reg->init_val; - return 0; -} -/* initialize Link Control 2 register */ -static int xen_pt_linkctrl2_reg_init(XenPCIPassthroughState *s, - XenPTRegInfo *reg, uint32_t real_offset, - uint32_t *data) -{ - uint8_t cap_ver = get_capability_version(s, real_offset - reg->offset); - uint32_t reg_field = 0; - - /* no need to initialize in case of cap_ver 1.x */ - if (cap_ver == 1) { - reg_field = XEN_PT_INVALID_REG; - } else { - /* set Supported Link Speed */ - uint8_t lnkcap = pci_get_byte(s->dev.config + real_offset - reg->offset - + PCI_EXP_LNKCAP); - reg_field |= PCI_EXP_LNKCAP_SLS & lnkcap; - } - - *data = reg_field; - return 0; -} - -/* PCI Express Capability Structure reg static information table */ -static XenPTRegInfo xen_pt_emu_reg_pcie[] = { - /* Next Pointer reg */ - { - .offset = PCI_CAP_LIST_NEXT, - .size = 1, - .init_val = 0x00, - .ro_mask = 0xFF, - .emu_mask = 0xFF, - .init = xen_pt_ptr_reg_init, - .u.b.read = xen_pt_byte_reg_read, - .u.b.write = xen_pt_byte_reg_write, - }, - /* Device Capabilities reg */ - { - .offset = PCI_EXP_DEVCAP, - .size = 4, - .init_val = 0x00000000, - .ro_mask = 0x1FFCFFFF, - .emu_mask = 0x10000000, - .init = xen_pt_common_reg_init, - .u.dw.read = xen_pt_long_reg_read, - .u.dw.write = xen_pt_long_reg_write, - }, - /* Device Control reg */ - { - .offset = PCI_EXP_DEVCTL, - .size = 2, - .init_val = 0x2810, - .ro_mask = 0x8400, - .emu_mask = 0xFFFF, - .init = xen_pt_common_reg_init, - .u.w.read = xen_pt_word_reg_read, - .u.w.write = xen_pt_word_reg_write, - }, - /* Link Control reg */ - { - .offset = PCI_EXP_LNKCTL, - .size = 2, - .init_val = 0x0000, - .ro_mask = 0xFC34, - .emu_mask = 0xFFFF, - .init = xen_pt_linkctrl_reg_init, - .u.w.read = xen_pt_word_reg_read, - .u.w.write = xen_pt_word_reg_write, - }, - /* Device Control 2 reg */ - { - .offset = 0x28, - .size = 2, - .init_val = 0x0000, - .ro_mask = 0xFFE0, - .emu_mask = 0xFFFF, - .init = xen_pt_devctrl2_reg_init, - .u.w.read = xen_pt_word_reg_read, - .u.w.write = xen_pt_word_reg_write, - }, - /* Link Control 2 reg */ - { - .offset = 0x30, - .size = 2, - .init_val = 0x0000, - .ro_mask = 0xE040, - .emu_mask = 0xFFFF, - .init = xen_pt_linkctrl2_reg_init, - .u.w.read = xen_pt_word_reg_read, - .u.w.write = xen_pt_word_reg_write, - }, - { - .size = 0, - }, -}; - - -/********************************* - * Power Management Capability - */ - -/* read Power Management Control/Status register */ -static int xen_pt_pmcsr_reg_read(XenPCIPassthroughState *s, XenPTReg *cfg_entry, - uint16_t *value, uint16_t valid_mask) -{ - XenPTRegInfo *reg = cfg_entry->reg; - uint16_t valid_emu_mask = reg->emu_mask; - - valid_emu_mask |= PCI_PM_CTRL_STATE_MASK | PCI_PM_CTRL_NO_SOFT_RESET; - - valid_emu_mask = valid_emu_mask & valid_mask; - *value = XEN_PT_MERGE_VALUE(*value, cfg_entry->data, ~valid_emu_mask); - - return 0; -} -/* 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 emu_mask = reg->emu_mask; - uint16_t writable_mask = 0; - uint16_t throughable_mask = 0; - - emu_mask |= PCI_PM_CTRL_STATE_MASK | PCI_PM_CTRL_NO_SOFT_RESET; - - /* modify emulate register */ - writable_mask = emu_mask & ~reg->ro_mask & valid_mask; - cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask); - - /* create value for writing to I/O device register */ - throughable_mask = ~emu_mask & valid_mask; - *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask); - - return 0; -} - -/* Power Management Capability reg static information table */ -static XenPTRegInfo xen_pt_emu_reg_pm[] = { - /* Next Pointer reg */ - { - .offset = PCI_CAP_LIST_NEXT, - .size = 1, - .init_val = 0x00, - .ro_mask = 0xFF, - .emu_mask = 0xFF, - .init = xen_pt_ptr_reg_init, - .u.b.read = xen_pt_byte_reg_read, - .u.b.write = xen_pt_byte_reg_write, - }, - /* Power Management Capabilities reg */ - { - .offset = PCI_CAP_FLAGS, - .size = 2, - .init_val = 0x0000, - .ro_mask = 0xFFFF, - .emu_mask = 0xF9C8, - .init = xen_pt_common_reg_init, - .u.w.read = xen_pt_word_reg_read, - .u.w.write = xen_pt_word_reg_write, - }, - /* PCI Power Management Control/Status reg */ - { - .offset = PCI_PM_CTRL, - .size = 2, - .init_val = 0x0008, - .ro_mask = 0xE1FC, - .emu_mask = 0x8100, - .init = xen_pt_common_reg_init, - .u.w.read = xen_pt_pmcsr_reg_read, - .u.w.write = xen_pt_pmcsr_reg_write, - }, - { - .size = 0, - }, -}; - - -/******************************** - * MSI Capability - */ - -/* Helper */ -static bool xen_pt_msgdata_check_type(uint32_t offset, uint16_t flags) -{ - /* check the offset whether matches the type or not */ - bool is_32 = (offset == PCI_MSI_DATA_32) && !(flags & PCI_MSI_FLAGS_64BIT); - bool is_64 = (offset == PCI_MSI_DATA_64) && (flags & PCI_MSI_FLAGS_64BIT); - return is_32 || is_64; -} - -/* Message Control register */ -static int xen_pt_msgctrl_reg_init(XenPCIPassthroughState *s, - XenPTRegInfo *reg, uint32_t real_offset, - uint32_t *data) -{ - PCIDevice *d = &s->dev; - XenPTMSI *msi = s->msi; - uint16_t reg_field = 0; - - /* use I/O device register's value as initial value */ - reg_field = pci_get_word(d->config + real_offset); - - if (reg_field & PCI_MSI_FLAGS_ENABLE) { - XEN_PT_LOG(&s->dev, "MSI already enabled, disabling it first\n"); - xen_host_pci_set_word(&s->real_device, real_offset, - reg_field & ~PCI_MSI_FLAGS_ENABLE); - } - msi->flags |= reg_field; - msi->ctrl_offset = real_offset; - msi->initialized = false; - msi->mapped = false; - - *data = reg->init_val; - return 0; -} -static int xen_pt_msgctrl_reg_write(XenPCIPassthroughState *s, - XenPTReg *cfg_entry, uint16_t *val, - uint16_t dev_value, uint16_t valid_mask) -{ - XenPTRegInfo *reg = cfg_entry->reg; - XenPTMSI *msi = s->msi; - uint16_t writable_mask = 0; - uint16_t throughable_mask = 0; - uint16_t raw_val; - - /* Currently no support for multi-vector */ - if (*val & PCI_MSI_FLAGS_QSIZE) { - XEN_PT_WARN(&s->dev, "Tries to set more than 1 vector ctrl %x\n", *val); - } - - /* modify emulate register */ - writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask; - cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask); - msi->flags |= cfg_entry->data & ~PCI_MSI_FLAGS_ENABLE; - - /* create value for writing to I/O device register */ - raw_val = *val; - throughable_mask = ~reg->emu_mask & valid_mask; - *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask); - - /* update MSI */ - if (raw_val & PCI_MSI_FLAGS_ENABLE) { - /* setup MSI pirq for the first time */ - if (!msi->initialized) { - /* Init physical one */ - XEN_PT_LOG(&s->dev, "setup MSI\n"); - if (xen_pt_msi_setup(s)) { - /* We do not broadcast the error to the framework code, so - * that MSI errors are contained in MSI emulation code and - * QEMU can go on running. - * Guest MSI would be actually not working. - */ - *val &= ~PCI_MSI_FLAGS_ENABLE; - XEN_PT_WARN(&s->dev, "Can not map MSI.\n"); - return 0; - } - if (xen_pt_msi_update(s)) { - *val &= ~PCI_MSI_FLAGS_ENABLE; - XEN_PT_WARN(&s->dev, "Can not bind MSI\n"); - return 0; - } - msi->initialized = true; - msi->mapped = true; - } - msi->flags |= PCI_MSI_FLAGS_ENABLE; - } else { - msi->flags &= ~PCI_MSI_FLAGS_ENABLE; - } - - /* pass through MSI_ENABLE bit */ - *val &= ~PCI_MSI_FLAGS_ENABLE; - *val |= raw_val & PCI_MSI_FLAGS_ENABLE; - - return 0; -} - -/* initialize Message Upper Address register */ -static int xen_pt_msgaddr64_reg_init(XenPCIPassthroughState *s, - XenPTRegInfo *reg, uint32_t real_offset, - uint32_t *data) -{ - /* no need to initialize in case of 32 bit type */ - if (!(s->msi->flags & PCI_MSI_FLAGS_64BIT)) { - *data = XEN_PT_INVALID_REG; - } else { - *data = reg->init_val; - } - - return 0; -} -/* this function will be called twice (for 32 bit and 64 bit type) */ -/* initialize Message Data register */ -static int xen_pt_msgdata_reg_init(XenPCIPassthroughState *s, - XenPTRegInfo *reg, uint32_t real_offset, - uint32_t *data) -{ - uint32_t flags = s->msi->flags; - uint32_t offset = reg->offset; - - /* check the offset whether matches the type or not */ - if (xen_pt_msgdata_check_type(offset, flags)) { - *data = reg->init_val; - } else { - *data = XEN_PT_INVALID_REG; - } - return 0; -} - -/* write Message Address register */ -static int xen_pt_msgaddr32_reg_write(XenPCIPassthroughState *s, - XenPTReg *cfg_entry, uint32_t *val, - uint32_t dev_value, uint32_t valid_mask) -{ - XenPTRegInfo *reg = cfg_entry->reg; - uint32_t writable_mask = 0; - uint32_t throughable_mask = 0; - uint32_t old_addr = cfg_entry->data; - - /* modify emulate register */ - writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask; - cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask); - s->msi->addr_lo = cfg_entry->data; - - /* create value for writing to I/O device register */ - throughable_mask = ~reg->emu_mask & valid_mask; - *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask); - - /* update MSI */ - if (cfg_entry->data != old_addr) { - if (s->msi->mapped) { - xen_pt_msi_update(s); - } - } - - return 0; -} -/* write Message Upper Address register */ -static int xen_pt_msgaddr64_reg_write(XenPCIPassthroughState *s, - XenPTReg *cfg_entry, uint32_t *val, - uint32_t dev_value, uint32_t valid_mask) -{ - XenPTRegInfo *reg = cfg_entry->reg; - uint32_t writable_mask = 0; - uint32_t throughable_mask = 0; - uint32_t old_addr = cfg_entry->data; - - /* check whether the type is 64 bit or not */ - if (!(s->msi->flags & PCI_MSI_FLAGS_64BIT)) { - XEN_PT_ERR(&s->dev, - "Can't write to the upper address without 64 bit support\n"); - return -1; - } - - /* modify emulate register */ - writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask; - cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask); - /* update the msi_info too */ - s->msi->addr_hi = cfg_entry->data; - - /* create value for writing to I/O device register */ - throughable_mask = ~reg->emu_mask & valid_mask; - *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask); - - /* update MSI */ - if (cfg_entry->data != old_addr) { - if (s->msi->mapped) { - xen_pt_msi_update(s); - } - } - - return 0; -} - - -/* this function will be called twice (for 32 bit and 64 bit type) */ -/* write Message Data register */ -static int xen_pt_msgdata_reg_write(XenPCIPassthroughState *s, - XenPTReg *cfg_entry, uint16_t *val, - uint16_t dev_value, uint16_t valid_mask) -{ - XenPTRegInfo *reg = cfg_entry->reg; - XenPTMSI *msi = s->msi; - uint16_t writable_mask = 0; - uint16_t throughable_mask = 0; - uint16_t old_data = cfg_entry->data; - uint32_t offset = reg->offset; - - /* check the offset whether matches the type or not */ - if (!xen_pt_msgdata_check_type(offset, msi->flags)) { - /* exit I/O emulator */ - XEN_PT_ERR(&s->dev, "the offset does not match the 32/64 bit type!\n"); - return -1; - } - - /* modify emulate register */ - writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask; - cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask); - /* update the msi_info too */ - msi->data = cfg_entry->data; - - /* create value for writing to I/O device register */ - throughable_mask = ~reg->emu_mask & valid_mask; - *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask); - - /* update MSI */ - if (cfg_entry->data != old_data) { - if (msi->mapped) { - xen_pt_msi_update(s); - } - } - - return 0; -} - -/* MSI Capability Structure reg static information table */ -static XenPTRegInfo xen_pt_emu_reg_msi[] = { - /* Next Pointer reg */ - { - .offset = PCI_CAP_LIST_NEXT, - .size = 1, - .init_val = 0x00, - .ro_mask = 0xFF, - .emu_mask = 0xFF, - .init = xen_pt_ptr_reg_init, - .u.b.read = xen_pt_byte_reg_read, - .u.b.write = xen_pt_byte_reg_write, - }, - /* Message Control reg */ - { - .offset = PCI_MSI_FLAGS, - .size = 2, - .init_val = 0x0000, - .ro_mask = 0xFF8E, - .emu_mask = 0x007F, - .init = xen_pt_msgctrl_reg_init, - .u.w.read = xen_pt_word_reg_read, - .u.w.write = xen_pt_msgctrl_reg_write, - }, - /* Message Address reg */ - { - .offset = PCI_MSI_ADDRESS_LO, - .size = 4, - .init_val = 0x00000000, - .ro_mask = 0x00000003, - .emu_mask = 0xFFFFFFFF, - .no_wb = 1, - .init = xen_pt_common_reg_init, - .u.dw.read = xen_pt_long_reg_read, - .u.dw.write = xen_pt_msgaddr32_reg_write, - }, - /* Message Upper Address reg (if PCI_MSI_FLAGS_64BIT set) */ - { - .offset = PCI_MSI_ADDRESS_HI, - .size = 4, - .init_val = 0x00000000, - .ro_mask = 0x00000000, - .emu_mask = 0xFFFFFFFF, - .no_wb = 1, - .init = xen_pt_msgaddr64_reg_init, - .u.dw.read = xen_pt_long_reg_read, - .u.dw.write = xen_pt_msgaddr64_reg_write, - }, - /* Message Data reg (16 bits of data for 32-bit devices) */ - { - .offset = PCI_MSI_DATA_32, - .size = 2, - .init_val = 0x0000, - .ro_mask = 0x0000, - .emu_mask = 0xFFFF, - .no_wb = 1, - .init = xen_pt_msgdata_reg_init, - .u.w.read = xen_pt_word_reg_read, - .u.w.write = xen_pt_msgdata_reg_write, - }, - /* Message Data reg (16 bits of data for 64-bit devices) */ - { - .offset = PCI_MSI_DATA_64, - .size = 2, - .init_val = 0x0000, - .ro_mask = 0x0000, - .emu_mask = 0xFFFF, - .no_wb = 1, - .init = xen_pt_msgdata_reg_init, - .u.w.read = xen_pt_word_reg_read, - .u.w.write = xen_pt_msgdata_reg_write, - }, - { - .size = 0, - }, -}; - - -/************************************** - * MSI-X Capability - */ - -/* Message Control register for MSI-X */ -static int xen_pt_msixctrl_reg_init(XenPCIPassthroughState *s, - XenPTRegInfo *reg, uint32_t real_offset, - uint32_t *data) -{ - PCIDevice *d = &s->dev; - uint16_t reg_field = 0; - - /* use I/O device register's value as initial value */ - reg_field = pci_get_word(d->config + real_offset); - - if (reg_field & PCI_MSIX_FLAGS_ENABLE) { - XEN_PT_LOG(d, "MSIX already enabled, disabling it first\n"); - xen_host_pci_set_word(&s->real_device, real_offset, - reg_field & ~PCI_MSIX_FLAGS_ENABLE); - } - - s->msix->ctrl_offset = real_offset; - - *data = reg->init_val; - return 0; -} -static int xen_pt_msixctrl_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 = 0; - int debug_msix_enabled_old; - - /* modify emulate register */ - writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask; - cfg_entry->data = XEN_PT_MERGE_VALUE(*val, cfg_entry->data, writable_mask); - - /* create value for writing to I/O device register */ - throughable_mask = ~reg->emu_mask & valid_mask; - *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask); - - /* update MSI-X */ - if ((*val & PCI_MSIX_FLAGS_ENABLE) - && !(*val & PCI_MSIX_FLAGS_MASKALL)) { - xen_pt_msix_update(s); - } - - debug_msix_enabled_old = s->msix->enabled; - s->msix->enabled = !!(*val & PCI_MSIX_FLAGS_ENABLE); - if (s->msix->enabled != debug_msix_enabled_old) { - XEN_PT_LOG(&s->dev, "%s MSI-X\n", - s->msix->enabled ? "enable" : "disable"); - } - - return 0; -} - -/* MSI-X Capability Structure reg static information table */ -static XenPTRegInfo xen_pt_emu_reg_msix[] = { - /* Next Pointer reg */ - { - .offset = PCI_CAP_LIST_NEXT, - .size = 1, - .init_val = 0x00, - .ro_mask = 0xFF, - .emu_mask = 0xFF, - .init = xen_pt_ptr_reg_init, - .u.b.read = xen_pt_byte_reg_read, - .u.b.write = xen_pt_byte_reg_write, - }, - /* Message Control reg */ - { - .offset = PCI_MSI_FLAGS, - .size = 2, - .init_val = 0x0000, - .ro_mask = 0x3FFF, - .emu_mask = 0x0000, - .init = xen_pt_msixctrl_reg_init, - .u.w.read = xen_pt_word_reg_read, - .u.w.write = xen_pt_msixctrl_reg_write, - }, - { - .size = 0, - }, -}; - - -/**************************** - * Capabilities - */ - -/* capability structure register group size functions */ - -static int xen_pt_reg_grp_size_init(XenPCIPassthroughState *s, - const XenPTRegGroupInfo *grp_reg, - uint32_t base_offset, uint8_t *size) -{ - *size = grp_reg->grp_size; - return 0; -} -/* get Vendor Specific Capability Structure register group size */ -static int xen_pt_vendor_size_init(XenPCIPassthroughState *s, - const XenPTRegGroupInfo *grp_reg, - uint32_t base_offset, uint8_t *size) -{ - *size = pci_get_byte(s->dev.config + base_offset + 0x02); - return 0; -} -/* get PCI Express Capability Structure register group size */ -static int xen_pt_pcie_size_init(XenPCIPassthroughState *s, - const XenPTRegGroupInfo *grp_reg, - uint32_t base_offset, uint8_t *size) -{ - PCIDevice *d = &s->dev; - uint8_t version = get_capability_version(s, base_offset); - uint8_t type = get_device_type(s, base_offset); - uint8_t pcie_size = 0; - - - /* calculate size depend on capability version and device/port type */ - /* in case of PCI Express Base Specification Rev 1.x */ - if (version == 1) { - /* The PCI Express Capabilities, Device Capabilities, and Device - * Status/Control registers are required for all PCI Express devices. - * The Link Capabilities and Link Status/Control are required for all - * Endpoints that are not Root Complex Integrated Endpoints. Endpoints - * are not required to implement registers other than those listed - * above and terminate the capability structure. - */ - switch (type) { - case PCI_EXP_TYPE_ENDPOINT: - case PCI_EXP_TYPE_LEG_END: - pcie_size = 0x14; - break; - case PCI_EXP_TYPE_RC_END: - /* has no link */ - pcie_size = 0x0C; - break; - /* only EndPoint passthrough is supported */ - case PCI_EXP_TYPE_ROOT_PORT: - case PCI_EXP_TYPE_UPSTREAM: - case PCI_EXP_TYPE_DOWNSTREAM: - case PCI_EXP_TYPE_PCI_BRIDGE: - case PCI_EXP_TYPE_PCIE_BRIDGE: - case PCI_EXP_TYPE_RC_EC: - default: - XEN_PT_ERR(d, "Unsupported device/port type %#x.\n", type); - return -1; - } - } - /* in case of PCI Express Base Specification Rev 2.0 */ - else if (version == 2) { - switch (type) { - case PCI_EXP_TYPE_ENDPOINT: - case PCI_EXP_TYPE_LEG_END: - case PCI_EXP_TYPE_RC_END: - /* For Functions that do not implement the registers, - * these spaces must be hardwired to 0b. - */ - pcie_size = 0x3C; - break; - /* only EndPoint passthrough is supported */ - case PCI_EXP_TYPE_ROOT_PORT: - case PCI_EXP_TYPE_UPSTREAM: - case PCI_EXP_TYPE_DOWNSTREAM: - case PCI_EXP_TYPE_PCI_BRIDGE: - case PCI_EXP_TYPE_PCIE_BRIDGE: - case PCI_EXP_TYPE_RC_EC: - default: - XEN_PT_ERR(d, "Unsupported device/port type %#x.\n", type); - return -1; - } - } else { - XEN_PT_ERR(d, "Unsupported capability version %#x.\n", version); - return -1; - } - - *size = pcie_size; - return 0; -} -/* get MSI Capability Structure register group size */ -static int xen_pt_msi_size_init(XenPCIPassthroughState *s, - const XenPTRegGroupInfo *grp_reg, - uint32_t base_offset, uint8_t *size) -{ - PCIDevice *d = &s->dev; - uint16_t msg_ctrl = 0; - uint8_t msi_size = 0xa; - - msg_ctrl = pci_get_word(d->config + (base_offset + PCI_MSI_FLAGS)); - - /* check if 64-bit address is capable of per-vector masking */ - if (msg_ctrl & PCI_MSI_FLAGS_64BIT) { - msi_size += 4; - } - if (msg_ctrl & PCI_MSI_FLAGS_MASKBIT) { - msi_size += 10; - } - - s->msi = g_new0(XenPTMSI, 1); - s->msi->pirq = XEN_PT_UNASSIGNED_PIRQ; - - *size = msi_size; - return 0; -} -/* get MSI-X Capability Structure register group size */ -static int xen_pt_msix_size_init(XenPCIPassthroughState *s, - const XenPTRegGroupInfo *grp_reg, - uint32_t base_offset, uint8_t *size) -{ - int rc = 0; - - rc = xen_pt_msix_init(s, base_offset); - - if (rc < 0) { - XEN_PT_ERR(&s->dev, "Internal error: Invalid xen_pt_msix_init.\n"); - return rc; - } - - *size = grp_reg->grp_size; - return 0; -} - - -static const XenPTRegGroupInfo xen_pt_emu_reg_grps[] = { - /* Header Type0 reg group */ - { - .grp_id = 0xFF, - .grp_type = XEN_PT_GRP_TYPE_EMU, - .grp_size = 0x40, - .size_init = xen_pt_reg_grp_size_init, - .emu_regs = xen_pt_emu_reg_header0, - }, - /* PCI PowerManagement Capability reg group */ - { - .grp_id = PCI_CAP_ID_PM, - .grp_type = XEN_PT_GRP_TYPE_EMU, - .grp_size = PCI_PM_SIZEOF, - .size_init = xen_pt_reg_grp_size_init, - .emu_regs = xen_pt_emu_reg_pm, - }, - /* AGP Capability Structure reg group */ - { - .grp_id = PCI_CAP_ID_AGP, - .grp_type = XEN_PT_GRP_TYPE_HARDWIRED, - .grp_size = 0x30, - .size_init = xen_pt_reg_grp_size_init, - }, - /* Vital Product Data Capability Structure reg group */ - { - .grp_id = PCI_CAP_ID_VPD, - .grp_type = XEN_PT_GRP_TYPE_EMU, - .grp_size = 0x08, - .size_init = xen_pt_reg_grp_size_init, - .emu_regs = xen_pt_emu_reg_vpd, - }, - /* Slot Identification reg group */ - { - .grp_id = PCI_CAP_ID_SLOTID, - .grp_type = XEN_PT_GRP_TYPE_HARDWIRED, - .grp_size = 0x04, - .size_init = xen_pt_reg_grp_size_init, - }, - /* MSI Capability Structure reg group */ - { - .grp_id = PCI_CAP_ID_MSI, - .grp_type = XEN_PT_GRP_TYPE_EMU, - .grp_size = 0xFF, - .size_init = xen_pt_msi_size_init, - .emu_regs = xen_pt_emu_reg_msi, - }, - /* PCI-X Capabilities List Item reg group */ - { - .grp_id = PCI_CAP_ID_PCIX, - .grp_type = XEN_PT_GRP_TYPE_HARDWIRED, - .grp_size = 0x18, - .size_init = xen_pt_reg_grp_size_init, - }, - /* Vendor Specific Capability Structure reg group */ - { - .grp_id = PCI_CAP_ID_VNDR, - .grp_type = XEN_PT_GRP_TYPE_EMU, - .grp_size = 0xFF, - .size_init = xen_pt_vendor_size_init, - .emu_regs = xen_pt_emu_reg_vendor, - }, - /* SHPC Capability List Item reg group */ - { - .grp_id = PCI_CAP_ID_SHPC, - .grp_type = XEN_PT_GRP_TYPE_HARDWIRED, - .grp_size = 0x08, - .size_init = xen_pt_reg_grp_size_init, - }, - /* Subsystem ID and Subsystem Vendor ID Capability List Item reg group */ - { - .grp_id = PCI_CAP_ID_SSVID, - .grp_type = XEN_PT_GRP_TYPE_HARDWIRED, - .grp_size = 0x08, - .size_init = xen_pt_reg_grp_size_init, - }, - /* AGP 8x Capability Structure reg group */ - { - .grp_id = PCI_CAP_ID_AGP3, - .grp_type = XEN_PT_GRP_TYPE_HARDWIRED, - .grp_size = 0x30, - .size_init = xen_pt_reg_grp_size_init, - }, - /* PCI Express Capability Structure reg group */ - { - .grp_id = PCI_CAP_ID_EXP, - .grp_type = XEN_PT_GRP_TYPE_EMU, - .grp_size = 0xFF, - .size_init = xen_pt_pcie_size_init, - .emu_regs = xen_pt_emu_reg_pcie, - }, - /* MSI-X Capability Structure reg group */ - { - .grp_id = PCI_CAP_ID_MSIX, - .grp_type = XEN_PT_GRP_TYPE_EMU, - .grp_size = 0x0C, - .size_init = xen_pt_msix_size_init, - .emu_regs = xen_pt_emu_reg_msix, - }, - { - .grp_size = 0, - }, -}; - -/* initialize Capabilities Pointer or Next Pointer register */ -static int xen_pt_ptr_reg_init(XenPCIPassthroughState *s, - XenPTRegInfo *reg, uint32_t real_offset, - uint32_t *data) -{ - int i; - uint8_t *config = s->dev.config; - uint32_t reg_field = pci_get_byte(config + real_offset); - uint8_t cap_id = 0; - - /* find capability offset */ - while (reg_field) { - for (i = 0; xen_pt_emu_reg_grps[i].grp_size != 0; i++) { - if (xen_pt_hide_dev_cap(&s->real_device, - xen_pt_emu_reg_grps[i].grp_id)) { - continue; - } - - cap_id = pci_get_byte(config + reg_field + PCI_CAP_LIST_ID); - if (xen_pt_emu_reg_grps[i].grp_id == cap_id) { - if (xen_pt_emu_reg_grps[i].grp_type == XEN_PT_GRP_TYPE_EMU) { - goto out; - } - /* ignore the 0 hardwired capability, find next one */ - break; - } - } - - /* next capability */ - reg_field = pci_get_byte(config + reg_field + PCI_CAP_LIST_NEXT); - } - -out: - *data = reg_field; - return 0; -} - - -/************* - * Main - */ - -static uint8_t find_cap_offset(XenPCIPassthroughState *s, uint8_t cap) -{ - uint8_t id; - unsigned max_cap = PCI_CAP_MAX; - uint8_t pos = PCI_CAPABILITY_LIST; - uint8_t status = 0; - - if (xen_host_pci_get_byte(&s->real_device, PCI_STATUS, &status)) { - return 0; - } - if ((status & PCI_STATUS_CAP_LIST) == 0) { - return 0; - } - - while (max_cap--) { - if (xen_host_pci_get_byte(&s->real_device, pos, &pos)) { - break; - } - if (pos < PCI_CONFIG_HEADER_SIZE) { - break; - } - - pos &= ~3; - if (xen_host_pci_get_byte(&s->real_device, - pos + PCI_CAP_LIST_ID, &id)) { - break; - } - - if (id == 0xff) { - break; - } - if (id == cap) { - return pos; - } - - pos += PCI_CAP_LIST_NEXT; - } - return 0; -} - -static int xen_pt_config_reg_init(XenPCIPassthroughState *s, - XenPTRegGroup *reg_grp, XenPTRegInfo *reg) -{ - XenPTReg *reg_entry; - uint32_t data = 0; - int rc = 0; - - reg_entry = g_new0(XenPTReg, 1); - reg_entry->reg = reg; - - if (reg->init) { - /* initialize emulate register */ - rc = reg->init(s, reg_entry->reg, - reg_grp->base_offset + reg->offset, &data); - if (rc < 0) { - free(reg_entry); - return rc; - } - if (data == XEN_PT_INVALID_REG) { - /* free unused BAR register entry */ - free(reg_entry); - return 0; - } - /* set register value */ - reg_entry->data = data; - } - /* list add register entry */ - QLIST_INSERT_HEAD(®_grp->reg_tbl_list, reg_entry, entries); - - return 0; -} - -int xen_pt_config_init(XenPCIPassthroughState *s) -{ - int i, rc; - - QLIST_INIT(&s->reg_grps); - - for (i = 0; xen_pt_emu_reg_grps[i].grp_size != 0; i++) { - uint32_t reg_grp_offset = 0; - XenPTRegGroup *reg_grp_entry = NULL; - - if (xen_pt_emu_reg_grps[i].grp_id != 0xFF) { - if (xen_pt_hide_dev_cap(&s->real_device, - xen_pt_emu_reg_grps[i].grp_id)) { - continue; - } - - reg_grp_offset = find_cap_offset(s, xen_pt_emu_reg_grps[i].grp_id); - - if (!reg_grp_offset) { - continue; - } - } - - reg_grp_entry = g_new0(XenPTRegGroup, 1); - QLIST_INIT(®_grp_entry->reg_tbl_list); - QLIST_INSERT_HEAD(&s->reg_grps, reg_grp_entry, entries); - - reg_grp_entry->base_offset = reg_grp_offset; - reg_grp_entry->reg_grp = xen_pt_emu_reg_grps + i; - if (xen_pt_emu_reg_grps[i].size_init) { - /* get register group size */ - rc = xen_pt_emu_reg_grps[i].size_init(s, reg_grp_entry->reg_grp, - reg_grp_offset, - ®_grp_entry->size); - if (rc < 0) { - xen_pt_config_delete(s); - return rc; - } - } - - if (xen_pt_emu_reg_grps[i].grp_type == XEN_PT_GRP_TYPE_EMU) { - if (xen_pt_emu_reg_grps[i].emu_regs) { - int j = 0; - XenPTRegInfo *regs = xen_pt_emu_reg_grps[i].emu_regs; - /* initialize capability register */ - for (j = 0; regs->size != 0; j++, regs++) { - /* initialize capability register */ - rc = xen_pt_config_reg_init(s, reg_grp_entry, regs); - if (rc < 0) { - xen_pt_config_delete(s); - return rc; - } - } - } - } - } - - return 0; -} - -/* delete all emulate register */ -void xen_pt_config_delete(XenPCIPassthroughState *s) -{ - struct XenPTRegGroup *reg_group, *next_grp; - struct XenPTReg *reg, *next_reg; - - /* free MSI/MSI-X info table */ - if (s->msix) { - xen_pt_msix_delete(s); - } - if (s->msi) { - g_free(s->msi); - } - - /* free all register group entry */ - QLIST_FOREACH_SAFE(reg_group, &s->reg_grps, entries, next_grp) { - /* free all register entry */ - QLIST_FOREACH_SAFE(reg, ®_group->reg_tbl_list, entries, next_reg) { - QLIST_REMOVE(reg, entries); - g_free(reg); - } - - QLIST_REMOVE(reg_group, entries); - g_free(reg_group); - } -} |