qemu/hw/xen_pt.h
<<
>>
Prefs
   1#ifndef XEN_PT_H
   2#define XEN_PT_H
   3
   4#include "qemu-common.h"
   5#include "xen_common.h"
   6#include "pci.h"
   7#include "xen-host-pci-device.h"
   8
   9void xen_pt_log(const PCIDevice *d, const char *f, ...) GCC_FMT_ATTR(2, 3);
  10
  11#define XEN_PT_ERR(d, _f, _a...) xen_pt_log(d, "%s: Error: "_f, __func__, ##_a)
  12
  13#ifdef XEN_PT_LOGGING_ENABLED
  14#  define XEN_PT_LOG(d, _f, _a...)  xen_pt_log(d, "%s: " _f, __func__, ##_a)
  15#  define XEN_PT_WARN(d, _f, _a...) \
  16    xen_pt_log(d, "%s: Warning: "_f, __func__, ##_a)
  17#else
  18#  define XEN_PT_LOG(d, _f, _a...)
  19#  define XEN_PT_WARN(d, _f, _a...)
  20#endif
  21
  22#ifdef XEN_PT_DEBUG_PCI_CONFIG_ACCESS
  23#  define XEN_PT_LOG_CONFIG(d, addr, val, len) \
  24    xen_pt_log(d, "%s: address=0x%04x val=0x%08x len=%d\n", \
  25               __func__, addr, val, len)
  26#else
  27#  define XEN_PT_LOG_CONFIG(d, addr, val, len)
  28#endif
  29
  30
  31/* Helper */
  32#define XEN_PFN(x) ((x) >> XC_PAGE_SHIFT)
  33
  34typedef struct XenPTRegInfo XenPTRegInfo;
  35typedef struct XenPTReg XenPTReg;
  36
  37typedef struct XenPCIPassthroughState XenPCIPassthroughState;
  38
  39/* function type for config reg */
  40typedef int (*xen_pt_conf_reg_init)
  41    (XenPCIPassthroughState *, XenPTRegInfo *, uint32_t real_offset,
  42     uint32_t *data);
  43typedef int (*xen_pt_conf_dword_write)
  44    (XenPCIPassthroughState *, XenPTReg *cfg_entry,
  45     uint32_t *val, uint32_t dev_value, uint32_t valid_mask);
  46typedef int (*xen_pt_conf_word_write)
  47    (XenPCIPassthroughState *, XenPTReg *cfg_entry,
  48     uint16_t *val, uint16_t dev_value, uint16_t valid_mask);
  49typedef int (*xen_pt_conf_byte_write)
  50    (XenPCIPassthroughState *, XenPTReg *cfg_entry,
  51     uint8_t *val, uint8_t dev_value, uint8_t valid_mask);
  52typedef int (*xen_pt_conf_dword_read)
  53    (XenPCIPassthroughState *, XenPTReg *cfg_entry,
  54     uint32_t *val, uint32_t valid_mask);
  55typedef int (*xen_pt_conf_word_read)
  56    (XenPCIPassthroughState *, XenPTReg *cfg_entry,
  57     uint16_t *val, uint16_t valid_mask);
  58typedef int (*xen_pt_conf_byte_read)
  59    (XenPCIPassthroughState *, XenPTReg *cfg_entry,
  60     uint8_t *val, uint8_t valid_mask);
  61
  62#define XEN_PT_BAR_ALLF 0xFFFFFFFF
  63#define XEN_PT_BAR_UNMAPPED (-1)
  64
  65#define PCI_CAP_MAX 48
  66
  67
  68typedef enum {
  69    XEN_PT_GRP_TYPE_HARDWIRED = 0,  /* 0 Hardwired reg group */
  70    XEN_PT_GRP_TYPE_EMU,            /* emul reg group */
  71} XenPTRegisterGroupType;
  72
  73typedef enum {
  74    XEN_PT_BAR_FLAG_MEM = 0,        /* Memory type BAR */
  75    XEN_PT_BAR_FLAG_IO,             /* I/O type BAR */
  76    XEN_PT_BAR_FLAG_UPPER,          /* upper 64bit BAR */
  77    XEN_PT_BAR_FLAG_UNUSED,         /* unused BAR */
  78} XenPTBarFlag;
  79
  80
  81typedef struct XenPTRegion {
  82    /* BAR flag */
  83    XenPTBarFlag bar_flag;
  84    /* Translation of the emulated address */
  85    union {
  86        uint64_t maddr;
  87        uint64_t pio_base;
  88        uint64_t u;
  89    } access;
  90} XenPTRegion;
  91
  92/* XenPTRegInfo declaration
  93 * - only for emulated register (either a part or whole bit).
  94 * - for passthrough register that need special behavior (like interacting with
  95 *   other component), set emu_mask to all 0 and specify r/w func properly.
  96 * - do NOT use ALL F for init_val, otherwise the tbl will not be registered.
  97 */
  98
  99/* emulated register information */
 100struct XenPTRegInfo {
 101    uint32_t offset;
 102    uint32_t size;
 103    uint32_t init_val;
 104    /* reg read only field mask (ON:RO/ROS, OFF:other) */
 105    uint32_t ro_mask;
 106    /* reg emulate field mask (ON:emu, OFF:passthrough) */
 107    uint32_t emu_mask;
 108    /* no write back allowed */
 109    uint32_t no_wb;
 110    xen_pt_conf_reg_init init;
 111    /* read/write function pointer
 112     * for double_word/word/byte size */
 113    union {
 114        struct {
 115            xen_pt_conf_dword_write write;
 116            xen_pt_conf_dword_read read;
 117        } dw;
 118        struct {
 119            xen_pt_conf_word_write write;
 120            xen_pt_conf_word_read read;
 121        } w;
 122        struct {
 123            xen_pt_conf_byte_write write;
 124            xen_pt_conf_byte_read read;
 125        } b;
 126    } u;
 127};
 128
 129/* emulated register management */
 130struct XenPTReg {
 131    QLIST_ENTRY(XenPTReg) entries;
 132    XenPTRegInfo *reg;
 133    uint32_t data; /* emulated value */
 134};
 135
 136typedef struct XenPTRegGroupInfo XenPTRegGroupInfo;
 137
 138/* emul reg group size initialize method */
 139typedef int (*xen_pt_reg_size_init_fn)
 140    (XenPCIPassthroughState *, const XenPTRegGroupInfo *,
 141     uint32_t base_offset, uint8_t *size);
 142
 143/* emulated register group information */
 144struct XenPTRegGroupInfo {
 145    uint8_t grp_id;
 146    XenPTRegisterGroupType grp_type;
 147    uint8_t grp_size;
 148    xen_pt_reg_size_init_fn size_init;
 149    XenPTRegInfo *emu_regs;
 150};
 151
 152/* emul register group management table */
 153typedef struct XenPTRegGroup {
 154    QLIST_ENTRY(XenPTRegGroup) entries;
 155    const XenPTRegGroupInfo *reg_grp;
 156    uint32_t base_offset;
 157    uint8_t size;
 158    QLIST_HEAD(, XenPTReg) reg_tbl_list;
 159} XenPTRegGroup;
 160
 161
 162#define XEN_PT_UNASSIGNED_PIRQ (-1)
 163typedef struct XenPTMSI {
 164    uint16_t flags;
 165    uint32_t addr_lo;  /* guest message address */
 166    uint32_t addr_hi;  /* guest message upper address */
 167    uint16_t data;     /* guest message data */
 168    uint32_t ctrl_offset; /* saved control offset */
 169    int pirq;          /* guest pirq corresponding */
 170    bool initialized;  /* when guest MSI is initialized */
 171    bool mapped;       /* when pirq is mapped */
 172} XenPTMSI;
 173
 174typedef struct XenPTMSIXEntry {
 175    int pirq;
 176    uint64_t addr;
 177    uint32_t data;
 178    uint32_t vector_ctrl;
 179    bool updated; /* indicate whether MSI ADDR or DATA is updated */
 180} XenPTMSIXEntry;
 181typedef struct XenPTMSIX {
 182    uint32_t ctrl_offset;
 183    bool enabled;
 184    int total_entries;
 185    int bar_index;
 186    uint64_t table_base;
 187    uint32_t table_offset_adjust; /* page align mmap */
 188    uint64_t mmio_base_addr;
 189    MemoryRegion mmio;
 190    void *phys_iomem_base;
 191    XenPTMSIXEntry msix_entry[0];
 192} XenPTMSIX;
 193
 194struct XenPCIPassthroughState {
 195    PCIDevice dev;
 196
 197    PCIHostDeviceAddress hostaddr;
 198    bool is_virtfn;
 199    XenHostPCIDevice real_device;
 200    XenPTRegion bases[PCI_NUM_REGIONS]; /* Access regions */
 201    QLIST_HEAD(, XenPTRegGroup) reg_grps;
 202
 203    uint32_t machine_irq;
 204
 205    XenPTMSI *msi;
 206    XenPTMSIX *msix;
 207
 208    MemoryRegion bar[PCI_NUM_REGIONS - 1];
 209    MemoryRegion rom;
 210
 211    MemoryListener memory_listener;
 212    MemoryListener io_listener;
 213};
 214
 215int xen_pt_config_init(XenPCIPassthroughState *s);
 216void xen_pt_config_delete(XenPCIPassthroughState *s);
 217XenPTRegGroup *xen_pt_find_reg_grp(XenPCIPassthroughState *s, uint32_t address);
 218XenPTReg *xen_pt_find_reg(XenPTRegGroup *reg_grp, uint32_t address);
 219int xen_pt_bar_offset_to_index(uint32_t offset);
 220
 221static inline pcibus_t xen_pt_get_emul_size(XenPTBarFlag flag, pcibus_t r_size)
 222{
 223    /* align resource size (memory type only) */
 224    if (flag == XEN_PT_BAR_FLAG_MEM) {
 225        return (r_size + XC_PAGE_SIZE - 1) & XC_PAGE_MASK;
 226    } else {
 227        return r_size;
 228    }
 229}
 230
 231/* INTx */
 232/* The PCI Local Bus Specification, Rev. 3.0,
 233 * Section 6.2.4 Miscellaneous Registers, pp 223
 234 * outlines 5 valid values for the interrupt pin (intx).
 235 *  0: For devices (or device functions) that don't use an interrupt in
 236 *  1: INTA#
 237 *  2: INTB#
 238 *  3: INTC#
 239 *  4: INTD#
 240 *
 241 * Xen uses the following 4 values for intx
 242 *  0: INTA#
 243 *  1: INTB#
 244 *  2: INTC#
 245 *  3: INTD#
 246 *
 247 * Observing that these list of values are not the same, xen_pt_pci_read_intx()
 248 * uses the following mapping from hw to xen values.
 249 * This seems to reflect the current usage within Xen.
 250 *
 251 * PCI hardware    | Xen | Notes
 252 * ----------------+-----+----------------------------------------------------
 253 * 0               | 0   | No interrupt
 254 * 1               | 0   | INTA#
 255 * 2               | 1   | INTB#
 256 * 3               | 2   | INTC#
 257 * 4               | 3   | INTD#
 258 * any other value | 0   | This should never happen, log error message
 259 */
 260
 261static inline uint8_t xen_pt_pci_read_intx(XenPCIPassthroughState *s)
 262{
 263    uint8_t v = 0;
 264    xen_host_pci_get_byte(&s->real_device, PCI_INTERRUPT_PIN, &v);
 265    return v;
 266}
 267
 268static inline uint8_t xen_pt_pci_intx(XenPCIPassthroughState *s)
 269{
 270    uint8_t r_val = xen_pt_pci_read_intx(s);
 271
 272    XEN_PT_LOG(&s->dev, "intx=%i\n", r_val);
 273    if (r_val < 1 || r_val > 4) {
 274        XEN_PT_LOG(&s->dev, "Interrupt pin read from hardware is out of range:"
 275                   " value=%i, acceptable range is 1 - 4\n", r_val);
 276        r_val = 0;
 277    } else {
 278        r_val -= 1;
 279    }
 280
 281    return r_val;
 282}
 283
 284/* MSI/MSI-X */
 285int xen_pt_msi_set_enable(XenPCIPassthroughState *s, bool en);
 286int xen_pt_msi_setup(XenPCIPassthroughState *s);
 287int xen_pt_msi_update(XenPCIPassthroughState *d);
 288void xen_pt_msi_disable(XenPCIPassthroughState *s);
 289
 290int xen_pt_msix_init(XenPCIPassthroughState *s, uint32_t base);
 291void xen_pt_msix_delete(XenPCIPassthroughState *s);
 292int xen_pt_msix_update(XenPCIPassthroughState *s);
 293int xen_pt_msix_update_remap(XenPCIPassthroughState *s, int bar_index);
 294void xen_pt_msix_disable(XenPCIPassthroughState *s);
 295
 296static inline bool xen_pt_has_msix_mapping(XenPCIPassthroughState *s, int bar)
 297{
 298    return s->msix && s->msix->bar_index == bar;
 299}
 300
 301
 302#endif /* !XEN_PT_H */
 303