linux/arch/mips/include/asm/mips-cps.h
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2017 Imagination Technologies
   3 * Author: Paul Burton <paul.burton@mips.com>
   4 *
   5 * This program is free software; you can redistribute it and/or modify it
   6 * under the terms of the GNU General Public License as published by the
   7 * Free Software Foundation;  either version 2 of the  License, or (at your
   8 * option) any later version.
   9 */
  10
  11#ifndef __MIPS_ASM_MIPS_CPS_H__
  12#define __MIPS_ASM_MIPS_CPS_H__
  13
  14#include <linux/io.h>
  15#include <linux/types.h>
  16
  17extern unsigned long __cps_access_bad_size(void)
  18        __compiletime_error("Bad size for CPS accessor");
  19
  20#define CPS_ACCESSOR_A(unit, off, name)                                 \
  21static inline void *addr_##unit##_##name(void)                          \
  22{                                                                       \
  23        return mips_##unit##_base + (off);                              \
  24}
  25
  26#define CPS_ACCESSOR_R(unit, sz, name)                                  \
  27static inline uint##sz##_t read_##unit##_##name(void)                   \
  28{                                                                       \
  29        uint64_t val64;                                                 \
  30                                                                        \
  31        switch (sz) {                                                   \
  32        case 32:                                                        \
  33                return __raw_readl(addr_##unit##_##name());             \
  34                                                                        \
  35        case 64:                                                        \
  36                if (mips_cm_is64)                                       \
  37                        return __raw_readq(addr_##unit##_##name());     \
  38                                                                        \
  39                val64 = __raw_readl(addr_##unit##_##name() + 4);        \
  40                val64 <<= 32;                                           \
  41                val64 |= __raw_readl(addr_##unit##_##name());           \
  42                return val64;                                           \
  43                                                                        \
  44        default:                                                        \
  45                return __cps_access_bad_size();                         \
  46        }                                                               \
  47}
  48
  49#define CPS_ACCESSOR_W(unit, sz, name)                                  \
  50static inline void write_##unit##_##name(uint##sz##_t val)              \
  51{                                                                       \
  52        switch (sz) {                                                   \
  53        case 32:                                                        \
  54                __raw_writel(val, addr_##unit##_##name());              \
  55                break;                                                  \
  56                                                                        \
  57        case 64:                                                        \
  58                if (mips_cm_is64) {                                     \
  59                        __raw_writeq(val, addr_##unit##_##name());      \
  60                        break;                                          \
  61                }                                                       \
  62                                                                        \
  63                __raw_writel((uint64_t)val >> 32,                       \
  64                             addr_##unit##_##name() + 4);               \
  65                __raw_writel(val, addr_##unit##_##name());              \
  66                break;                                                  \
  67                                                                        \
  68        default:                                                        \
  69                __cps_access_bad_size();                                \
  70                break;                                                  \
  71        }                                                               \
  72}
  73
  74#define CPS_ACCESSOR_M(unit, sz, name)                                  \
  75static inline void change_##unit##_##name(uint##sz##_t mask,            \
  76                                          uint##sz##_t val)             \
  77{                                                                       \
  78        uint##sz##_t reg_val = read_##unit##_##name();                  \
  79        reg_val &= ~mask;                                               \
  80        reg_val |= val;                                                 \
  81        write_##unit##_##name(reg_val);                                 \
  82}                                                                       \
  83                                                                        \
  84static inline void set_##unit##_##name(uint##sz##_t val)                \
  85{                                                                       \
  86        change_##unit##_##name(val, val);                               \
  87}                                                                       \
  88                                                                        \
  89static inline void clear_##unit##_##name(uint##sz##_t val)              \
  90{                                                                       \
  91        change_##unit##_##name(val, 0);                                 \
  92}
  93
  94#define CPS_ACCESSOR_RO(unit, sz, off, name)                            \
  95        CPS_ACCESSOR_A(unit, off, name)                                 \
  96        CPS_ACCESSOR_R(unit, sz, name)
  97
  98#define CPS_ACCESSOR_WO(unit, sz, off, name)                            \
  99        CPS_ACCESSOR_A(unit, off, name)                                 \
 100        CPS_ACCESSOR_W(unit, sz, name)
 101
 102#define CPS_ACCESSOR_RW(unit, sz, off, name)                            \
 103        CPS_ACCESSOR_A(unit, off, name)                                 \
 104        CPS_ACCESSOR_R(unit, sz, name)                                  \
 105        CPS_ACCESSOR_W(unit, sz, name)                                  \
 106        CPS_ACCESSOR_M(unit, sz, name)
 107
 108#include <asm/mips-cm.h>
 109#include <asm/mips-cpc.h>
 110#include <asm/mips-gic.h>
 111
 112/**
 113 * mips_cps_numclusters - return the number of clusters present in the system
 114 *
 115 * Returns the number of clusters in the system.
 116 */
 117static inline unsigned int mips_cps_numclusters(void)
 118{
 119        unsigned int num_clusters;
 120
 121        if (mips_cm_revision() < CM_REV_CM3_5)
 122                return 1;
 123
 124        num_clusters = read_gcr_config() & CM_GCR_CONFIG_NUM_CLUSTERS;
 125        num_clusters >>= __ffs(CM_GCR_CONFIG_NUM_CLUSTERS);
 126        return num_clusters;
 127}
 128
 129/**
 130 * mips_cps_cluster_config - return (GCR|CPC)_CONFIG from a cluster
 131 * @cluster: the ID of the cluster whose config we want
 132 *
 133 * Read the value of GCR_CONFIG (or its CPC_CONFIG mirror) from a @cluster.
 134 *
 135 * Returns the value of GCR_CONFIG.
 136 */
 137static inline uint64_t mips_cps_cluster_config(unsigned int cluster)
 138{
 139        uint64_t config;
 140
 141        if (mips_cm_revision() < CM_REV_CM3_5) {
 142                /*
 143                 * Prior to CM 3.5 we don't have the notion of multiple
 144                 * clusters so we can trivially read the GCR_CONFIG register
 145                 * within this cluster.
 146                 */
 147                WARN_ON(cluster != 0);
 148                config = read_gcr_config();
 149        } else {
 150                /*
 151                 * From CM 3.5 onwards we read the CPC_CONFIG mirror of
 152                 * GCR_CONFIG via the redirect region, since the CPC is always
 153                 * powered up allowing us not to need to power up the CM.
 154                 */
 155                mips_cm_lock_other(cluster, 0, 0, CM_GCR_Cx_OTHER_BLOCK_GLOBAL);
 156                config = read_cpc_redir_config();
 157                mips_cm_unlock_other();
 158        }
 159
 160        return config;
 161}
 162
 163/**
 164 * mips_cps_numcores - return the number of cores present in a cluster
 165 * @cluster: the ID of the cluster whose core count we want
 166 *
 167 * Returns the value of the PCORES field of the GCR_CONFIG register plus 1, or
 168 * zero if no Coherence Manager is present.
 169 */
 170static inline unsigned int mips_cps_numcores(unsigned int cluster)
 171{
 172        if (!mips_cm_present())
 173                return 0;
 174
 175        /* Add one before masking to handle 0xff indicating no cores */
 176        return (mips_cps_cluster_config(cluster) + 1) & CM_GCR_CONFIG_PCORES;
 177}
 178
 179/**
 180 * mips_cps_numiocu - return the number of IOCUs present in a cluster
 181 * @cluster: the ID of the cluster whose IOCU count we want
 182 *
 183 * Returns the value of the NUMIOCU field of the GCR_CONFIG register, or zero
 184 * if no Coherence Manager is present.
 185 */
 186static inline unsigned int mips_cps_numiocu(unsigned int cluster)
 187{
 188        unsigned int num_iocu;
 189
 190        if (!mips_cm_present())
 191                return 0;
 192
 193        num_iocu = mips_cps_cluster_config(cluster) & CM_GCR_CONFIG_NUMIOCU;
 194        num_iocu >>= __ffs(CM_GCR_CONFIG_NUMIOCU);
 195        return num_iocu;
 196}
 197
 198/**
 199 * mips_cps_numvps - return the number of VPs (threads) supported by a core
 200 * @cluster: the ID of the cluster containing the core we want to examine
 201 * @core: the ID of the core whose VP count we want
 202 *
 203 * Returns the number of Virtual Processors (VPs, ie. hardware threads) that
 204 * are supported by the given @core in the given @cluster. If the core or the
 205 * kernel do not support hardware mutlti-threading this returns 1.
 206 */
 207static inline unsigned int mips_cps_numvps(unsigned int cluster, unsigned int core)
 208{
 209        unsigned int cfg;
 210
 211        if (!mips_cm_present())
 212                return 1;
 213
 214        if ((!IS_ENABLED(CONFIG_MIPS_MT_SMP) || !cpu_has_mipsmt)
 215                && (!IS_ENABLED(CONFIG_CPU_MIPSR6) || !cpu_has_vp))
 216                return 1;
 217
 218        mips_cm_lock_other(cluster, core, 0, CM_GCR_Cx_OTHER_BLOCK_LOCAL);
 219
 220        if (mips_cm_revision() < CM_REV_CM3_5) {
 221                /*
 222                 * Prior to CM 3.5 we can only have one cluster & don't have
 223                 * CPC_Cx_CONFIG, so we read GCR_Cx_CONFIG.
 224                 */
 225                cfg = read_gcr_co_config();
 226        } else {
 227                /*
 228                 * From CM 3.5 onwards we read CPC_Cx_CONFIG because the CPC is
 229                 * always powered, which allows us to not worry about powering
 230                 * up the cluster's CM here.
 231                 */
 232                cfg = read_cpc_co_config();
 233        }
 234
 235        mips_cm_unlock_other();
 236
 237        return (cfg + 1) & CM_GCR_Cx_CONFIG_PVPE;
 238}
 239
 240#endif /* __MIPS_ASM_MIPS_CPS_H__ */
 241