aboutsummaryrefslogtreecommitdiff
path: root/lib/pci.h
blob: 5ad0722813bc627248ad13a91a3dcde826bcaac7 (plain)
1
2
3
4
5
6
7
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
34
35
36
37
38
39
40
41
42
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
69
70
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
103
104
105
106
107
108
109
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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
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
291
292
293
294
295
296
297
298
/*
 * Copyright (c) 2019 Nutanix Inc. All rights reserved.
 *
 * Authors: Thanos Makatos <thanos@nutanix.com>
 *          Swapnil Ingle <swapnil.ingle@nutanix.com>
 *          Felipe Franciosi <felipe@nutanix.com>
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *      * Redistributions of source code must retain the above copyright
 *        notice, this list of conditions and the following disclaimer.
 *      * Redistributions in binary form must reproduce the above copyright
 *        notice, this list of conditions and the following disclaimer in the
 *        documentation and/or other materials provided with the distribution.
 *      * Neither the name of Nutanix nor the names of its contributors may be
 *        used to endorse or promote products derived from this software without
 *        specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 *  ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
 *  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 *  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 *  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 *  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
 *  DAMAGE.
 *
 */

#ifndef LIBMUSER_PCI_H
#define LIBMUSER_PCI_H

#include <stdint.h>
#include <stdbool.h>

#include <linux/pci_regs.h>

struct lm_ctx;
typedef struct lm_ctx lm_ctx_t;

typedef uint64_t dma_addr_t;

typedef struct {
    int region;
    int length;
    uint64_t offset;
} dma_scattergather_t;

typedef struct lm_ctx lm_ctx_t;
typedef struct lm_reg_info lm_reg_info_t;
typedef struct lm_pci_config_space lm_pci_config_space_t;

typedef enum {
    LM_ERR,
    LM_INF,
    LM_DBG
} lm_log_lvl_t;

/*
 * These are already defined in include/uapi/linux/pci_regs.h, however that
 * file doesn't seem to installed.
 */
#define PCI_CFG_SPACE_SIZE      256
#define PCI_CFG_SPACE_EXP_SIZE  4096

enum {
    LM_DEV_BAR0_REG_IDX,
    LM_DEV_BAR1_REG_IDX,
    LM_DEV_BAR2_REG_IDX,
    LM_DEV_BAR3_REG_IDX,
    LM_DEV_BAR4_REG_IDX,
    LM_DEV_BAR5_REG_IDX,
    LM_DEV_ROM_REG_IDX,
    LM_DEV_CFG_REG_IDX,
    LM_DEV_VGA_REG_IDX,
    LM_DEV_NUM_REGS = 9
};

/*
 * TODO lots of the sizes of each member are defined in pci_regs.h, use those
 * instead?
 */

typedef union {
    uint32_t raw;
    struct {
        uint16_t vid;
        uint16_t sid;
    } __attribute__ ((packed));
} __attribute__ ((packed)) lm_pci_hdr_ss_t;
_Static_assert(sizeof(lm_pci_hdr_ss_t) == 0x4, "bad SS size");

typedef union {
    uint8_t raw;
} __attribute__ ((packed)) lm_pci_hdr_bist_t;
_Static_assert(sizeof(lm_pci_hdr_bist_t) == 0x1, "bad BIST size");

typedef union {
    uint32_t raw;
    union {
        struct {
            unsigned int region_type:1;
            unsigned int locatable:2;
            unsigned int prefetchable:1;
            unsigned int base_address:28;
        } __attribute__ ((packed)) mem;
        struct {
            unsigned int region_type:1;
            unsigned int reserved:1;
            unsigned int base_address:30;
        } __attribute__ ((packed)) io;
    } __attribute__ ((packed));
} __attribute__ ((packed)) lm_bar_t;
_Static_assert(sizeof(lm_bar_t) == 0x4, "bad BAR size");

typedef union {
    uint8_t raw;
} __attribute__ ((packed)) lm_pci_hdr_htype_t;
_Static_assert(sizeof(lm_pci_hdr_htype_t) == 0x1, "bad HTYPE size");

typedef union {
    uint8_t raw[3];
    struct {
        uint8_t pi;
        uint8_t scc;
        uint8_t bcc;
    } __attribute__ ((packed));
} __attribute__ ((packed)) lm_pci_hdr_cc_t;
_Static_assert(sizeof(lm_pci_hdr_cc_t) == 0x3, "bad CC size");

/* device status */
typedef union {
    uint16_t raw;
    struct {
        unsigned int res1:3;
        unsigned int is:1;
        unsigned int cl:1;
        unsigned int c66:1;
        unsigned int res2:1;
        unsigned int fbc:1;
        unsigned int dpd:1;
        unsigned int devt:2;
        unsigned int sta:1;
        unsigned int rta:1;
        unsigned int rma:1;
        unsigned int sse:1;
        unsigned int dpe:1;
    } __attribute__ ((packed));
} __attribute__ ((packed)) lm_pci_hdr_sts_t;
_Static_assert(sizeof(lm_pci_hdr_sts_t) == 0x2, "bad STS size");

