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