Statistics
| Branch: | Revision:

root / hw / xen_pt.h @ 0d09e41a

History | View | Annotate | Download (8.8 kB)

1
#ifndef XEN_PT_H
2
#define XEN_PT_H
3

    
4
#include "qemu-common.h"
5
#include "hw/xen/xen_common.h"
6
#include "hw/pci/pci.h"
7
#include "hw/xen-host-pci-device.h"
8

    
9
void 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

    
34
typedef struct XenPTRegInfo XenPTRegInfo;
35
typedef struct XenPTReg XenPTReg;
36

    
37
typedef struct XenPCIPassthroughState XenPCIPassthroughState;
38

    
39
/* function type for config reg */
40
typedef int (*xen_pt_conf_reg_init)
41
    (XenPCIPassthroughState *, XenPTRegInfo *, uint32_t real_offset,
42
     uint32_t *data);
43
typedef int (*xen_pt_conf_dword_write)
44
    (XenPCIPassthroughState *, XenPTReg *cfg_entry,
45
     uint32_t *val, uint32_t dev_value, uint32_t valid_mask);
46
typedef int (*xen_pt_conf_word_write)
47
    (XenPCIPassthroughState *, XenPTReg *cfg_entry,
48
     uint16_t *val, uint16_t dev_value, uint16_t valid_mask);
49
typedef int (*xen_pt_conf_byte_write)
50
    (XenPCIPassthroughState *, XenPTReg *cfg_entry,
51
     uint8_t *val, uint8_t dev_value, uint8_t valid_mask);
52
typedef int (*xen_pt_conf_dword_read)
53
    (XenPCIPassthroughState *, XenPTReg *cfg_entry,
54
     uint32_t *val, uint32_t valid_mask);
55
typedef int (*xen_pt_conf_word_read)
56
    (XenPCIPassthroughState *, XenPTReg *cfg_entry,
57
     uint16_t *val, uint16_t valid_mask);
58
typedef 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

    
68
typedef enum {
69
    XEN_PT_GRP_TYPE_HARDWIRED = 0,  /* 0 Hardwired reg group */
70
    XEN_PT_GRP_TYPE_EMU,            /* emul reg group */
71
} XenPTRegisterGroupType;
72

    
73
typedef 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

    
81
typedef 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 */
100
struct 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 */
130
struct XenPTReg {
131
    QLIST_ENTRY(XenPTReg) entries;
132
    XenPTRegInfo *reg;
133
    uint32_t data; /* emulated value */
134
};
135

    
136
typedef struct XenPTRegGroupInfo XenPTRegGroupInfo;
137

    
138
/* emul reg group size initialize method */
139
typedef 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 */
144
struct 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 */
153
typedef 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)
163
typedef 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

    
174
typedef 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;
181
typedef 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

    
194
struct 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

    
215
int xen_pt_config_init(XenPCIPassthroughState *s);
216
void xen_pt_config_delete(XenPCIPassthroughState *s);
217
XenPTRegGroup *xen_pt_find_reg_grp(XenPCIPassthroughState *s, uint32_t address);
218
XenPTReg *xen_pt_find_reg(XenPTRegGroup *reg_grp, uint32_t address);
219
int xen_pt_bar_offset_to_index(uint32_t offset);
220

    
221
static 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

    
261
static 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

    
268
static 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 */
285
int xen_pt_msi_set_enable(XenPCIPassthroughState *s, bool en);
286
int xen_pt_msi_setup(XenPCIPassthroughState *s);
287
int xen_pt_msi_update(XenPCIPassthroughState *d);
288
void xen_pt_msi_disable(XenPCIPassthroughState *s);
289

    
290
int xen_pt_msix_init(XenPCIPassthroughState *s, uint32_t base);
291
void xen_pt_msix_delete(XenPCIPassthroughState *s);
292
int xen_pt_msix_update(XenPCIPassthroughState *s);
293
int xen_pt_msix_update_remap(XenPCIPassthroughState *s, int bar_index);
294
void xen_pt_msix_disable(XenPCIPassthroughState *s);
295

    
296
static 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 */