1 #include "libxl_osdeps.h" /* must come before any other headers */
2 #include "libxlu_internal.h"
3 #include "libxlu_disk_l.h"
4 #include "libxlu_disk_i.h"
5 #include "libxlu_cfg_i.h"
6
7
8 #define XLU__PCI_ERR(_c, _x, _a...) \
9 if((_c) && (_c)->report) fprintf((_c)->report, _x, ##_a)
10
hex_convert(const char * str,unsigned int * val,unsigned int mask)11 static int hex_convert(const char *str, unsigned int *val, unsigned int mask)
12 {
13 unsigned long ret;
14 char *end;
15
16 ret = strtoul(str, &end, 16);
17 if ( end == str || *end != '\0' )
18 return -1;
19 if ( ret & ~mask )
20 return -1;
21 *val = (unsigned int)ret & mask;
22 return 0;
23 }
24
pcidev_struct_fill(libxl_device_pci * pcidev,unsigned int domain,unsigned int bus,unsigned int dev,unsigned int func,unsigned int vdevfn)25 static int pcidev_struct_fill(libxl_device_pci *pcidev, unsigned int domain,
26 unsigned int bus, unsigned int dev,
27 unsigned int func, unsigned int vdevfn)
28 {
29 pcidev->domain = domain;
30 pcidev->bus = bus;
31 pcidev->dev = dev;
32 pcidev->func = func;
33 pcidev->vdevfn = vdevfn;
34 return 0;
35 }
36
37 #define STATE_DOMAIN 0
38 #define STATE_BUS 1
39 #define STATE_DEV 2
40 #define STATE_FUNC 3
41 #define STATE_VSLOT 4
42 #define STATE_OPTIONS_K 6
43 #define STATE_OPTIONS_V 7
44 #define STATE_TERMINAL 8
45 #define STATE_TYPE 9
46 #define STATE_RDM_STRATEGY 10
47 #define STATE_RESERVE_POLICY 11
xlu_pci_parse_bdf(XLU_Config * cfg,libxl_device_pci * pcidev,const char * str)48 int xlu_pci_parse_bdf(XLU_Config *cfg, libxl_device_pci *pcidev, const char *str)
49 {
50 unsigned state = STATE_DOMAIN;
51 unsigned dom, bus, dev, func, vslot = 0;
52 char *buf2, *tok, *ptr, *end, *optkey = NULL;
53
54 if ( NULL == (buf2 = ptr = strdup(str)) )
55 return ERROR_NOMEM;
56
57 for(tok = ptr, end = ptr + strlen(ptr) + 1; ptr < end; ptr++) {
58 switch(state) {
59 case STATE_DOMAIN:
60 if ( *ptr == ':' ) {
61 state = STATE_BUS;
62 *ptr = '\0';
63 if ( hex_convert(tok, &dom, 0xffff) )
64 goto parse_error;
65 tok = ptr + 1;
66 }
67 break;
68 case STATE_BUS:
69 if ( *ptr == ':' ) {
70 state = STATE_DEV;
71 *ptr = '\0';
72 if ( hex_convert(tok, &bus, 0xff) )
73 goto parse_error;
74 tok = ptr + 1;
75 }else if ( *ptr == '.' ) {
76 state = STATE_FUNC;
77 *ptr = '\0';
78 if ( dom & ~0xff )
79 goto parse_error;
80 bus = dom;
81 dom = 0;
82 if ( hex_convert(tok, &dev, 0xff) )
83 goto parse_error;
84 tok = ptr + 1;
85 }
86 break;
87 case STATE_DEV:
88 if ( *ptr == '.' ) {
89 state = STATE_FUNC;
90 *ptr = '\0';
91 if ( hex_convert(tok, &dev, 0xff) )
92 goto parse_error;
93 tok = ptr + 1;
94 }
95 break;
96 case STATE_FUNC:
97 if ( *ptr == '\0' || *ptr == '@' || *ptr == ',' ) {
98 switch( *ptr ) {
99 case '\0':
100 state = STATE_TERMINAL;
101 break;
102 case '@':
103 state = STATE_VSLOT;
104 break;
105 case ',':
106 state = STATE_OPTIONS_K;
107 break;
108 }
109 *ptr = '\0';
110 if ( !strcmp(tok, "*") ) {
111 pcidev->vfunc_mask = LIBXL_PCI_FUNC_ALL;
112 }else{
113 if ( hex_convert(tok, &func, 0x7) )
114 goto parse_error;
115 pcidev->vfunc_mask = (1 << 0);
116 }
117 tok = ptr + 1;
118 }
119 break;
120 case STATE_VSLOT:
121 if ( *ptr == '\0' || *ptr == ',' ) {
122 state = ( *ptr == ',' ) ? STATE_OPTIONS_K : STATE_TERMINAL;
123 *ptr = '\0';
124 if ( hex_convert(tok, &vslot, 0xff) )
125 goto parse_error;
126 tok = ptr + 1;
127 }
128 break;
129 case STATE_OPTIONS_K:
130 if ( *ptr == '=' ) {
131 state = STATE_OPTIONS_V;
132 *ptr = '\0';
133 optkey = tok;
134 tok = ptr + 1;
135 }
136 break;
137 case STATE_OPTIONS_V:
138 if ( *ptr == ',' || *ptr == '\0' ) {
139 state = (*ptr == ',') ? STATE_OPTIONS_K : STATE_TERMINAL;
140 *ptr = '\0';
141 if ( !strcmp(optkey, "msitranslate") ) {
142 pcidev->msitranslate = atoi(tok);
143 }else if ( !strcmp(optkey, "power_mgmt") ) {
144 pcidev->power_mgmt = atoi(tok);
145 }else if ( !strcmp(optkey, "permissive") ) {
146 pcidev->permissive = atoi(tok);
147 }else if ( !strcmp(optkey, "seize") ) {
148 pcidev->seize = atoi(tok);
149 } else if (!strcmp(optkey, "rdm_policy")) {
150 if (!strcmp(tok, "strict")) {
151 pcidev->rdm_policy = LIBXL_RDM_RESERVE_POLICY_STRICT;
152 } else if (!strcmp(tok, "relaxed")) {
153 pcidev->rdm_policy = LIBXL_RDM_RESERVE_POLICY_RELAXED;
154 } else {
155 XLU__PCI_ERR(cfg, "%s is not an valid PCI RDM property"
156 " policy: 'strict' or 'relaxed'.",
157 tok);
158 goto parse_error;
159 }
160 } else {
161 XLU__PCI_ERR(cfg, "Unknown PCI BDF option: %s", optkey);
162 }
163 tok = ptr + 1;
164 }
165 default:
166 break;
167 }
168 }
169
170 if ( tok != ptr || state != STATE_TERMINAL )
171 goto parse_error;
172
173 /* Just a pretty way to fill in the values */
174 pcidev_struct_fill(pcidev, dom, bus, dev, func, vslot << 3);
175
176 free(buf2);
177
178 return 0;
179
180 parse_error:
181 free(buf2);
182 return ERROR_INVAL;
183 }
184
xlu_rdm_parse(XLU_Config * cfg,libxl_rdm_reserve * rdm,const char * str)185 int xlu_rdm_parse(XLU_Config *cfg, libxl_rdm_reserve *rdm, const char *str)
186 {
187 unsigned state = STATE_TYPE;
188 char *buf2, *tok, *ptr, *end;
189
190 if (NULL == (buf2 = ptr = strdup(str)))
191 return ERROR_NOMEM;
192
193 for (tok = ptr, end = ptr + strlen(ptr) + 1; ptr < end; ptr++) {
194 switch(state) {
195 case STATE_TYPE:
196 if (*ptr == '=') {
197 state = STATE_RDM_STRATEGY;
198 *ptr = '\0';
199 if (strcmp(tok, "strategy")) {
200 XLU__PCI_ERR(cfg, "Unknown RDM state option: %s", tok);
201 goto parse_error;
202 }
203 tok = ptr + 1;
204 }
205 break;
206 case STATE_RDM_STRATEGY:
207 if (*ptr == '\0' || *ptr == ',') {
208 state = STATE_RESERVE_POLICY;
209 *ptr = '\0';
210 if (!strcmp(tok, "host")) {
211 rdm->strategy = LIBXL_RDM_RESERVE_STRATEGY_HOST;
212 } else {
213 XLU__PCI_ERR(cfg, "Unknown RDM strategy option: %s", tok);
214 goto parse_error;
215 }
216 tok = ptr + 1;
217 }
218 break;
219 case STATE_RESERVE_POLICY:
220 if (*ptr == '=') {
221 state = STATE_OPTIONS_V;
222 *ptr = '\0';
223 if (strcmp(tok, "policy")) {
224 XLU__PCI_ERR(cfg, "Unknown RDM property value: %s", tok);
225 goto parse_error;
226 }
227 tok = ptr + 1;
228 }
229 break;
230 case STATE_OPTIONS_V:
231 if (*ptr == ',' || *ptr == '\0') {
232 state = STATE_TERMINAL;
233 *ptr = '\0';
234 if (!strcmp(tok, "strict")) {
235 rdm->policy = LIBXL_RDM_RESERVE_POLICY_STRICT;
236 } else if (!strcmp(tok, "relaxed")) {
237 rdm->policy = LIBXL_RDM_RESERVE_POLICY_RELAXED;
238 } else {
239 XLU__PCI_ERR(cfg, "Unknown RDM property policy value: %s",
240 tok);
241 goto parse_error;
242 }
243 tok = ptr + 1;
244 }
245 default:
246 break;
247 }
248 }
249
250 if (tok != ptr || state != STATE_TERMINAL)
251 goto parse_error;
252
253 free(buf2);
254
255 return 0;
256
257 parse_error:
258 free(buf2);
259 return ERROR_INVAL;
260 }
261
262 /*
263 * Local variables:
264 * mode: C
265 * c-basic-offset: 4
266 * indent-tabs-mode: nil
267 * End:
268 */
269