Statistics
| Branch: | Revision:

root / hw / xen_pt.h @ 0b944384

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 "xen_common.h"
6
#include "pci.h"
7
#include "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 infomation */
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 infomation */
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
};
213

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

    
220
static inline pcibus_t xen_pt_get_emul_size(XenPTBarFlag flag, pcibus_t r_size)
221
{
222
    /* align resource size (memory type only) */
223
    if (flag == XEN_PT_BAR_FLAG_MEM) {
224
        return (r_size + XC_PAGE_SIZE - 1) & XC_PAGE_MASK;
225
    } else {
226
        return r_size;
227
    }
228
}
229

    
230
/* INTx */
231
/* The PCI Local Bus Specification, Rev. 3.0,
232
 * Section 6.2.4 Miscellaneous Registers, pp 223
233
 * outlines 5 valid values for the interrupt pin (intx).
234
 *  0: For devices (or device functions) that don't use an interrupt in
235
 *  1: INTA#
236
 *  2: INTB#
237
 *  3: INTC#
238
 *  4: INTD#
239
 *
240
 * Xen uses the following 4 values for intx
241
 *  0: INTA#
242
 *  1: INTB#
243
 *  2: INTC#
244
 *  3: INTD#
245
 *
246
 * Observing that these list of values are not the same, xen_pt_pci_read_intx()
247
 * uses the following mapping from hw to xen values.
248
 * This seems to reflect the current usage within Xen.
249
 *
250
 * PCI hardware    | Xen | Notes
251
 * ----------------+-----+----------------------------------------------------
252
 * 0               | 0   | No interrupt
253
 * 1               | 0   | INTA#
254
 * 2               | 1   | INTB#
255
 * 3               | 2   | INTC#
256
 * 4               | 3   | INTD#
257
 * any other value | 0   | This should never happen, log error message
258
 */
259

    
260
static inline uint8_t xen_pt_pci_read_intx(XenPCIPassthroughState *s)
261
{
262
    uint8_t v = 0;
263
    xen_host_pci_get_byte(&s->real_device, PCI_INTERRUPT_PIN, &v);
264
    return v;
265
}
266

    
267
static inline uint8_t xen_pt_pci_intx(XenPCIPassthroughState *s)
268
{
269
    uint8_t r_val = xen_pt_pci_read_intx(s);
270

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

    
280
    return r_val;
281
}
282

    
283
/* MSI/MSI-X */
284
int xen_pt_msi_set_enable(XenPCIPassthroughState *s, bool en);
285
int xen_pt_msi_setup(XenPCIPassthroughState *s);
286
int xen_pt_msi_update(XenPCIPassthroughState *d);
287
void xen_pt_msi_disable(XenPCIPassthroughState *s);
288

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

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

    
300

    
301
#endif /* !XEN_PT_H */