typedef union {
    uint16_t raw;
    struct {
        uint8_t iose:1;
        uint8_t mse:1;
        uint8_t bme:1;
        uint8_t sce:1;
        uint8_t mwie:1;
        uint8_t vga:1;
        uint8_t pee:1;
        uint8_t zero:1;
        uint8_t see:1;
        uint8_t fbe:1;
        uint8_t id:1;
        uint8_t res1:5;
    } __attribute__ ((packed));
} __attribute__ ((packed)) lm_pci_hdr_cmd_t;
_Static_assert(sizeof(lm_pci_hdr_cmd_t) == 0x2, "bad CMD size");

typedef union {
    uint32_t raw;
    struct {
        uint16_t vid;
        uint16_t did;
    } __attribute__ ((packed));
} __attribute__ ((packed)) lm_pci_hdr_id_t;
_Static_assert(sizeof(lm_pci_hdr_id_t) == 0x4, "bad ID size");

typedef union {
    uint16_t raw;
    struct {
        uint8_t iline;
        uint8_t ipin;
    } __attribute__ ((packed));
} __attribute__ ((packed)) lm_pci_hdr_intr_t;
_Static_assert(sizeof(lm_pci_hdr_intr_t) == 0x2, "bad INTR size");

typedef union {
    uint8_t raw[PCI_STD_HEADER_SIZEOF];
    struct {
        lm_pci_hdr_id_t id;
        lm_pci_hdr_cmd_t cmd;
        lm_pci_hdr_sts_t sts;
        uint8_t rid;
        lm_pci_hdr_cc_t cc;
        uint8_t cls;
        uint8_t mlt;
        lm_pci_hdr_htype_t htype;
        lm_pci_hdr_bist_t bist;
#define PCI_BARS_NR 6
        lm_bar_t bars[PCI_BARS_NR];
        uint32_t ccptr;
        lm_pci_hdr_ss_t ss;
        uint32_t erom;
        uint8_t cap;
        uint8_t res1[7];
        lm_pci_hdr_intr_t intr;
        uint8_t mgnt;
        uint8_t mlat;
    } __attribute__ ((packed));
} __attribute__ ((packed)) lm_pci_hdr_t;
_Static_assert(sizeof(lm_pci_hdr_t) == 0x40, "bad PCI header size");

typedef struct {
    uint8_t raw[PCI_CFG_SPACE_SIZE - PCI_STD_HEADER_SIZEOF];
} __attribute__ ((packed)) lm_pci_non_std_config_space_t;
_Static_assert(sizeof(lm_pci_non_std_config_space_t) == 0xc0,
               "bad non-standard PCI configuration space size");

struct lm_pci_config_space {
    union {
        uint8_t raw[PCI_CFG_SPACE_SIZE];
        struct {
            lm_pci_hdr_t hdr;
            lm_pci_non_std_config_space_t non_std;
        } __attribute__ ((packed));
    } __attribute__ ((packed));
    uint8_t extended[];
} __attribute__ ((packed));
_Static_assert(sizeof(struct lm_pci_config_space) == 0x100,
               "bad PCI configuration space size");

// Region flags.
#define LM_REG_FLAG_READ    (1 << 0)
#define LM_REG_FLAG_WRITE   (1 << 1)
#define LM_REG_FLAG_MMAP    (1 << 2)    // TODO: how this relates to IO bar?
#define LM_REG_FLAG_RW      (LM_REG_FLAG_READ | LM_REG_FLAG_WRITE)
#define LM_REG_FLAG_MEM     (1 << 3)    // if unset, bar is IO

struct lm_mmap_area {
	uint64_t start;
	uint64_t size;
};

struct lm_sparse_mmap_areas {
    int nr_mmap_areas;
    struct lm_mmap_area areas[];
};

typedef ssize_t (lm_region_access_t) (void *pvt, char * const buf, size_t count,
                                      loff_t offset, const bool is_write);

typedef unsigned long (lm_map_region_t) (void *pvt, unsigned long pgoff,
                                         unsigned long len);
struct lm_reg_info {
    uint32_t            flags;
    uint32_t            size;
    uint64_t            offset;
    lm_region_access_t  *fn;
    lm_map_region_t     *map;
    struct lm_sparse_mmap_areas *mmap_areas; /* sparse mmap areas */
};

enum {
    LM_DEV_INTX_IRQ_IDX,
    LM_DEV_MSI_IRQ_IDX,
    LM_DEV_MSIX_IRQ_IDX,
    LM_DEV_ERR_IRQ_IDX,
    LM_DEV_REQ_IRQ_IDX,
    LM_DEV_NUM_IRQS = 5
};

/*
 * Returns a pointer to the non-standard part of the PCI configuration space.
 */
lm_pci_config_space_t *lm_get_pci_config_space(lm_ctx_t * const lm_ctx);

lm_reg_info_t *lm_get_region_info(lm_ctx_t * const lm_ctx);

/*
 * TODO the rest of these functions don't need to be public, put them in a
 * private header file so libmuser.c can use them.
 * TODO replace the "muser" prefix
 */
int
muser_pci_hdr_access(lm_ctx_t * const lm_ctx, size_t * const count,
                     loff_t * const pos, const bool write,
                     unsigned char *const buf);



#endif                          /* LIBMUSER_PCI_H */

/* ex: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab: */