1 /*
2 * xc_psr.c
3 *
4 * platform shared resource related API functions.
5 *
6 * Copyright (C) 2014 Intel Corporation
7 * Author Dongxiao Xu <dongxiao.xu@intel.com>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as published
11 * by the Free Software Foundation; version 2.1 only. with the special
12 * exception on linking described in file LICENSE.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Lesser General Public License for more details.
18 */
19
20 #include <assert.h>
21 #include "xc_private.h"
22 #include "xc_msr_x86.h"
23
24 #define IA32_CMT_CTR_ERROR_MASK (0x3ull << 62)
25
26 #define EVTID_L3_OCCUPANCY 0x1
27 #define EVTID_TOTAL_MEM_COUNT 0x2
28 #define EVTID_LOCAL_MEM_COUNT 0x3
29
xc_psr_cmt_attach(xc_interface * xch,uint32_t domid)30 int xc_psr_cmt_attach(xc_interface *xch, uint32_t domid)
31 {
32 DECLARE_DOMCTL;
33
34 domctl.cmd = XEN_DOMCTL_psr_cmt_op;
35 domctl.domain = domid;
36 domctl.u.psr_cmt_op.cmd = XEN_DOMCTL_PSR_CMT_OP_ATTACH;
37
38 return do_domctl(xch, &domctl);
39 }
40
xc_psr_cmt_detach(xc_interface * xch,uint32_t domid)41 int xc_psr_cmt_detach(xc_interface *xch, uint32_t domid)
42 {
43 DECLARE_DOMCTL;
44
45 domctl.cmd = XEN_DOMCTL_psr_cmt_op;
46 domctl.domain = domid;
47 domctl.u.psr_cmt_op.cmd = XEN_DOMCTL_PSR_CMT_OP_DETACH;
48
49 return do_domctl(xch, &domctl);
50 }
51
xc_psr_cmt_get_domain_rmid(xc_interface * xch,uint32_t domid,uint32_t * rmid)52 int xc_psr_cmt_get_domain_rmid(xc_interface *xch, uint32_t domid,
53 uint32_t *rmid)
54 {
55 int rc;
56 DECLARE_DOMCTL;
57
58 domctl.cmd = XEN_DOMCTL_psr_cmt_op;
59 domctl.domain = domid;
60 domctl.u.psr_cmt_op.cmd = XEN_DOMCTL_PSR_CMT_OP_QUERY_RMID;
61
62 rc = do_domctl(xch, &domctl);
63
64 if ( !rc )
65 *rmid = domctl.u.psr_cmt_op.data;
66
67 return rc;
68 }
69
xc_psr_cmt_get_total_rmid(xc_interface * xch,uint32_t * total_rmid)70 int xc_psr_cmt_get_total_rmid(xc_interface *xch, uint32_t *total_rmid)
71 {
72 static int val = 0;
73 int rc;
74 DECLARE_SYSCTL;
75
76 if ( val )
77 {
78 *total_rmid = val;
79 return 0;
80 }
81
82 sysctl.cmd = XEN_SYSCTL_psr_cmt_op;
83 sysctl.u.psr_cmt_op.cmd = XEN_SYSCTL_PSR_CMT_get_total_rmid;
84 sysctl.u.psr_cmt_op.flags = 0;
85
86 rc = xc_sysctl(xch, &sysctl);
87 if ( !rc )
88 val = *total_rmid = sysctl.u.psr_cmt_op.u.data;
89
90 return rc;
91 }
92
xc_psr_cmt_get_l3_upscaling_factor(xc_interface * xch,uint32_t * upscaling_factor)93 int xc_psr_cmt_get_l3_upscaling_factor(xc_interface *xch,
94 uint32_t *upscaling_factor)
95 {
96 static int val = 0;
97 int rc;
98 DECLARE_SYSCTL;
99
100 if ( val )
101 {
102 *upscaling_factor = val;
103 return 0;
104 }
105
106 sysctl.cmd = XEN_SYSCTL_psr_cmt_op;
107 sysctl.u.psr_cmt_op.cmd =
108 XEN_SYSCTL_PSR_CMT_get_l3_upscaling_factor;
109 sysctl.u.psr_cmt_op.flags = 0;
110
111 rc = xc_sysctl(xch, &sysctl);
112 if ( !rc )
113 val = *upscaling_factor = sysctl.u.psr_cmt_op.u.data;
114
115 return rc;
116 }
117
xc_psr_cmt_get_l3_event_mask(xc_interface * xch,uint32_t * event_mask)118 int xc_psr_cmt_get_l3_event_mask(xc_interface *xch, uint32_t *event_mask)
119 {
120 int rc;
121 DECLARE_SYSCTL;
122
123 sysctl.cmd = XEN_SYSCTL_psr_cmt_op;
124 sysctl.u.psr_cmt_op.cmd =
125 XEN_SYSCTL_PSR_CMT_get_l3_event_mask;
126 sysctl.u.psr_cmt_op.flags = 0;
127
128 rc = xc_sysctl(xch, &sysctl);
129 if ( !rc )
130 *event_mask = sysctl.u.psr_cmt_op.u.data;
131
132 return rc;
133 }
134
xc_psr_cmt_get_l3_cache_size(xc_interface * xch,uint32_t cpu,uint32_t * l3_cache_size)135 int xc_psr_cmt_get_l3_cache_size(xc_interface *xch, uint32_t cpu,
136 uint32_t *l3_cache_size)
137 {
138 static int val = 0;
139 int rc;
140 DECLARE_SYSCTL;
141
142 if ( val )
143 {
144 *l3_cache_size = val;
145 return 0;
146 }
147
148 sysctl.cmd = XEN_SYSCTL_psr_cmt_op;
149 sysctl.u.psr_cmt_op.cmd =
150 XEN_SYSCTL_PSR_CMT_get_l3_cache_size;
151 sysctl.u.psr_cmt_op.flags = 0;
152 sysctl.u.psr_cmt_op.u.l3_cache.cpu = cpu;
153
154 rc = xc_sysctl(xch, &sysctl);
155 if ( !rc )
156 val = *l3_cache_size= sysctl.u.psr_cmt_op.u.data;
157
158 return rc;
159 }
160
xc_psr_cmt_get_data(xc_interface * xch,uint32_t rmid,uint32_t cpu,xc_psr_cmt_type type,uint64_t * monitor_data,uint64_t * tsc)161 int xc_psr_cmt_get_data(xc_interface *xch, uint32_t rmid, uint32_t cpu,
162 xc_psr_cmt_type type, uint64_t *monitor_data,
163 uint64_t *tsc)
164 {
165 xc_resource_op_t op;
166 xc_resource_entry_t entries[3];
167 xc_resource_entry_t *tsc_entry = NULL;
168 uint32_t evtid, nr = 0;
169 int rc;
170
171 switch ( type )
172 {
173 case XC_PSR_CMT_L3_OCCUPANCY:
174 evtid = EVTID_L3_OCCUPANCY;
175 break;
176 case XC_PSR_CMT_TOTAL_MEM_COUNT:
177 evtid = EVTID_TOTAL_MEM_COUNT;
178 break;
179 case XC_PSR_CMT_LOCAL_MEM_COUNT:
180 evtid = EVTID_LOCAL_MEM_COUNT;
181 break;
182 default:
183 return -1;
184 }
185
186 entries[nr].u.cmd = XEN_RESOURCE_OP_MSR_WRITE;
187 entries[nr].idx = MSR_IA32_CMT_EVTSEL;
188 entries[nr].val = (uint64_t)rmid << 32 | evtid;
189 entries[nr].rsvd = 0;
190 nr++;
191
192 entries[nr].u.cmd = XEN_RESOURCE_OP_MSR_READ;
193 entries[nr].idx = MSR_IA32_CMT_CTR;
194 entries[nr].val = 0;
195 entries[nr].rsvd = 0;
196 nr++;
197
198 if ( tsc != NULL )
199 {
200 tsc_entry = &entries[nr];
201 entries[nr].u.cmd = XEN_RESOURCE_OP_MSR_READ;
202 entries[nr].idx = MSR_IA32_TSC;
203 entries[nr].val = 0;
204 entries[nr].rsvd = 0;
205 nr++;
206 }
207
208 assert(nr <= ARRAY_SIZE(entries));
209
210 op.cpu = cpu;
211 op.nr_entries = nr;
212 op.entries = entries;
213
214 rc = xc_resource_op(xch, 1, &op);
215 if ( rc < 0 )
216 return rc;
217
218 if ( op.result != nr || entries[1].val & IA32_CMT_CTR_ERROR_MASK )
219 return -1;
220
221 *monitor_data = entries[1].val;
222
223 if ( tsc_entry != NULL )
224 *tsc = tsc_entry->val;
225
226 return 0;
227 }
228
xc_psr_cmt_enabled(xc_interface * xch)229 int xc_psr_cmt_enabled(xc_interface *xch)
230 {
231 static int val = -1;
232 int rc;
233 DECLARE_SYSCTL;
234
235 if ( val >= 0 )
236 return val;
237
238 sysctl.cmd = XEN_SYSCTL_psr_cmt_op;
239 sysctl.u.psr_cmt_op.cmd = XEN_SYSCTL_PSR_CMT_enabled;
240 sysctl.u.psr_cmt_op.flags = 0;
241
242 rc = do_sysctl(xch, &sysctl);
243 if ( !rc )
244 {
245 val = sysctl.u.psr_cmt_op.u.data;
246 return val;
247 }
248
249 return 0;
250 }
xc_psr_set_domain_data(xc_interface * xch,uint32_t domid,xc_psr_type type,uint32_t target,uint64_t data)251 int xc_psr_set_domain_data(xc_interface *xch, uint32_t domid,
252 xc_psr_type type, uint32_t target,
253 uint64_t data)
254 {
255 DECLARE_DOMCTL;
256 uint32_t cmd;
257
258 switch ( type )
259 {
260 case XC_PSR_CAT_L3_CBM:
261 cmd = XEN_DOMCTL_PSR_SET_L3_CBM;
262 break;
263 case XC_PSR_CAT_L3_CBM_CODE:
264 cmd = XEN_DOMCTL_PSR_SET_L3_CODE;
265 break;
266 case XC_PSR_CAT_L3_CBM_DATA:
267 cmd = XEN_DOMCTL_PSR_SET_L3_DATA;
268 break;
269 case XC_PSR_CAT_L2_CBM:
270 cmd = XEN_DOMCTL_PSR_SET_L2_CBM;
271 break;
272 case XC_PSR_MBA_THRTL:
273 cmd = XEN_DOMCTL_PSR_SET_MBA_THRTL;
274 break;
275 default:
276 errno = EINVAL;
277 return -1;
278 }
279
280 domctl.cmd = XEN_DOMCTL_psr_alloc;
281 domctl.domain = domid;
282 domctl.u.psr_alloc.cmd = cmd;
283 domctl.u.psr_alloc.target = target;
284 domctl.u.psr_alloc.data = data;
285
286 return do_domctl(xch, &domctl);
287 }
288
xc_psr_get_domain_data(xc_interface * xch,uint32_t domid,xc_psr_type type,uint32_t target,uint64_t * data)289 int xc_psr_get_domain_data(xc_interface *xch, uint32_t domid,
290 xc_psr_type type, uint32_t target,
291 uint64_t *data)
292 {
293 int rc;
294 DECLARE_DOMCTL;
295 uint32_t cmd;
296
297 switch ( type )
298 {
299 case XC_PSR_CAT_L3_CBM:
300 cmd = XEN_DOMCTL_PSR_GET_L3_CBM;
301 break;
302 case XC_PSR_CAT_L3_CBM_CODE:
303 cmd = XEN_DOMCTL_PSR_GET_L3_CODE;
304 break;
305 case XC_PSR_CAT_L3_CBM_DATA:
306 cmd = XEN_DOMCTL_PSR_GET_L3_DATA;
307 break;
308 case XC_PSR_CAT_L2_CBM:
309 cmd = XEN_DOMCTL_PSR_GET_L2_CBM;
310 break;
311 case XC_PSR_MBA_THRTL:
312 cmd = XEN_DOMCTL_PSR_GET_MBA_THRTL;
313 break;
314 default:
315 errno = EINVAL;
316 return -1;
317 }
318
319 domctl.cmd = XEN_DOMCTL_psr_alloc;
320 domctl.domain = domid;
321 domctl.u.psr_alloc.cmd = cmd;
322 domctl.u.psr_alloc.target = target;
323
324 rc = do_domctl(xch, &domctl);
325
326 if ( !rc )
327 *data = domctl.u.psr_alloc.data;
328
329 return rc;
330 }
331
xc_psr_get_hw_info(xc_interface * xch,uint32_t socket,xc_psr_feat_type type,xc_psr_hw_info * hw_info)332 int xc_psr_get_hw_info(xc_interface *xch, uint32_t socket,
333 xc_psr_feat_type type, xc_psr_hw_info *hw_info)
334 {
335 int rc = -1;
336 DECLARE_SYSCTL;
337
338 if ( !hw_info )
339 {
340 errno = EINVAL;
341 return rc;
342 }
343
344 sysctl.cmd = XEN_SYSCTL_psr_alloc;
345 sysctl.u.psr_alloc.target = socket;
346
347 switch ( type )
348 {
349 case XC_PSR_CAT_L2:
350 case XC_PSR_CAT_L3:
351 sysctl.u.psr_alloc.cmd = (type == XC_PSR_CAT_L2) ?
352 XEN_SYSCTL_PSR_get_l2_info :
353 XEN_SYSCTL_PSR_get_l3_info;
354
355 rc = xc_sysctl(xch, &sysctl);
356 if ( rc )
357 break;
358
359 hw_info->cat.cos_max = sysctl.u.psr_alloc.u.cat_info.cos_max;
360 hw_info->cat.cbm_len = sysctl.u.psr_alloc.u.cat_info.cbm_len;
361 hw_info->cat.cdp_enabled = (type == XC_PSR_CAT_L2) ?
362 false :
363 (sysctl.u.psr_alloc.u.cat_info.flags &
364 XEN_SYSCTL_PSR_CAT_L3_CDP);
365
366 break;
367 case XC_PSR_MBA:
368 sysctl.u.psr_alloc.cmd = XEN_SYSCTL_PSR_get_mba_info;
369 rc = xc_sysctl(xch, &sysctl);
370 if ( rc )
371 break;
372
373 hw_info->mba.cos_max = sysctl.u.psr_alloc.u.mba_info.cos_max;
374 hw_info->mba.thrtl_max = sysctl.u.psr_alloc.u.mba_info.thrtl_max;
375 hw_info->mba.linear = sysctl.u.psr_alloc.u.mba_info.flags &
376 XEN_SYSCTL_PSR_MBA_LINEAR;
377
378 break;
379 default:
380 errno = EOPNOTSUPP;
381 break;
382 }
383
384 return rc;
385 }
386
387 /*
388 * Local variables:
389 * mode: C
390 * c-file-style: "BSD"
391 * c-basic-offset: 4
392 * tab-width: 4
393 * indent-tabs-mode: nil
394 * End:
395 */
396