xen_pt.h 9.5 KB
Newer Older
1 2 3 4
#ifndef XEN_PT_H
#define XEN_PT_H

#include "qemu-common.h"
P
Paolo Bonzini 已提交
5
#include "hw/xen/xen_common.h"
6
#include "hw/pci/pci.h"
7
#include "xen-host-pci-device.h"
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33

void xen_pt_log(const PCIDevice *d, const char *f, ...) GCC_FMT_ATTR(2, 3);

#define XEN_PT_ERR(d, _f, _a...) xen_pt_log(d, "%s: Error: "_f, __func__, ##_a)

#ifdef XEN_PT_LOGGING_ENABLED
#  define XEN_PT_LOG(d, _f, _a...)  xen_pt_log(d, "%s: " _f, __func__, ##_a)
#  define XEN_PT_WARN(d, _f, _a...) \
    xen_pt_log(d, "%s: Warning: "_f, __func__, ##_a)
#else
#  define XEN_PT_LOG(d, _f, _a...)
#  define XEN_PT_WARN(d, _f, _a...)
#endif

#ifdef XEN_PT_DEBUG_PCI_CONFIG_ACCESS
#  define XEN_PT_LOG_CONFIG(d, addr, val, len) \
    xen_pt_log(d, "%s: address=0x%04x val=0x%08x len=%d\n", \
               __func__, addr, val, len)
#else
#  define XEN_PT_LOG_CONFIG(d, addr, val, len)
#endif


/* Helper */
#define XEN_PFN(x) ((x) >> XC_PAGE_SHIFT)

34
typedef const struct XenPTRegInfo XenPTRegInfo;
35 36 37 38
typedef struct XenPTReg XenPTReg;

typedef struct XenPCIPassthroughState XenPCIPassthroughState;

G
Gonglei 已提交
39 40 41 42
#define TYPE_XEN_PT_DEVICE "xen-pci-passthrough"
#define XEN_PT_DEVICE(obj) \
    OBJECT_CHECK(XenPCIPassthroughState, (obj), TYPE_XEN_PT_DEVICE)

43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
/* function type for config reg */
typedef int (*xen_pt_conf_reg_init)
    (XenPCIPassthroughState *, XenPTRegInfo *, uint32_t real_offset,
     uint32_t *data);
typedef int (*xen_pt_conf_dword_write)
    (XenPCIPassthroughState *, XenPTReg *cfg_entry,
     uint32_t *val, uint32_t dev_value, uint32_t valid_mask);
typedef int (*xen_pt_conf_word_write)
    (XenPCIPassthroughState *, XenPTReg *cfg_entry,
     uint16_t *val, uint16_t dev_value, uint16_t valid_mask);
typedef int (*xen_pt_conf_byte_write)
    (XenPCIPassthroughState *, XenPTReg *cfg_entry,
     uint8_t *val, uint8_t dev_value, uint8_t valid_mask);
typedef int (*xen_pt_conf_dword_read)
    (XenPCIPassthroughState *, XenPTReg *cfg_entry,
     uint32_t *val, uint32_t valid_mask);
typedef int (*xen_pt_conf_word_read)
    (XenPCIPassthroughState *, XenPTReg *cfg_entry,
     uint16_t *val, uint16_t valid_mask);
typedef int (*xen_pt_conf_byte_read)
    (XenPCIPassthroughState *, XenPTReg *cfg_entry,
     uint8_t *val, uint8_t valid_mask);

#define XEN_PT_BAR_ALLF 0xFFFFFFFF
#define XEN_PT_BAR_UNMAPPED (-1)

69 70
#define PCI_CAP_MAX 48

71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102

typedef enum {
    XEN_PT_GRP_TYPE_HARDWIRED = 0,  /* 0 Hardwired reg group */
    XEN_PT_GRP_TYPE_EMU,            /* emul reg group */
} XenPTRegisterGroupType;

typedef enum {
    XEN_PT_BAR_FLAG_MEM = 0,        /* Memory type BAR */
    XEN_PT_BAR_FLAG_IO,             /* I/O type BAR */
    XEN_PT_BAR_FLAG_UPPER,          /* upper 64bit BAR */
    XEN_PT_BAR_FLAG_UNUSED,         /* unused BAR */
} XenPTBarFlag;


typedef struct XenPTRegion {
    /* BAR flag */
    XenPTBarFlag bar_flag;
    /* Translation of the emulated address */
    union {
        uint64_t maddr;
        uint64_t pio_base;
        uint64_t u;
    } access;
} XenPTRegion;

/* XenPTRegInfo declaration
 * - only for emulated register (either a part or whole bit).
 * - for passthrough register that need special behavior (like interacting with
 *   other component), set emu_mask to all 0 and specify r/w func properly.
 * - do NOT use ALL F for init_val, otherwise the tbl will not be registered.
 */

103
/* emulated register information */
104 105 106 107
struct XenPTRegInfo {
    uint32_t offset;
    uint32_t size;
    uint32_t init_val;
108 109
    /* reg reserved field mask (ON:reserved, OFF:defined) */
    uint32_t res_mask;
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
    /* reg read only field mask (ON:RO/ROS, OFF:other) */
    uint32_t ro_mask;
    /* reg emulate field mask (ON:emu, OFF:passthrough) */
    uint32_t emu_mask;
    xen_pt_conf_reg_init init;
    /* read/write function pointer
     * for double_word/word/byte size */
    union {
        struct {
            xen_pt_conf_dword_write write;
            xen_pt_conf_dword_read read;
        } dw;
        struct {
            xen_pt_conf_word_write write;
            xen_pt_conf_word_read read;
        } w;
        struct {
            xen_pt_conf_byte_write write;
            xen_pt_conf_byte_read read;
        } b;
    } u;
};

/* emulated register management */
struct XenPTReg {
    QLIST_ENTRY(XenPTReg) entries;
    XenPTRegInfo *reg;
    uint32_t data; /* emulated value */
};

140
typedef const struct XenPTRegGroupInfo XenPTRegGroupInfo;
141 142 143

/* emul reg group size initialize method */
typedef int (*xen_pt_reg_size_init_fn)
144
    (XenPCIPassthroughState *, XenPTRegGroupInfo *,
145 146
     uint32_t base_offset, uint8_t *size);

147
/* emulated register group information */
148 149 150 151 152 153 154 155 156 157 158
struct XenPTRegGroupInfo {
    uint8_t grp_id;
    XenPTRegisterGroupType grp_type;
    uint8_t grp_size;
    xen_pt_reg_size_init_fn size_init;
    XenPTRegInfo *emu_regs;
};

/* emul register group management table */
typedef struct XenPTRegGroup {
    QLIST_ENTRY(XenPTRegGroup) entries;
159
    XenPTRegGroupInfo *reg_grp;
160 161 162 163 164 165 166
    uint32_t base_offset;
    uint8_t size;
    QLIST_HEAD(, XenPTReg) reg_tbl_list;
} XenPTRegGroup;


#define XEN_PT_UNASSIGNED_PIRQ (-1)
167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
typedef struct XenPTMSI {
    uint16_t flags;
    uint32_t addr_lo;  /* guest message address */
    uint32_t addr_hi;  /* guest message upper address */
    uint16_t data;     /* guest message data */
    uint32_t ctrl_offset; /* saved control offset */
    int pirq;          /* guest pirq corresponding */
    bool initialized;  /* when guest MSI is initialized */
    bool mapped;       /* when pirq is mapped */
} XenPTMSI;

typedef struct XenPTMSIXEntry {
    int pirq;
    uint64_t addr;
    uint32_t data;
    uint32_t vector_ctrl;
    bool updated; /* indicate whether MSI ADDR or DATA is updated */
J
Jan Beulich 已提交
184
    bool warned;  /* avoid issuing (bogus) warning more than once */
185 186 187 188 189 190 191 192 193 194 195 196 197
} XenPTMSIXEntry;
typedef struct XenPTMSIX {
    uint32_t ctrl_offset;
    bool enabled;
    int total_entries;
    int bar_index;
    uint64_t table_base;
    uint32_t table_offset_adjust; /* page align mmap */
    uint64_t mmio_base_addr;
    MemoryRegion mmio;
    void *phys_iomem_base;
    XenPTMSIXEntry msix_entry[0];
} XenPTMSIX;
198 199 200 201 202 203

struct XenPCIPassthroughState {
    PCIDevice dev;

    PCIHostDeviceAddress hostaddr;
    bool is_virtfn;
204 205
    bool permissive;
    bool permissive_warned;
206 207 208 209 210 211
    XenHostPCIDevice real_device;
    XenPTRegion bases[PCI_NUM_REGIONS]; /* Access regions */
    QLIST_HEAD(, XenPTRegGroup) reg_grps;

    uint32_t machine_irq;

212 213 214
    XenPTMSI *msi;
    XenPTMSIX *msix;

215 216 217 218
    MemoryRegion bar[PCI_NUM_REGIONS - 1];
    MemoryRegion rom;

    MemoryListener memory_listener;
219
    MemoryListener io_listener;
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290
};

int xen_pt_config_init(XenPCIPassthroughState *s);
void xen_pt_config_delete(XenPCIPassthroughState *s);
XenPTRegGroup *xen_pt_find_reg_grp(XenPCIPassthroughState *s, uint32_t address);
XenPTReg *xen_pt_find_reg(XenPTRegGroup *reg_grp, uint32_t address);
int xen_pt_bar_offset_to_index(uint32_t offset);

static inline pcibus_t xen_pt_get_emul_size(XenPTBarFlag flag, pcibus_t r_size)
{
    /* align resource size (memory type only) */
    if (flag == XEN_PT_BAR_FLAG_MEM) {
        return (r_size + XC_PAGE_SIZE - 1) & XC_PAGE_MASK;
    } else {
        return r_size;
    }
}

/* INTx */
/* The PCI Local Bus Specification, Rev. 3.0,
 * Section 6.2.4 Miscellaneous Registers, pp 223
 * outlines 5 valid values for the interrupt pin (intx).
 *  0: For devices (or device functions) that don't use an interrupt in
 *  1: INTA#
 *  2: INTB#
 *  3: INTC#
 *  4: INTD#
 *
 * Xen uses the following 4 values for intx
 *  0: INTA#
 *  1: INTB#
 *  2: INTC#
 *  3: INTD#
 *
 * Observing that these list of values are not the same, xen_pt_pci_read_intx()
 * uses the following mapping from hw to xen values.
 * This seems to reflect the current usage within Xen.
 *
 * PCI hardware    | Xen | Notes
 * ----------------+-----+----------------------------------------------------
 * 0               | 0   | No interrupt
 * 1               | 0   | INTA#
 * 2               | 1   | INTB#
 * 3               | 2   | INTC#
 * 4               | 3   | INTD#
 * any other value | 0   | This should never happen, log error message
 */

static inline uint8_t xen_pt_pci_read_intx(XenPCIPassthroughState *s)
{
    uint8_t v = 0;
    xen_host_pci_get_byte(&s->real_device, PCI_INTERRUPT_PIN, &v);
    return v;
}

static inline uint8_t xen_pt_pci_intx(XenPCIPassthroughState *s)
{
    uint8_t r_val = xen_pt_pci_read_intx(s);

    XEN_PT_LOG(&s->dev, "intx=%i\n", r_val);
    if (r_val < 1 || r_val > 4) {
        XEN_PT_LOG(&s->dev, "Interrupt pin read from hardware is out of range:"
                   " value=%i, acceptable range is 1 - 4\n", r_val);
        r_val = 0;
    } else {
        r_val -= 1;
    }

    return r_val;
}

291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307
/* MSI/MSI-X */
int xen_pt_msi_set_enable(XenPCIPassthroughState *s, bool en);
int xen_pt_msi_setup(XenPCIPassthroughState *s);
int xen_pt_msi_update(XenPCIPassthroughState *d);
void xen_pt_msi_disable(XenPCIPassthroughState *s);

int xen_pt_msix_init(XenPCIPassthroughState *s, uint32_t base);
void xen_pt_msix_delete(XenPCIPassthroughState *s);
int xen_pt_msix_update(XenPCIPassthroughState *s);
int xen_pt_msix_update_remap(XenPCIPassthroughState *s, int bar_index);
void xen_pt_msix_disable(XenPCIPassthroughState *s);

static inline bool xen_pt_has_msix_mapping(XenPCIPassthroughState *s, int bar)
{
    return s->msix && s->msix->bar_index == bar;
}

308 309 310 311 312 313 314 315 316
extern bool has_igd_gfx_passthru;
static inline bool is_igd_vga_passthrough(XenHostPCIDevice *dev)
{
    return (has_igd_gfx_passthru
            && ((dev->class_code >> 0x8) == PCI_CLASS_DISPLAY_VGA));
}
int xen_pt_register_vga_regions(XenHostPCIDevice *dev);
int xen_pt_unregister_vga_regions(XenHostPCIDevice *dev);
int xen_pt_setup_vga(XenPCIPassthroughState *s, XenHostPCIDevice *dev);
317
#endif /* !XEN_PT_H */