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