From: Chao Peng <chao.p.peng@linux.intel.com>
To: xen-devel@lists.xen.org
Cc: keir@xen.org, Ian.Campbell@citrix.com,
stefano.stabellini@eu.citrix.com, andrew.cooper3@citrix.com,
dario.faggioli@citrix.com, Ian.Jackson@eu.citrix.com,
will.auld@intel.com, JBeulich@suse.com, wei.liu2@citrix.com,
dgdegra@tycho.nsa.gov
Subject: [PATCH v9 06/13] x86: dynamically get/set CBM for a domain
Date: Wed, 3 Jun 2015 12:53:03 +0800 [thread overview]
Message-ID: <1433307190-6381-7-git-send-email-chao.p.peng@linux.intel.com> (raw)
In-Reply-To: <1433307190-6381-1-git-send-email-chao.p.peng@linux.intel.com>
For CAT, COS is maintained in hypervisor only while CBM is exposed to
user space directly to allow getting/setting domain's cache capacity.
For each specified CBM, hypervisor will either use a existed COS which
has the same CBM or allocate a new one if the same CBM is not found. If
the allocation fails because of no enough COS available then error is
returned. The getting/setting are always operated on a specified socket.
For multiple sockets system, the interface may be called several times.
Signed-off-by: Chao Peng <chao.p.peng@linux.intel.com>
Reviewed-by: Dario Faggioli <dario.faggioli@citrix.com>
Acked-by: Jan Beulich <jbeulich@suse.com>
---
Changes in v9:
* Initialize 'info' explictly so that compiler would not complain.
* Simplify the code and remove multiple return points.
* Remove confused comment for 'target'.
* Add an additional check for cbm to make sure at least one bit is set(which is required).
Changes in v8:
* Add likely for 'socket < nr_sockets' in get_socket_cpu.
Changes in v7:
* find => found in psr_set_l3_cbm().
Changes in v6:
* Correct spin_lock scope.
Changes in v5:
* Add spin_lock to protect cbm_map.
---
xen/arch/x86/domctl.c | 20 ++++++
xen/arch/x86/psr.c | 139 ++++++++++++++++++++++++++++++++++++++++
xen/include/asm-x86/msr-index.h | 1 +
xen/include/asm-x86/psr.h | 2 +
xen/include/public/domctl.h | 12 ++++
5 files changed, 174 insertions(+)
diff --git a/xen/arch/x86/domctl.c b/xen/arch/x86/domctl.c
index e9f76d0..84baec0 100644
--- a/xen/arch/x86/domctl.c
+++ b/xen/arch/x86/domctl.c
@@ -1130,6 +1130,26 @@ long arch_do_domctl(
}
break;
+ case XEN_DOMCTL_psr_cat_op:
+ switch ( domctl->u.psr_cat_op.cmd )
+ {
+ case XEN_DOMCTL_PSR_CAT_OP_SET_L3_CBM:
+ ret = psr_set_l3_cbm(d, domctl->u.psr_cat_op.target,
+ domctl->u.psr_cat_op.data);
+ break;
+
+ case XEN_DOMCTL_PSR_CAT_OP_GET_L3_CBM:
+ ret = psr_get_l3_cbm(d, domctl->u.psr_cat_op.target,
+ &domctl->u.psr_cat_op.data);
+ copyback = 1;
+ break;
+
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+ break;
+
default:
ret = iommu_do_domctl(domctl, d, u_domctl);
break;
diff --git a/xen/arch/x86/psr.c b/xen/arch/x86/psr.c
index 10c4cdd..fce5bca 100644
--- a/xen/arch/x86/psr.c
+++ b/xen/arch/x86/psr.c
@@ -48,6 +48,14 @@ static unsigned int __read_mostly opt_cos_max = 255;
static uint64_t rmid_mask;
static DEFINE_PER_CPU(struct psr_assoc, psr_assoc);
+static unsigned int get_socket_cpu(unsigned int socket)
+{
+ if ( likely(socket < nr_sockets) )
+ return cpumask_any(socket_cpumask[socket]);
+
+ return nr_cpu_ids;
+}
+
static void __init parse_psr_bool(char *s, char *value, char *feature,
unsigned int mask)
{
@@ -248,6 +256,137 @@ int psr_get_cat_l3_info(unsigned int socket, uint32_t *cbm_len,
return ret;
}
+int psr_get_l3_cbm(struct domain *d, unsigned int socket, uint64_t *cbm)
+{
+ struct psr_cat_socket_info *info = NULL;
+ int ret = get_cat_socket_info(socket, &info);
+
+ if ( !ret )
+ *cbm = info->cos_to_cbm[d->arch.psr_cos_ids[socket]].cbm;
+
+ return ret;
+}
+
+static bool_t psr_check_cbm(unsigned int cbm_len, uint64_t cbm)
+{
+ unsigned int first_bit, zero_bit;
+
+ /* Set bits should only in the range of [0, cbm_len). */
+ if ( cbm & (~0ull << cbm_len) )
+ return 0;
+
+ /* At least one bit need to be set. */
+ if ( hweight_long(cbm) < 1 )
+ return 0;
+
+ first_bit = find_first_bit(&cbm, cbm_len);
+ zero_bit = find_next_zero_bit(&cbm, cbm_len, first_bit);
+
+ /* Set bits should be contiguous. */
+ if ( zero_bit < cbm_len &&
+ find_next_bit(&cbm, cbm_len, zero_bit) < cbm_len )
+ return 0;
+
+ return 1;
+}
+
+struct cos_cbm_info
+{
+ unsigned int cos;
+ uint64_t cbm;
+};
+
+static void do_write_l3_cbm(void *data)
+{
+ struct cos_cbm_info *info = data;
+
+ wrmsrl(MSR_IA32_PSR_L3_MASK(info->cos), info->cbm);
+}
+
+static int write_l3_cbm(unsigned int socket, unsigned int cos, uint64_t cbm)
+{
+ struct cos_cbm_info info = { .cos = cos, .cbm = cbm };
+
+ if ( socket == cpu_to_socket(smp_processor_id()) )
+ do_write_l3_cbm(&info);
+ else
+ {
+ unsigned int cpu = get_socket_cpu(socket);
+
+ if ( cpu >= nr_cpu_ids )
+ return -EBADSLT;
+ on_selected_cpus(cpumask_of(cpu), do_write_l3_cbm, &info, 1);
+ }
+
+ return 0;
+}
+
+int psr_set_l3_cbm(struct domain *d, unsigned int socket, uint64_t cbm)
+{
+ unsigned int old_cos, cos;
+ struct psr_cat_cbm *map, *found = NULL;
+ struct psr_cat_socket_info *info = NULL;
+ int ret = get_cat_socket_info(socket, &info);
+
+ if ( ret )
+ return ret;
+
+ if ( !psr_check_cbm(info->cbm_len, cbm) )
+ return -EINVAL;
+
+ old_cos = d->arch.psr_cos_ids[socket];
+ map = info->cos_to_cbm;
+
+ spin_lock(&info->cbm_lock);
+
+ for ( cos = 0; cos <= info->cos_max; cos++ )
+ {
+ /* If still not found, then keep unused one. */
+ if ( !found && cos != 0 && map[cos].ref == 0 )
+ found = map + cos;
+ else if ( map[cos].cbm == cbm )
+ {
+ if ( unlikely(cos == old_cos) )
+ {
+ spin_unlock(&info->cbm_lock);
+ return 0;
+ }
+ found = map + cos;
+ break;
+ }
+ }
+
+ /* If old cos is referred only by the domain, then use it. */
+ if ( !found && map[old_cos].ref == 1 )
+ found = map + old_cos;
+
+ if ( !found )
+ {
+ spin_unlock(&info->cbm_lock);
+ return -EUSERS;
+ }
+
+ cos = found - map;
+ if ( found->cbm != cbm )
+ {
+ ret = write_l3_cbm(socket, cos, cbm);
+ if ( ret )
+ {
+ spin_unlock(&info->cbm_lock);
+ return ret;
+ }
+ found->cbm = cbm;
+ }
+
+ found->ref++;
+ map[old_cos].ref--;
+ spin_unlock(&info->cbm_lock);
+
+ d->arch.psr_cos_ids[socket] = cos;
+
+ return 0;
+}
+
/* Called with domain lock held, no extra lock needed for 'psr_cos_ids' */
static void psr_free_cos(struct domain *d)
{
diff --git a/xen/include/asm-x86/msr-index.h b/xen/include/asm-x86/msr-index.h
index 83f2f70..5425f77 100644
--- a/xen/include/asm-x86/msr-index.h
+++ b/xen/include/asm-x86/msr-index.h
@@ -327,6 +327,7 @@
#define MSR_IA32_CMT_EVTSEL 0x00000c8d
#define MSR_IA32_CMT_CTR 0x00000c8e
#define MSR_IA32_PSR_ASSOC 0x00000c8f
+#define MSR_IA32_PSR_L3_MASK(n) (0x00000c90 + (n))
/* Intel Model 6 */
#define MSR_P6_PERFCTR(n) (0x000000c1 + (n))
diff --git a/xen/include/asm-x86/psr.h b/xen/include/asm-x86/psr.h
index d364e8c..081750f 100644
--- a/xen/include/asm-x86/psr.h
+++ b/xen/include/asm-x86/psr.h
@@ -53,6 +53,8 @@ void psr_ctxt_switch_to(struct domain *d);
int psr_get_cat_l3_info(unsigned int socket, uint32_t *cbm_len,
uint32_t *cos_max);
+int psr_get_l3_cbm(struct domain *d, unsigned int socket, uint64_t *cbm);
+int psr_set_l3_cbm(struct domain *d, unsigned int socket, uint64_t cbm);
int psr_domain_init(struct domain *d);
void psr_domain_free(struct domain *d);
diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h
index 53cdf08..936cf3e 100644
--- a/xen/include/public/domctl.h
+++ b/xen/include/public/domctl.h
@@ -1039,6 +1039,16 @@ struct xen_domctl_monitor_op {
typedef struct xen_domctl__op xen_domctl_monitor_op_t;
DEFINE_XEN_GUEST_HANDLE(xen_domctl_monitor_op_t);
+struct xen_domctl_psr_cat_op {
+#define XEN_DOMCTL_PSR_CAT_OP_SET_L3_CBM 0
+#define XEN_DOMCTL_PSR_CAT_OP_GET_L3_CBM 1
+ uint32_t cmd; /* IN: XEN_DOMCTL_PSR_CAT_OP_* */
+ uint32_t target; /* IN */
+ uint64_t data; /* IN/OUT */
+};
+typedef struct xen_domctl_psr_cat_op xen_domctl_psr_cat_op_t;
+DEFINE_XEN_GUEST_HANDLE(xen_domctl_psr_cat_op_t);
+
struct xen_domctl {
uint32_t cmd;
#define XEN_DOMCTL_createdomain 1
@@ -1114,6 +1124,7 @@ struct xen_domctl {
#define XEN_DOMCTL_setvnumainfo 74
#define XEN_DOMCTL_psr_cmt_op 75
#define XEN_DOMCTL_monitor_op 77
+#define XEN_DOMCTL_psr_cat_op 78
#define XEN_DOMCTL_gdbsx_guestmemio 1000
#define XEN_DOMCTL_gdbsx_pausevcpu 1001
#define XEN_DOMCTL_gdbsx_unpausevcpu 1002
@@ -1175,6 +1186,7 @@ struct xen_domctl {
struct xen_domctl_vnuma vnuma;
struct xen_domctl_psr_cmt_op psr_cmt_op;
struct xen_domctl_monitor_op monitor_op;
+ struct xen_domctl_psr_cat_op psr_cat_op;
uint8_t pad[128];
} u;
};
--
1.9.1
next prev parent reply other threads:[~2015-06-03 4:53 UTC|newest]
Thread overview: 26+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-06-03 4:52 [PATCH v9 00/13] enable Cache Allocation Technology (CAT) for VMs Chao Peng
2015-06-03 4:52 ` [PATCH v9 01/13] x86: add socket_cpumask Chao Peng
2015-06-15 15:59 ` Jan Beulich
2015-06-03 4:52 ` [PATCH v9 02/13] x86: detect and initialize Intel CAT feature Chao Peng
2015-06-15 15:56 ` Jan Beulich
2015-06-03 4:53 ` [PATCH v9 03/13] x86: maintain COS to CBM mapping for each socket Chao Peng
2015-06-15 16:02 ` Jan Beulich
2015-06-23 7:08 ` Chao Peng
2015-06-23 8:27 ` Jan Beulich
2015-06-03 4:53 ` [PATCH v9 04/13] x86: add COS information for each domain Chao Peng
2015-06-16 6:55 ` Jan Beulich
2015-06-03 4:53 ` [PATCH v9 05/13] x86: expose CBM length and COS number information Chao Peng
2015-06-16 6:58 ` Jan Beulich
2015-06-03 4:53 ` Chao Peng [this message]
2015-06-16 7:08 ` [PATCH v9 06/13] x86: dynamically get/set CBM for a domain Jan Beulich
2015-06-23 7:19 ` Chao Peng
2015-06-23 8:35 ` Jan Beulich
2015-06-23 9:03 ` Chao Peng
2015-06-23 9:14 ` Jan Beulich
2015-06-03 4:53 ` [PATCH v9 07/13] x86: add scheduling support for Intel CAT Chao Peng
2015-06-03 4:53 ` [PATCH v9 08/13] xsm: add CAT related xsm policies Chao Peng
2015-06-03 4:53 ` [PATCH v9 09/13] tools/libxl: minor name changes for CMT commands Chao Peng
2015-06-03 4:53 ` [PATCH v9 10/13] tools/libxl: add command to show PSR hardware info Chao Peng
2015-06-03 4:53 ` [PATCH v9 11/13] tools/libxl: introduce some socket helpers Chao Peng
2015-06-03 4:53 ` [PATCH v9 12/13] tools: add tools support for Intel CAT Chao Peng
2015-06-03 4:53 ` [PATCH v9 13/13] docs: add xl-psr.markdown Chao Peng
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1433307190-6381-7-git-send-email-chao.p.peng@linux.intel.com \
--to=chao.p.peng@linux.intel.com \
--cc=Ian.Campbell@citrix.com \
--cc=Ian.Jackson@eu.citrix.com \
--cc=JBeulich@suse.com \
--cc=andrew.cooper3@citrix.com \
--cc=dario.faggioli@citrix.com \
--cc=dgdegra@tycho.nsa.gov \
--cc=keir@xen.org \
--cc=stefano.stabellini@eu.citrix.com \
--cc=wei.liu2@citrix.com \
--cc=will.auld@intel.com \
--cc=xen-devel@lists.xen.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).