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_cat_set_domain_data(xc_interface * xch,uint32_t domid,xc_psr_cat_type type,uint32_t target,uint64_t data)251 int xc_psr_cat_set_domain_data(xc_interface *xch, uint32_t domid,
252 xc_psr_cat_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_CAT_OP_SET_L3_CBM;
262 break;
263 case XC_PSR_CAT_L3_CBM_CODE:
264 cmd = XEN_DOMCTL_PSR_CAT_OP_SET_L3_CODE;
265 break;
266 case XC_PSR_CAT_L3_CBM_DATA:
267 cmd = XEN_DOMCTL_PSR_CAT_OP_SET_L3_DATA;
268 break;
269 case XC_PSR_CAT_L2_CBM:
270 cmd = XEN_DOMCTL_PSR_CAT_OP_SET_L2_CBM;
271 break;
272 default:
273 errno = EINVAL;
274 return -1;
275 }
276
277 domctl.cmd = XEN_DOMCTL_psr_cat_op;
278 domctl.domain = domid;
279 domctl.u.psr_cat_op.cmd = cmd;
280 domctl.u.psr_cat_op.target = target;
281 domctl.u.psr_cat_op.data = data;
282
283 return do_domctl(xch, &domctl);
284 }
285
xc_psr_cat_get_domain_data(xc_interface * xch,uint32_t domid,xc_psr_cat_type type,uint32_t target,uint64_t * data)286 int xc_psr_cat_get_domain_data(xc_interface *xch, uint32_t domid,
287 xc_psr_cat_type type, uint32_t target,
288 uint64_t *data)
289 {
290 int rc;
291 DECLARE_DOMCTL;
292 uint32_t cmd;
293
294 switch ( type )
295 {
296 case XC_PSR_CAT_L3_CBM:
297 cmd = XEN_DOMCTL_PSR_CAT_OP_GET_L3_CBM;
298 break;
299 case XC_PSR_CAT_L3_CBM_CODE:
300 cmd = XEN_DOMCTL_PSR_CAT_OP_GET_L3_CODE;
301 break;
302 case XC_PSR_CAT_L3_CBM_DATA:
303 cmd = XEN_DOMCTL_PSR_CAT_OP_GET_L3_DATA;
304 break;
305 case XC_PSR_CAT_L2_CBM:
306 cmd = XEN_DOMCTL_PSR_CAT_OP_GET_L2_CBM;
307 break;
308 default:
309 errno = EINVAL;
310 return -1;
311 }
312
313 domctl.cmd = XEN_DOMCTL_psr_cat_op;
314 domctl.domain = domid;
315 domctl.u.psr_cat_op.cmd = cmd;
316 domctl.u.psr_cat_op.target = target;
317
318 rc = do_domctl(xch, &domctl);
319
320 if ( !rc )
321 *data = domctl.u.psr_cat_op.data;
322
323 return rc;
324 }
325
xc_psr_cat_get_info(xc_interface * xch,uint32_t socket,unsigned int lvl,uint32_t * cos_max,uint32_t * cbm_len,bool * cdp_enabled)326 int xc_psr_cat_get_info(xc_interface *xch, uint32_t socket, unsigned int lvl,
327 uint32_t *cos_max, uint32_t *cbm_len, bool *cdp_enabled)
328 {
329 int rc = -1;
330 DECLARE_SYSCTL;
331
332 sysctl.cmd = XEN_SYSCTL_psr_cat_op;
333 sysctl.u.psr_cat_op.target = socket;
334
335 switch ( lvl )
336 {
337 case 2:
338 sysctl.u.psr_cat_op.cmd = XEN_SYSCTL_PSR_CAT_get_l2_info;
339 rc = xc_sysctl(xch, &sysctl);
340 if ( !rc )
341 {
342 *cos_max = sysctl.u.psr_cat_op.u.cat_info.cos_max;
343 *cbm_len = sysctl.u.psr_cat_op.u.cat_info.cbm_len;
344 *cdp_enabled = false;
345 }
346 break;
347 case 3:
348 sysctl.u.psr_cat_op.cmd = XEN_SYSCTL_PSR_CAT_get_l3_info;
349 rc = xc_sysctl(xch, &sysctl);
350 if ( !rc )
351 {
352 *cos_max = sysctl.u.psr_cat_op.u.cat_info.cos_max;
353 *cbm_len = sysctl.u.psr_cat_op.u.cat_info.cbm_len;
354 *cdp_enabled = sysctl.u.psr_cat_op.u.cat_info.flags &
355 XEN_SYSCTL_PSR_CAT_L3_CDP;
356 }
357 break;
358 default:
359 errno = EOPNOTSUPP;
360 break;
361 }
362
363 return rc;
364 }
365
366 /*
367 * Local variables:
368 * mode: C
369 * c-file-style: "BSD"
370 * c-basic-offset: 4
371 * tab-width: 4
372 * indent-tabs-mode: nil
373 * End:
374 */
375