[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] [PATCH 2/5] x86: Support enable/disable CDP dynamically and get CDP status



On 02/09/15 09:27, He Chen wrote:
>  cdp_enabled is added to CAT socket info to indicate CDP is on or off on
>  the socket and struct psr_cat_cbm is extended to support CDP operation.
>  IA32_L3_QOS_CFG is a new MSR to enable/disable L3 CDP, when enable or
>  disable CDP, all domains will reset to COS0 with fully access all L3
>  cache.
>
>  Signed-off-by: He Chen <he.chen@xxxxxxxxxxxxxxx>
> ---
>  xen/arch/x86/psr.c          | 164 
> ++++++++++++++++++++++++++++++++++++++++----
>  xen/arch/x86/sysctl.c       |   9 ++-
>  xen/include/asm-x86/psr.h   |  10 ++-
>  xen/include/public/sysctl.h |   5 ++
>  4 files changed, 174 insertions(+), 14 deletions(-)
>
> diff --git a/xen/arch/x86/psr.c b/xen/arch/x86/psr.c
> index b357816..26596dd 100644
> --- a/xen/arch/x86/psr.c
> +++ b/xen/arch/x86/psr.c
> @@ -17,13 +17,20 @@
>  #include <xen/cpu.h>
>  #include <xen/err.h>
>  #include <xen/sched.h>
> +#include <xen/domain.h>
>  #include <asm/psr.h>
>  
>  #define PSR_CMT        (1<<0)
>  #define PSR_CAT        (1<<1)
>  
>  struct psr_cat_cbm {
> -    uint64_t cbm;
> +    union {
> +        uint64_t cbm;
> +        struct {
> +            uint64_t code;
> +            uint64_t data;
> +        }cdp;
> +    }u;

Spaces after } please.

>      unsigned int ref;
>  };
>  
> @@ -32,6 +39,7 @@ struct psr_cat_socket_info {
>      unsigned int cos_max;
>      struct psr_cat_cbm *cos_to_cbm;
>      spinlock_t cbm_lock;
> +    bool_t cdp_enabled;
>  };
>  
>  struct psr_assoc {
> @@ -263,7 +271,7 @@ static struct psr_cat_socket_info 
> *get_cat_socket_info(unsigned int socket)
>  }
>  
>  int psr_get_cat_l3_info(unsigned int socket, uint32_t *cbm_len,
> -                        uint32_t *cos_max)
> +                        uint32_t *cos_max, uint8_t *cdp_enabled)

bool_t *cdp_enabled which...

