Print this page
cpuid for ARMv7

Split Close
Expand all
Collapse all
          --- old/usr/src/uts/armv7/os/cpuid.c
          +++ new/usr/src/uts/armv7/os/cpuid.c
↓ open down ↓ 3 lines elided ↑ open up ↑
   4    4   * You may only use this file in accordance with the terms of version
   5    5   * 1.0 of the CDDL.
   6    6   *
   7    7   * A full copy of the text of the CDDL should have accompanied this
   8    8   * source.  A copy of the CDDL is also available via the Internet at
   9    9   * http://www.illumos.org/license/CDDL.
  10   10   */
  11   11  
  12   12  /*
  13   13   * Copyright (c) 2014 Joyent, Inc.  All rights reserved.
       14 + * Copyright (c) 2015 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
  14   15   */
  15   16  
  16   17  #include <sys/cpuid_impl.h>
  17   18  #include <sys/param.h>
  18   19  #include <sys/bootconf.h>
  19   20  #include <vm/vm_dep.h>
  20   21  #include <sys/armv7_bsmf.h>
  21   22  
  22   23  /*
  23   24   * Handle classification and identification of ARM processors.
↓ open down ↓ 1 lines elided ↑ open up ↑
  25   26   * Currently we do a single pass which reads in information and asserts that the
  26   27   * basic information which we receive here matches what we'd expect and are able
  27   28   * to do everything that we need with this ARM CPU.
  28   29   *
  29   30   * TODO We'll eventually do another pass to make sure that we properly determine
  30   31   * the feature set to expose to userland.
  31   32   */
  32   33  
  33   34  static arm_cpuid_t cpuid_data0;
  34   35  
  35      -static void
  36      -cpuid_parse_stage(uint32_t line, uint32_t mask, uint32_t shift, int *out)
       36 +static uint32_t
       37 +extract(uint32_t line, uint32_t mask, uint32_t shift)
  37   38  {
  38      -        *out = (line & mask) >> shift;
       39 +        return ((line & mask) >> shift);
  39   40  }
  40   41  
  41   42  static void
  42   43  cpuid_fill_main(arm_cpuid_t *cpd)
  43   44  {
  44   45          cpd->ac_pfr[0] = arm_cpuid_pfr0();
  45   46          cpd->ac_pfr[1] = arm_cpuid_pfr1();
  46   47          cpd->ac_dfr = arm_cpuid_dfr0();
  47   48          cpd->ac_mmfr[0] = arm_cpuid_mmfr0();
  48   49          cpd->ac_mmfr[1] = arm_cpuid_mmfr1();
↓ open down ↓ 7 lines elided ↑ open up ↑
  56   57          cpd->ac_isar[5] = arm_cpuid_isar5();
  57   58  }
  58   59  
  59   60  static void
  60   61  cpuid_fill_fpu(arm_cpuid_t *cpd)
  61   62  {
  62   63          cpd->ac_mvfr[0] = arm_cpuid_mvfr0();
  63   64          cpd->ac_mvfr[1] = arm_cpuid_mvfr1();
  64   65  }
  65   66  
  66      -#define CACHE_LEN_MASK          0x003
  67      -#define CACHE_M_BIT             0x004
  68      -#define CACHE_ASSOC_MASK        0x038
  69      -#define CACHE_ASSOC_SHIFT       3
  70      -#define CACHE_SIZE_MASK         0x3c0
  71      -#define CACHE_SIZE_SHIFT        6
  72      -#define CACHE_COLOR_BIT         0x800
  73      -#define CACHE_MASK              0xfff
  74      -#define CACHE_DCACHE_SHIFT      12
  75      -#define CACHE_SEPARATE          0x1000000
       67 +#define CCSIDR_WT               0x80000000
       68 +#define CCSIDR_WB               0x40000000
       69 +#define CCSIDR_RA               0x20000000
       70 +#define CCSIDR_WA               0x10000000
       71 +#define CCSIDR_NUMSETS_MASK     0x0fffe000
       72 +#define CCSIDR_NUMSETS_SHIFT    13
       73 +#define CCSIDR_ASSOC_MASK       0x00001ff8
       74 +#define CCSIDR_ASSOC_SHIFT      3
       75 +#define CCSIDR_LINESIZE_MASK    0x00000007
       76 +#define CCSIDR_LINESIZE_SHIFT   0
       77 +
       78 +static void
       79 +cpuid_fill_onecache(arm_cpuid_t *cpd, int level, boolean_t icache)
       80 +{
       81 +        arm_cpuid_cache_t *cache = &cpd->ac_caches[icache][level];
       82 +        uint32_t ccsidr;
       83 +
       84 +        ccsidr = arm_cpuid_ccsidr(level, icache);
       85 +        cpd->ac_ccsidr[icache][level] = ccsidr;
       86 +
       87 +        cache->acc_exists = B_TRUE;
       88 +        cache->acc_wt = (ccsidr & CCSIDR_WT) == CCSIDR_WT;
       89 +        cache->acc_wb = (ccsidr & CCSIDR_WB) == CCSIDR_WB;
       90 +        cache->acc_ra = (ccsidr & CCSIDR_RA) == CCSIDR_RA;
       91 +        cache->acc_wa = (ccsidr & CCSIDR_WA) == CCSIDR_WA;
       92 +        cache->acc_sets = extract(ccsidr, CCSIDR_NUMSETS_MASK,
       93 +            CCSIDR_NUMSETS_SHIFT) + 1;
       94 +        cache->acc_assoc = extract(ccsidr, CCSIDR_ASSOC_MASK,
       95 +            CCSIDR_ASSOC_SHIFT) + 1;
       96 +        cache->acc_linesz = sizeof (uint32_t) << (extract(ccsidr,
       97 +            CCSIDR_LINESIZE_MASK, CCSIDR_LINESIZE_SHIFT) + 2);
  76   98  
  77   99  /*
  78      - * On ARMv6 the value of the cache size and the cache associativity depends on
  79      - * the value of the M bit, which modifies the value that's in the actual index.
      100 + * XXX?
      101 +#warning "set acc_size?"
  80  102   */
  81      -static uint32_t armv6_cpuid_cache_sizes[2][9] = {
  82      -        { 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000, 0x100000,
  83      -                0x20000 },
  84      -        { 0x300, 0x600, 0xc00, 0x1800, 0x3000, 0x6000, 0xc000, 0x18000,
  85      -                0x30000 }
  86      -};
  87      -
  88      -static int8_t armv6_cpuid_cache_assoc[2][9] = {
  89      -        { 1, 2, 4, 8, 16, 32, 64, 128 },
  90      -        { -1, 3, 6, 12, 24, 48, 96, 192 }
  91      -};
  92      -
  93      -static uint8_t armv6_cpuid_cache_linesz[] = {
  94      -        8,
  95      -        16,
  96      -        32,
  97      -        64
  98      -};
  99      -
 100      -static void
 101      -cpuid_fill_onecache(arm_cpuid_cache_t *accp, uint32_t val)
 102      -{
 103      -        int mbit, index, assoc;
 104      -
 105      -        mbit = (val & CACHE_M_BIT) != 0 ? 1 : 0;
 106      -        index = (val & CACHE_ASSOC_MASK) >> CACHE_ASSOC_SHIFT;
 107      -        assoc = armv6_cpuid_cache_assoc[mbit][index];
 108      -        if (assoc == -1) {
 109      -                accp->acc_exists = B_FALSE;
 110      -                return;
 111      -        }
 112      -        ASSERT(assoc > 0);
 113      -        accp->acc_assoc = assoc;
 114      -        accp->acc_rcolor = (val & CACHE_COLOR_BIT) == 0 ?
 115      -            B_FALSE : B_TRUE;
 116      -        index = val & CACHE_LEN_MASK;
 117      -        accp->acc_linesz = armv6_cpuid_cache_linesz[index];
 118      -        index = (val & CACHE_SIZE_MASK) >> CACHE_SIZE_SHIFT;
 119      -        accp->acc_size = armv6_cpuid_cache_sizes[mbit][index];
 120      -        accp->acc_exists = B_TRUE;
 121  103  }
 122  104  
 123  105  static void
 124  106  cpuid_fill_caches(arm_cpuid_t *cpd)
 125  107  {
 126      -        uint32_t val, icache, dcache;
      108 +        uint32_t erg, cwg;
      109 +        uint32_t l1ip;
      110 +        uint32_t ctr;
      111 +        uint32_t clidr;
      112 +        int level;
      113 +
      114 +        clidr = arm_cpuid_clidr();
      115 +        cpd->ac_clidr = clidr;
      116 +
      117 +        /* default all caches to not existing, and not unified */
      118 +        for (level = 0; level < 7; level++) {
      119 +                cpd->ac_caches[B_TRUE][level].acc_exists = B_FALSE;
      120 +                cpd->ac_caches[B_FALSE][level].acc_exists = B_FALSE;
      121 +                cpd->ac_caches[B_TRUE][level].acc_unified = B_FALSE;
      122 +                cpd->ac_caches[B_FALSE][level].acc_unified = B_FALSE;
      123 +        }
      124 +
      125 +        /* retrieve cache info for each level */
      126 +        for (level = 0; level < 7; level++) {
      127 +                arm_cpuid_cache_t *icache = &cpd->ac_caches[B_TRUE][level];
      128 +                arm_cpuid_cache_t *dcache = &cpd->ac_caches[B_FALSE][level];
      129 +                uint32_t ctype = (cpd->ac_clidr >> (3 * level)) & 0x7;
      130 +
      131 +                /* stop looking we find the first non-existent level */
      132 +                if (!ctype)
      133 +                        break;
      134 +
      135 +                switch (ctype) {
      136 +                case 1:
      137 +                        cpuid_fill_onecache(cpd, level, B_TRUE);
      138 +                        break;
      139 +                case 2:
      140 +                        cpuid_fill_onecache(cpd, level, B_FALSE);
      141 +                        break;
      142 +                case 3:
      143 +                        cpuid_fill_onecache(cpd, level, B_TRUE);
      144 +                        cpuid_fill_onecache(cpd, level, B_FALSE);
      145 +                        break;
      146 +                case 4:
      147 +                        cpuid_fill_onecache(cpd, level, B_FALSE);
      148 +                        dcache->acc_unified = B_TRUE;
      149 +                        break;
      150 +                default:
      151 +                        bop_panic("unsupported cache type");
      152 +                }
      153 +        }
      154 +
      155 +        /*
      156 +         * We require L1-I/D & L2-D.  Unified caches are OK as well.
      157 +         */
      158 +        if (!cpd->ac_caches[B_TRUE][0].acc_exists &&
      159 +            (!cpd->ac_caches[B_FALSE][0].acc_exists ||
      160 +            !cpd->ac_caches[B_FALSE][0].acc_unified))
      161 +                bop_panic("no L1 instructian cache detected");
      162 +
      163 +        if (!cpd->ac_caches[B_FALSE][1].acc_exists)
      164 +                bop_panic("no L2 data cache detected");
 127  165  
 128      -        val = arm_cpuid_ctr();
 129      -        icache = val & CACHE_MASK;
 130      -        cpuid_fill_onecache(&cpd->ac_icache, icache);
 131      -        dcache = (val >> CACHE_DCACHE_SHIFT) & CACHE_MASK;
 132      -        cpuid_fill_onecache(&cpd->ac_dcache, dcache);
 133      -
 134      -        if (val & CACHE_SEPARATE) {
 135      -                cpd->ac_unifiedl1 = B_FALSE;
 136      -        } else {
 137      -                cpd->ac_unifiedl1 = B_TRUE;
 138      -        }
 139      -
 140      -        armv7_bsmdep_l2cacheinfo();
 141      -        armv6_cachesz = cpd->ac_dcache.acc_size;
 142      -        armv6_cache_assoc = cpd->ac_dcache.acc_assoc;
      166 +        /*
      167 +         * set globals with cache size info
      168 +         */
      169 +        l2cache_sz = cpd->ac_caches[B_FALSE][1].acc_size;
      170 +        l2cache_linesz = cpd->ac_caches[B_FALSE][1].acc_linesz;
      171 +        l2cache_assoc = cpd->ac_caches[B_FALSE][1].acc_assoc;
 143  172  }
 144  173  
 145  174  
 146  175  /*
 147      - * There isn't a specific way to indicate that we're on ARMv6k. Instead what we
 148      - * need to do is go through and check for a few features that we know we're
 149      - * going to need.
 150      - *
 151      - * TODO This will have to be revisited with ARMv7 support
      176 + * We need to do is go through and check for a few features that we know
      177 + * we're going to need.
 152  178   */
 153  179  static void
 154  180  cpuid_verify(void)
 155  181  {
 156  182          arm_cpuid_mem_vmsa_t vmsa;
 157  183          arm_cpuid_mem_barrier_t barrier;
 158  184          int sync, syncf;
 159  185  
 160  186          arm_cpuid_t *cpd = &cpuid_data0;
 161  187  
 162      -        /* v6 vmsa */
 163      -        cpuid_parse_stage(cpd->ac_mmfr[0], ARM_CPUID_MMFR0_STATE0_MASK,
 164      -            ARM_CPUID_MMFR0_STATE0_SHIFT, (int *)&vmsa);
 165      -        /* TODO We might be able to support v6, but bcm2835+qvpb are this */
      188 +        /* v7 vmsa */
      189 +        vmsa = extract(cpd->ac_mmfr[0], ARM_CPUID_MMFR0_STATE0_MASK,
      190 +            ARM_CPUID_MMFR0_STATE0_SHIFT);
 166  191          if (vmsa != ARM_CPUID_MEM_VMSA_V7) {
 167  192                  bop_printf(NULL, "invalid vmsa setting, found 0x%x\n", vmsa);
 168  193                  bop_panic("unsupported cpu");
 169  194          }
 170  195  
 171  196          /* check for ISB, DSB, etc. in cp15 */
 172      -        cpuid_parse_stage(cpd->ac_mmfr[2], ARM_CPUID_MMFR2_STATE5_MASK,
 173      -            ARM_CPUID_MMFR2_STATE5_SHIFT, (int *)&barrier);
 174      -        if (barrier != ARM_CPUID_MEM_BARRIER_CP15 &&
 175      -            barrier != ARM_CPUID_MEM_BARRIER_INSTR) {
 176      -                bop_printf(NULL, "missing support for CP15 memory barriers\n");
      197 +        barrier = extract(cpd->ac_mmfr[2], ARM_CPUID_MMFR2_STATE5_MASK,
      198 +            ARM_CPUID_MMFR2_STATE5_SHIFT);
      199 +        if (barrier != ARM_CPUID_MEM_BARRIER_INSTR) {
      200 +                bop_printf(NULL, "missing support for memory barrier "
      201 +                    "instructions\n");
 177  202                  bop_panic("unsupported CPU");
 178  203          }
 179  204  
 180  205          /* synch prims */
 181      -        cpuid_parse_stage(cpd->ac_isar[4], ARM_CPUID_ISAR3_STATE3_SHIFT,
 182      -            ARM_CPUID_ISAR4_STATE5_SHIFT, (int *)&sync);
 183      -        cpuid_parse_stage(cpd->ac_isar[4], ARM_CPUID_ISAR4_STATE3_SHIFT,
 184      -            ARM_CPUID_ISAR4_STATE5_SHIFT, (int *)&syncf);
      206 +        sync = extract(cpd->ac_isar[3], ARM_CPUID_ISAR3_STATE3_SHIFT,
      207 +            ARM_CPUID_ISAR3_STATE3_SHIFT);
      208 +        syncf = extract(cpd->ac_isar[4], ARM_CPUID_ISAR4_STATE5_SHIFT,
      209 +            ARM_CPUID_ISAR4_STATE5_SHIFT);
 185  210          if (sync != 0x2 && syncf != 0x0) {
 186  211                  bop_printf(NULL, "unsupported synch primitives: sync,frac: "
 187  212                      "%x,%x\n", sync, syncf);
 188  213                  bop_panic("unsupported CPU");
 189  214          }
 190      -
 191      -        if (cpd->ac_icache.acc_exists == B_FALSE) {
 192      -                bop_printf(NULL, "icache not defined to exist\n");
 193      -                bop_panic("unsupported CPU");
 194      -        }
 195      -
 196      -        if (cpd->ac_dcache.acc_exists == B_FALSE) {
 197      -                bop_printf(NULL, "dcache not defined to exist\n");
 198      -                bop_panic("unsupported CPU");
 199      -        }
 200  215  }
 201  216  
 202  217  static void
 203  218  cpuid_valid_ident(uint32_t ident)
 204  219  {
 205  220          arm_cpuid_ident_arch_t arch;
 206  221  
 207  222          /*
 208      -         * We don't support stock ARMv6 or older.
      223 +         * We don't support anything older than ARMv7.
 209  224           */
 210  225          arch = (ident & ARM_CPUID_IDENT_ARCH_MASK) >>
 211  226              ARM_CPUID_IDENT_ARCH_SHIFT;
 212  227          if (arch != ARM_CPUID_IDENT_ARCH_CPUID) {
 213  228                  bop_printf(NULL, "encountered unsupported CPU arch: 0x%x",
 214  229                      arch);
 215  230                  bop_panic("unsupported CPU");
 216  231          }
 217  232  }
 218  233  
 219  234  static void
 220  235  cpuid_valid_fpident(uint32_t ident)
 221  236  {
 222  237          arm_cpuid_vfp_arch_t vfp;
 223  238  
 224      -        cpuid_parse_stage(ident, ARM_CPUID_VFP_ARCH_MASK,
 225      -            ARM_CPUID_VFP_ARCH_SHIFT, (int *)&vfp);
      239 +        vfp = extract(ident, ARM_CPUID_VFP_ARCH_MASK, ARM_CPUID_VFP_ARCH_SHIFT);
      240 +        // XXX: _V3_V2BASE? _V3_NOBASE? _V3_V3BASE?
 226  241          if (vfp != ARM_CPUID_VFP_ARCH_V2) {
 227  242                  bop_printf(NULL, "unsupported vfp version: %x\n", vfp);
 228  243                  bop_panic("unsupported CPU");
 229  244          }
 230  245  
 231  246          if ((ident & ARM_CPUID_VFP_SW_MASK) != 0) {
 232  247                  bop_printf(NULL, "encountered software-only vfp\n");
 233  248                  bop_panic("unsuppored CPU");
 234  249          }
 235  250  }
 236  251  void
 237  252  cpuid_setup(void)
 238  253  {
 239  254          arm_cpuid_t *cpd = &cpuid_data0;
 240  255  
 241      -        cpd->ac_ident = arm_cpuid_idreg();
      256 +        cpd->ac_ident = arm_cpuid_midr();
 242  257          cpuid_valid_ident(cpd->ac_ident);
 243  258          cpuid_fill_main(cpd);
 244  259  
 245  260          cpd->ac_fpident = arm_cpuid_vfpidreg();
 246  261          cpuid_valid_fpident(cpd->ac_fpident);
 247  262          cpuid_fill_fpu(cpd);
      263 +
 248  264          cpuid_fill_caches(cpd);
 249  265  
 250  266          cpuid_verify();
 251  267  }
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX