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