>  {
>      struct psr_cat_socket_info *info = get_cat_socket_info(socket);
>  
> @@ -272,6 +280,7 @@ int psr_get_cat_l3_info(unsigned int socket, uint32_t 
> *cbm_len,
>  
>      *cbm_len = info->cbm_len;
>      *cos_max = info->cos_max;
> +    *cdp_enabled = (uint8_t)info->cdp_enabled;

... avoids this typecast.

>  
>      return 0;
>  }
> @@ -283,7 +292,7 @@ int psr_get_l3_cbm(struct domain *d, unsigned int socket, 
> uint64_t *cbm)
>      if ( IS_ERR(info) )
>          return PTR_ERR(info);
>  
> -    *cbm = info->cos_to_cbm[d->arch.psr_cos_ids[socket]].cbm;
> +    *cbm = info->cos_to_cbm[d->arch.psr_cos_ids[socket]].u.cbm;
>  
>      return 0;
>  }
> @@ -314,19 +323,33 @@ static bool_t psr_check_cbm(unsigned int cbm_len, 
> uint64_t cbm)
>  struct cos_cbm_info
>  {
>      unsigned int cos;
> -    uint64_t cbm;
> +    uint64_t cbm_code;
> +    uint64_t cbm_data;
> +    bool_t cdp_mode;

This should either be plain "cdp" which would be fine, or
"cdp_enabled".  The name "_mode" here is misleading.

>  };
>  
>  static void do_write_l3_cbm(void *data)
>  {
>      struct cos_cbm_info *info = data;
>  
> -    wrmsrl(MSR_IA32_PSR_L3_MASK(info->cos), info->cbm);
> +    if ( info->cdp_mode == 0 )
> +        wrmsrl(MSR_IA32_PSR_L3_MASK(info->cos), info->cbm_code);
> +    else
> +    {
> +        wrmsrl(MSR_IA32_PSR_L3_MASK(info->cos*2+1), info->cbm_code);
> +        wrmsrl(MSR_IA32_PSR_L3_MASK(info->cos*2), info->cbm_data);

Please introduce

MSR_IA32_PSR_L3_MASK_CBM_CODE()
MSR_IA32_PSR_L3_MASK_CBM_DATA()

to abstract away the  x * 2 + 1 calculation.

> +    }
>  }
>  
> -static int write_l3_cbm(unsigned int socket, unsigned int cos, uint64_t cbm)
> +static int write_l3_cbm(unsigned int socket, unsigned int cos,
> +                        uint64_t cbm_code, uint64_t cbm_data, bool_t 
> cdp_mode)
>  {
> -    struct cos_cbm_info info = { .cos = cos, .cbm = cbm };
> +    struct cos_cbm_info info =
> +    { .cos = cos,

Newline here please, so

{
    .cos

> +      .cbm_code = cbm_code,
> +      .cbm_data = cbm_data,
> +      .cdp_mode = cdp_mode,
> +    };
>  
>      if ( socket == cpu_to_socket(smp_processor_id()) )
>          do_write_l3_cbm(&info);
> @@ -364,7 +387,7 @@ int psr_set_l3_cbm(struct domain *d, unsigned int socket, 
> uint64_t cbm)
>          /* 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 )
> +        else if ( map[cos].u.cbm == cbm )
>          {
>              if ( unlikely(cos == old_cos) )
>              {
> @@ -388,16 +411,16 @@ int psr_set_l3_cbm(struct domain *d, unsigned int 
> socket, uint64_t cbm)
>      }
>  
>      cos = found - map;
> -    if ( found->cbm != cbm )
> +    if ( found->u.cbm != cbm )
>      {
> -        int ret = write_l3_cbm(socket, cos, cbm);
> +        int ret = write_l3_cbm(socket, cos, cbm, 0, 0);
>  
>          if ( ret )
>          {
>              spin_unlock(&info->cbm_lock);
>              return ret;
>          }
> -        found->cbm = cbm;
> +        found->u.cbm = cbm;
>      }
>  
>      found->ref++;
> @@ -491,7 +514,7 @@ static void cat_cpu_init(void)
>          info->cos_to_cbm = temp_cos_to_cbm;
>          temp_cos_to_cbm = NULL;
>          /* cos=0 is reserved as default cbm(all ones). */
> -        info->cos_to_cbm[0].cbm = (1ull << info->cbm_len) - 1;
> +        info->cos_to_cbm[0].u.cbm = (1ull << info->cbm_len) - 1;
>  
>          spin_lock_init(&info->cbm_lock);
>  
> @@ -556,6 +579,123 @@ static int psr_cpu_prepare(unsigned int cpu)
>      return cat_cpu_prepare(cpu);
>  }
>  
> +static void do_write_l3_config(void *data)
> +{
> +    uint64_t val;
> +    uint64_t *mask = data;
> +
> +    rdmsrl(PSR_L3_QOS_CFG, val);
> +    wrmsrl(PSR_L3_QOS_CFG, val | *mask);
> +}
> +
> +static int config_socket_l3_cdp(unsigned int socket, uint64_t cdp_mask)
> +{
> +    unsigned int cpu;
> +    uint64_t mask = cdp_mask;
> +
> +    if ( socket == cpu_to_socket(smp_processor_id()) )
> +        do_write_l3_config(&mask);
> +    else
> +    {
> +        cpu = get_socket_cpu(socket);
> +        if ( cpu >= nr_cpu_ids )
> +            return -ENOTSOCK;
> +        on_selected_cpus(cpumask_of(cpu), do_write_l3_config, &mask, 1);
> +    }
> +    return 0;
> +}
> +
> +int psr_cat_enable_cdp(void)
> +{
> +    int i, ret;
> +    struct psr_cat_socket_info *info;
> +    unsigned int socket;
> +    struct domain *d;
> +
> +    for_each_set_bit(socket, cat_socket_enable, nr_sockets)
> +    {
> +        ret = config_socket_l3_cdp(socket, 1 << PSR_L3_QOS_CDP_ENABLE_BIT);
> +        if ( ret )
> +            return ret;
> +
> +        info = cat_socket_info + socket;
> +        if (info->cdp_enabled)

Style.  spaces inside brakces.

> +            return 0;
> +
> +        /* Cut half of cos_max when CDP enabled */
> +        info->cos_max = info->cos_max / 2;
> +
> +        spin_lock(&info->cbm_lock);
> +
> +        /* Reset COS0 code CBM & data CBM for all domain */
> +        info->cos_to_cbm[0].u.cdp.code = (1ull << info->cbm_len) - 1;
> +        info->cos_to_cbm[0].u.cdp.data = (1ull << info->cbm_len) - 1;
> +
> +        for ( i = 0; i <= info->cos_max; i++ )
> +            info->cos_to_cbm[0].ref = 0;
> +
> +        /* Only write mask1 since mask0 is always all 1 by CAT. */
> +        ret = write_l3_cbm(socket, 1, info->cos_to_cbm[0].u.cdp.code, 0, 0);
> +        if ( ret )
> +        {
> +            spin_unlock(&info->cbm_lock);
> +            return ret;
> +        }
> +
> +        /* Reset all domain to COS0 */
> +        for_each_domain( d )
> +        {
> +            d->arch.psr_cos_ids[socket] = 0;
> +            info->cos_to_cbm[0].ref++;

This is a long running operation and must not be done synchronously like
this.  Unfortunately, it is not easy to make restartable.

I think it would be perfectly reasonable to have cdp as a boot time
switch only, and have no ability to change it at runtime.  I don't see a
reasonable case to change it dynamically at runtime; users will either
want to use it, or not.

Making this a boot-time choice (i.e. psr=cat,cdp) removes all of this
re-juggling logic, and simplifies things greatly.

Thoughts?

> +        }
> +
> +        spin_unlock(&info->cbm_lock);
> +        info->cdp_enabled = 1;
> +    }
> +
> +    return 0;
> +}
> +
> +int psr_cat_disable_cdp(void)
> +{
> +    int i, ret;
> +    struct psr_cat_socket_info *info;
> +    unsigned int socket;
> +    struct domain *d;
> +
> +    for_each_set_bit(socket, cat_socket_enable, nr_sockets)
> +    {
> +        ret = config_socket_l3_cdp(socket, 0 << PSR_L3_QOS_CDP_ENABLE_BIT);
> +        if ( ret )
> +            return ret;
> +
> +        info = cat_socket_info + socket;
> +        if( !info->cdp_enabled )
> +            return 0;
> +
> +        /* Restore CAT cos_max when CDP disabled */
> +        info->cos_max = info->cos_max * 2 + 1;
> +        spin_lock(&info->cbm_lock);
> +
> +        /* Reset all CBMs and set fully open COS0 for all domains */
> +        info->cos_to_cbm[0].u.cbm = (1ull << info->cbm_len) - 1;
> +        for ( i = 0; i <= info->cos_max; i++ )
> +            info->cos_to_cbm[i].ref = 0;
> +
> +        /* Reset all domains to COS0 */
> +        for_each_domain( d )
> +        {
> +            d->arch.psr_cos_ids[socket] = 0;
> +            info->cos_to_cbm[0].ref++;
> +        }
> +
> +        spin_unlock(&info->cbm_lock);
> +        info->cdp_enabled = 0;
> +    }
> +
> +    return 0;
> +}
> +
>  static void psr_cpu_init(void)
>  {
>      if ( cat_socket_info )
> diff --git a/xen/arch/x86/sysctl.c b/xen/arch/x86/sysctl.c
> index f36b52f..51b03a4 100644
> --- a/xen/arch/x86/sysctl.c
> +++ b/xen/arch/x86/sysctl.c
> @@ -177,12 +177,19 @@ long arch_do_sysctl(
>          case XEN_SYSCTL_PSR_CAT_get_l3_info:
>              ret = psr_get_cat_l3_info(sysctl->u.psr_cat_op.target,
>                                        
> &sysctl->u.psr_cat_op.u.l3_info.cbm_len,
> -                                      
> &sysctl->u.psr_cat_op.u.l3_info.cos_max);
> +                                      
> &sysctl->u.psr_cat_op.u.l3_info.cos_max,
> +                                      
> &sysctl->u.psr_cat_op.u.l3_info.cdp_enabled);
>  
>              if ( !ret && __copy_field_to_guest(u_sysctl, sysctl, 
> u.psr_cat_op) )
>                  ret = -EFAULT;
>  
>              break;
> +        case XEN_SYSCTL_PSR_CAT_enable_cdp:
> +            ret = psr_cat_enable_cdp();
> +            break;
> +        case XEN_SYSCTL_PSR_CAT_disable_cdp:
> +            ret = psr_cat_disable_cdp();
> +            break;

I realise you are copying the existing (incorrect) style, but please
introduce a blank line between break statements and the subsequent
case/default label.  It makes the switch statement far easier to read.

>          default:
>              ret = -EOPNOTSUPP;
>              break;
> diff --git a/xen/include/asm-x86/psr.h b/xen/include/asm-x86/psr.h
> index a6b83df..2b79a92 100644
> --- a/xen/include/asm-x86/psr.h
> +++ b/xen/include/asm-x86/psr.h
> @@ -30,6 +30,11 @@
>  /* CDP Capability */
>  #define PSR_CAT_CDP_CAPABILITY       0x4
>  
> +/* L3 QoS Config MSR Address */
> +#define PSR_L3_QOS_CFG           0xc81
> +
> +/* L3 CDP Enable bit*/
> +#define PSR_L3_QOS_CDP_ENABLE_BIT       0x0
>  
>  struct psr_cmt_l3 {
>      unsigned int features;
> @@ -56,13 +61,16 @@ void psr_free_rmid(struct domain *d);
>  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);
> +                        uint32_t *cos_max, uint8_t *cdp_enabled);
>  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);
>  
> +int psr_cat_enable_cdp(void);
> +int psr_cat_disable_cdp(void);
> +
>  #endif /* __ASM_PSR_H__ */
>  
>  /*
> diff --git a/xen/include/public/sysctl.h b/xen/include/public/sysctl.h
> index 58c9be2..8b97137 100644
> --- a/xen/include/public/sysctl.h
> +++ b/xen/include/public/sysctl.h
> @@ -697,6 +697,8 @@ typedef struct xen_sysctl_pcitopoinfo 
> xen_sysctl_pcitopoinfo_t;
>  DEFINE_XEN_GUEST_HANDLE(xen_sysctl_pcitopoinfo_t);
>  
>  #define XEN_SYSCTL_PSR_CAT_get_l3_info               0
> +#define XEN_SYSCTL_PSR_CAT_enable_cdp                1
> +#define XEN_SYSCTL_PSR_CAT_disable_cdp               2
>  struct xen_sysctl_psr_cat_op {
>      uint32_t cmd;       /* IN: XEN_SYSCTL_PSR_CAT_* */
>      uint32_t target;    /* IN */
> @@ -704,6 +706,9 @@ struct xen_sysctl_psr_cat_op {
>          struct {
>              uint32_t cbm_len;   /* OUT: CBM length */
>              uint32_t cos_max;   /* OUT: Maximum COS */
> +            #define XEN_SYSCTL_PSR_CDP_DISABLED      0
> +            #define XEN_SYSCTL_PSR_CDP_ENABLED       1
> +            uint8_t cdp_enabled;   /* OUT: CDP status */

Rather than using a whole 8 bits for a boolean, and leaving alignment
fun for the next person to edit this structure, may I recommend

#define XEN_SYSCTL_PSR_CAT_L3_CDP (1u << 0)
uint32_t flags;

Instead.  (Also assumes that in the future we might get CDP at the L4 cache)

~Andrew

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.