1 | /* SPDX-License-Identifier: GPL-2.0 */ |
2 | /* |
3 | * PCI Backend - Common data structures for overriding the configuration space |
4 | * |
5 | * Author: Ryan Wilson <hap9@epoch.ncsc.mil> |
6 | */ |
7 | |
8 | #ifndef __XEN_PCIBACK_CONF_SPACE_H__ |
9 | #define __XEN_PCIBACK_CONF_SPACE_H__ |
10 | |
11 | #include <linux/list.h> |
12 | #include <linux/err.h> |
13 | |
14 | /* conf_field_init can return an errno in a ptr with ERR_PTR() */ |
15 | typedef void *(*conf_field_init) (struct pci_dev *dev, int offset); |
16 | typedef void (*conf_field_reset) (struct pci_dev *dev, int offset, void *data); |
17 | typedef void (*conf_field_free) (struct pci_dev *dev, int offset, void *data); |
18 | |
19 | typedef int (*conf_dword_write) (struct pci_dev *dev, int offset, u32 value, |
20 | void *data); |
21 | typedef int (*conf_word_write) (struct pci_dev *dev, int offset, u16 value, |
22 | void *data); |
23 | typedef int (*conf_byte_write) (struct pci_dev *dev, int offset, u8 value, |
24 | void *data); |
25 | typedef int (*conf_dword_read) (struct pci_dev *dev, int offset, u32 *value, |
26 | void *data); |
27 | typedef int (*conf_word_read) (struct pci_dev *dev, int offset, u16 *value, |
28 | void *data); |
29 | typedef int (*conf_byte_read) (struct pci_dev *dev, int offset, u8 *value, |
30 | void *data); |
31 | |
32 | /* These are the fields within the configuration space which we |
33 | * are interested in intercepting reads/writes to and changing their |
34 | * values. |
35 | */ |
36 | struct config_field { |
37 | unsigned int offset; |
38 | unsigned int size; |
39 | unsigned int mask; |
40 | conf_field_init init; |
41 | conf_field_reset reset; |
42 | conf_field_free release; |
43 | void (*clean) (struct config_field *field); |
44 | union { |
45 | struct { |
46 | conf_dword_write write; |
47 | conf_dword_read read; |
48 | } dw; |
49 | struct { |
50 | conf_word_write write; |
51 | conf_word_read read; |
52 | } w; |
53 | struct { |
54 | conf_byte_write write; |
55 | conf_byte_read read; |
56 | } b; |
57 | } u; |
58 | struct list_head list; |
59 | }; |
60 | |
61 | struct config_field_entry { |
62 | struct list_head list; |
63 | const struct config_field *field; |
64 | unsigned int base_offset; |
65 | void *data; |
66 | }; |
67 | |
68 | #define INTERRUPT_TYPE_NONE (0) |
69 | #define INTERRUPT_TYPE_INTX (1<<0) |
70 | #define INTERRUPT_TYPE_MSI (1<<1) |
71 | #define INTERRUPT_TYPE_MSIX (1<<2) |
72 | |
73 | extern bool xen_pcibk_permissive; |
74 | |
75 | #define OFFSET(cfg_entry) ((cfg_entry)->base_offset+(cfg_entry)->field->offset) |
76 | |
77 | /* Add fields to a device - the add_fields macro expects to get a pointer to |
78 | * the first entry in an array (of which the ending is marked by size==0) |
79 | */ |
80 | int xen_pcibk_config_add_field_offset(struct pci_dev *dev, |
81 | const struct config_field *field, |
82 | unsigned int offset); |
83 | |
84 | static inline int xen_pcibk_config_add_field(struct pci_dev *dev, |
85 | const struct config_field *field) |
86 | { |
87 | return xen_pcibk_config_add_field_offset(dev, field, offset: 0); |
88 | } |
89 | |
90 | static inline int xen_pcibk_config_add_fields(struct pci_dev *dev, |
91 | const struct config_field *field) |
92 | { |
93 | int i, err = 0; |
94 | for (i = 0; field[i].size != 0; i++) { |
95 | err = xen_pcibk_config_add_field(dev, field: &field[i]); |
96 | if (err) |
97 | break; |
98 | } |
99 | return err; |
100 | } |
101 | |
102 | static inline int xen_pcibk_config_add_fields_offset(struct pci_dev *dev, |
103 | const struct config_field *field, |
104 | unsigned int offset) |
105 | { |
106 | int i, err = 0; |
107 | for (i = 0; field[i].size != 0; i++) { |
108 | err = xen_pcibk_config_add_field_offset(dev, field: &field[i], offset); |
109 | if (err) |
110 | break; |
111 | } |
112 | return err; |
113 | } |
114 | |
115 | /* Read/Write the real configuration space */ |
116 | int xen_pcibk_read_config_byte(struct pci_dev *dev, int offset, u8 *value, |
117 | void *data); |
118 | int xen_pcibk_read_config_word(struct pci_dev *dev, int offset, u16 *value, |
119 | void *data); |
120 | int xen_pcibk_read_config_dword(struct pci_dev *dev, int offset, u32 *value, |
121 | void *data); |
122 | int xen_pcibk_write_config_byte(struct pci_dev *dev, int offset, u8 value, |
123 | void *data); |
124 | int xen_pcibk_write_config_word(struct pci_dev *dev, int offset, u16 value, |
125 | void *data); |
126 | int xen_pcibk_write_config_dword(struct pci_dev *dev, int offset, u32 value, |
127 | void *data); |
128 | |
129 | int xen_pcibk_config_capability_init(void); |
130 | |
131 | int (struct pci_dev *dev); |
132 | int xen_pcibk_config_capability_add_fields(struct pci_dev *dev); |
133 | |
134 | int xen_pcibk_get_interrupt_type(struct pci_dev *dev); |
135 | |
136 | #endif /* __XEN_PCIBACK_CONF_SPACE_H__ */ |
137 | |