linux/arch/powerpc/platforms/wsp/scom_smp.c
<<
>>
Prefs
   1/*
   2 * SCOM support for A2 platforms
   3 *
   4 * Copyright 2007-2011 Benjamin Herrenschmidt, David Gibson,
   5 *                     Michael Ellerman, IBM Corp.
   6 *
   7 * This program is free software; you can redistribute it and/or
   8 * modify it under the terms of the GNU General Public License
   9 * as published by the Free Software Foundation; either version
  10 * 2 of the License, or (at your option) any later version.
  11 */
  12
  13#include <linux/cpumask.h>
  14#include <linux/io.h>
  15#include <linux/of.h>
  16#include <linux/spinlock.h>
  17#include <linux/types.h>
  18
  19#include <asm/cputhreads.h>
  20#include <asm/reg_a2.h>
  21#include <asm/scom.h>
  22#include <asm/udbg.h>
  23
  24#include "wsp.h"
  25
  26#define SCOM_RAMC               0x2a            /* Ram Command */
  27#define SCOM_RAMC_TGT1_EXT      0x80000000
  28#define SCOM_RAMC_SRC1_EXT      0x40000000
  29#define SCOM_RAMC_SRC2_EXT      0x20000000
  30#define SCOM_RAMC_SRC3_EXT      0x10000000
  31#define SCOM_RAMC_ENABLE        0x00080000
  32#define SCOM_RAMC_THREADSEL     0x00060000
  33#define SCOM_RAMC_EXECUTE       0x00010000
  34#define SCOM_RAMC_MSR_OVERRIDE  0x00008000
  35#define SCOM_RAMC_MSR_PR        0x00004000
  36#define SCOM_RAMC_MSR_GS        0x00002000
  37#define SCOM_RAMC_FORCE         0x00001000
  38#define SCOM_RAMC_FLUSH         0x00000800
  39#define SCOM_RAMC_INTERRUPT     0x00000004
  40#define SCOM_RAMC_ERROR         0x00000002
  41#define SCOM_RAMC_DONE          0x00000001
  42#define SCOM_RAMI               0x29            /* Ram Instruction */
  43#define SCOM_RAMIC              0x28            /* Ram Instruction and Command */
  44#define SCOM_RAMIC_INSN         0xffffffff00000000
  45#define SCOM_RAMD               0x2d            /* Ram Data */
  46#define SCOM_RAMDH              0x2e            /* Ram Data High */
  47#define SCOM_RAMDL              0x2f            /* Ram Data Low */
  48#define SCOM_PCCR0              0x33            /* PC Configuration Register 0 */
  49#define SCOM_PCCR0_ENABLE_DEBUG 0x80000000
  50#define SCOM_PCCR0_ENABLE_RAM   0x40000000
  51#define SCOM_THRCTL             0x30            /* Thread Control and Status */
  52#define SCOM_THRCTL_T0_STOP     0x80000000
  53#define SCOM_THRCTL_T1_STOP     0x40000000
  54#define SCOM_THRCTL_T2_STOP     0x20000000
  55#define SCOM_THRCTL_T3_STOP     0x10000000
  56#define SCOM_THRCTL_T0_STEP     0x08000000
  57#define SCOM_THRCTL_T1_STEP     0x04000000
  58#define SCOM_THRCTL_T2_STEP     0x02000000
  59#define SCOM_THRCTL_T3_STEP     0x01000000
  60#define SCOM_THRCTL_T0_RUN      0x00800000
  61#define SCOM_THRCTL_T1_RUN      0x00400000
  62#define SCOM_THRCTL_T2_RUN      0x00200000
  63#define SCOM_THRCTL_T3_RUN      0x00100000
  64#define SCOM_THRCTL_T0_PM       0x00080000
  65#define SCOM_THRCTL_T1_PM       0x00040000
  66#define SCOM_THRCTL_T2_PM       0x00020000
  67#define SCOM_THRCTL_T3_PM       0x00010000
  68#define SCOM_THRCTL_T0_UDE      0x00008000
  69#define SCOM_THRCTL_T1_UDE      0x00004000
  70#define SCOM_THRCTL_T2_UDE      0x00002000
  71#define SCOM_THRCTL_T3_UDE      0x00001000
  72#define SCOM_THRCTL_ASYNC_DIS   0x00000800
  73#define SCOM_THRCTL_TB_DIS      0x00000400
  74#define SCOM_THRCTL_DEC_DIS     0x00000200
  75#define SCOM_THRCTL_AND         0x31            /* Thread Control and Status */
  76#define SCOM_THRCTL_OR          0x32            /* Thread Control and Status */
  77
  78
  79static DEFINE_PER_CPU(scom_map_t, scom_ptrs);
  80
  81static scom_map_t get_scom(int cpu, struct device_node *np, int *first_thread)
  82{
  83        scom_map_t scom = per_cpu(scom_ptrs, cpu);
  84        int tcpu;
  85
  86        if (scom_map_ok(scom)) {
  87                *first_thread = 0;
  88                return scom;
  89        }
  90
  91        *first_thread = 1;
  92
  93        scom = scom_map_device(np, 0);
  94
  95        for (tcpu = cpu_first_thread_sibling(cpu);
  96             tcpu <= cpu_last_thread_sibling(cpu); tcpu++)
  97                per_cpu(scom_ptrs, tcpu) = scom;
  98
  99        /* Hack: for the boot core, this will actually get called on
 100         * the second thread up, not the first so our test above will
 101         * set first_thread incorrectly. */
 102        if (cpu_first_thread_sibling(cpu) == 0)
 103                *first_thread = 0;
 104
 105        return scom;
 106}
 107
 108static int a2_scom_ram(scom_map_t scom, int thread, u32 insn, int extmask)
 109{
 110        u64 cmd, mask, val;
 111        int n = 0;
 112
 113        cmd = ((u64)insn << 32) | (((u64)extmask & 0xf) << 28)
 114                | ((u64)thread << 17) | SCOM_RAMC_ENABLE | SCOM_RAMC_EXECUTE;
 115        mask = SCOM_RAMC_DONE | SCOM_RAMC_INTERRUPT | SCOM_RAMC_ERROR;
 116
 117        scom_write(scom, SCOM_RAMIC, cmd);
 118
 119        while (!((val = scom_read(scom, SCOM_RAMC)) & mask)) {
 120                pr_devel("Waiting on RAMC = 0x%llx\n", val);
 121                if (++n == 3) {
 122                        pr_err("RAMC timeout on instruction 0x%08x, thread %d\n",
 123                               insn, thread);
 124                        return -1;
 125                }
 126        }
 127
 128        if (val & SCOM_RAMC_INTERRUPT) {
 129                pr_err("RAMC interrupt on instruction 0x%08x, thread %d\n",
 130                       insn, thread);
 131                return -SCOM_RAMC_INTERRUPT;
 132        }
 133
 134        if (val & SCOM_RAMC_ERROR) {
 135                pr_err("RAMC error on instruction 0x%08x, thread %d\n",
 136                       insn, thread);
 137                return -SCOM_RAMC_ERROR;
 138        }
 139
 140        return 0;
 141}
 142
 143static int a2_scom_getgpr(scom_map_t scom, int thread, int gpr, int alt,
 144                          u64 *out_gpr)
 145{
 146        int rc;
 147
 148        /* or rN, rN, rN */
 149        u32 insn = 0x7c000378 | (gpr << 21) | (gpr << 16) | (gpr << 11);
 150        rc = a2_scom_ram(scom, thread, insn, alt ? 0xf : 0x0);
 151        if (rc)
 152                return rc;
 153
 154        *out_gpr = scom_read(scom, SCOM_RAMD);
 155
 156        return 0;
 157}
 158
 159static int a2_scom_getspr(scom_map_t scom, int thread, int spr, u64 *out_spr)
 160{
 161        int rc, sprhi, sprlo;
 162        u32 insn;
 163
 164        sprhi = spr >> 5;
 165        sprlo = spr & 0x1f;
 166        insn = 0x7c2002a6 | (sprlo << 16) | (sprhi << 11); /* mfspr r1,spr */
 167
 168        if (spr == 0x0ff0)
 169                insn = 0x7c2000a6; /* mfmsr r1 */
 170
 171        rc = a2_scom_ram(scom, thread, insn, 0xf);
 172        if (rc)
 173                return rc;
 174        return a2_scom_getgpr(scom, thread, 1, 1, out_spr);
 175}
 176
 177static int a2_scom_setgpr(scom_map_t scom, int thread, int gpr,
 178                          int alt, u64 val)
 179{
 180        u32 lis = 0x3c000000 | (gpr << 21);
 181        u32 li = 0x38000000 | (gpr << 21);
 182        u32 oris = 0x64000000 | (gpr << 21) | (gpr << 16);
 183        u32 ori = 0x60000000 | (gpr << 21) | (gpr << 16);
 184        u32 rldicr32 = 0x780007c6 | (gpr << 21) | (gpr << 16);
 185        u32 highest = val >> 48;
 186        u32 higher = (val >> 32) & 0xffff;
 187        u32 high = (val >> 16) & 0xffff;
 188        u32 low = val & 0xffff;
 189        int lext = alt ? 0x8 : 0x0;
 190        int oext = alt ? 0xf : 0x0;
 191        int rc = 0;
 192
 193        if (highest)
 194                rc |= a2_scom_ram(scom, thread, lis | highest, lext);
 195
 196        if (higher) {
 197                if (highest)
 198                        rc |= a2_scom_ram(scom, thread, oris | higher, oext);
 199                else
 200                        rc |= a2_scom_ram(scom, thread, li | higher, lext);
 201        }
 202
 203        if (highest || higher)
 204                rc |= a2_scom_ram(scom, thread, rldicr32, oext);
 205
 206        if (high) {
 207                if (highest || higher)
 208                        rc |= a2_scom_ram(scom, thread, oris | high, oext);
 209                else
 210                        rc |= a2_scom_ram(scom, thread, lis | high, lext);
 211        }
 212
 213        if (highest || higher || high)
 214                rc |= a2_scom_ram(scom, thread, ori | low, oext);
 215        else
 216                rc |= a2_scom_ram(scom, thread, li | low, lext);
 217
 218        return rc;
 219}
 220
 221static int a2_scom_setspr(scom_map_t scom, int thread, int spr, u64 val)
 222{
 223        int sprhi = spr >> 5;
 224        int sprlo = spr & 0x1f;
 225        /* mtspr spr, r1 */
 226        u32 insn = 0x7c2003a6 | (sprlo << 16) | (sprhi << 11);
 227
 228        if (spr == 0x0ff0)
 229                insn = 0x7c200124; /* mtmsr r1 */
 230
 231        if (a2_scom_setgpr(scom, thread, 1, 1, val))
 232                return -1;
 233
 234        return a2_scom_ram(scom, thread, insn, 0xf);
 235}
 236
 237static int a2_scom_initial_tlb(scom_map_t scom, int thread)
 238{
 239        extern u32 a2_tlbinit_code_start[], a2_tlbinit_code_end[];
 240        extern u32 a2_tlbinit_after_iprot_flush[];
 241        extern u32 a2_tlbinit_after_linear_map[];
 242        u32 assoc, entries, i;
 243        u64 epn, tlbcfg;
 244        u32 *p;
 245        int rc;
 246
 247        /* Invalidate all entries (including iprot) */
 248
 249        rc = a2_scom_getspr(scom, thread, SPRN_TLB0CFG, &tlbcfg);
 250        if (rc)
 251                goto scom_fail;
 252        entries = tlbcfg & TLBnCFG_N_ENTRY;
 253        assoc = (tlbcfg & TLBnCFG_ASSOC) >> 24;
 254        epn = 0;
 255
 256        /* Set MMUCR2 to enable 4K, 64K, 1M, 16M and 1G pages */
 257        a2_scom_setspr(scom, thread, SPRN_MMUCR2, 0x000a7531);
 258        /* Set MMUCR3 to write all thids bit to the TLB */
 259        a2_scom_setspr(scom, thread, SPRN_MMUCR3, 0x0000000f);
 260
 261        /* Set MAS1 for 1G page size, and MAS2 to our initial EPN */
 262        a2_scom_setspr(scom, thread, SPRN_MAS1, MAS1_TSIZE(BOOK3E_PAGESZ_1GB));
 263        a2_scom_setspr(scom, thread, SPRN_MAS2, epn);
 264        for (i = 0; i < entries; i++) {
 265
 266                a2_scom_setspr(scom, thread, SPRN_MAS0, MAS0_ESEL(i % assoc));
 267
 268                /* tlbwe */
 269                rc = a2_scom_ram(scom, thread, 0x7c0007a4, 0);
 270                if (rc)
 271                        goto scom_fail;
 272
 273                /* Next entry is new address? */
 274                if((i + 1) % assoc == 0) {
 275                        epn += (1 << 30);
 276                        a2_scom_setspr(scom, thread, SPRN_MAS2, epn);
 277                }
 278        }
 279
 280        /* Setup args for linear mapping */
 281        rc = a2_scom_setgpr(scom, thread, 3, 0, MAS0_TLBSEL(0));
 282        if (rc)
 283                goto scom_fail;
 284
 285        /* Linear mapping */
 286        for (p = a2_tlbinit_code_start; p < a2_tlbinit_after_linear_map; p++) {
 287                rc = a2_scom_ram(scom, thread, *p, 0);
 288                if (rc)
 289                        goto scom_fail;
 290        }
 291
 292        /*
 293         * For the boot thread, between the linear mapping and the debug
 294         * mappings there is a loop to flush iprot mappings. Ramming doesn't do
 295         * branches, but the secondary threads don't need to be nearly as smart
 296         * (i.e. we don't need to worry about invalidating the mapping we're
 297         * standing on).
 298         */
 299
 300        /* Debug mappings. Expects r11 = MAS0 from linear map (set above) */
 301        for (p = a2_tlbinit_after_iprot_flush; p < a2_tlbinit_code_end; p++) {
 302                rc = a2_scom_ram(scom, thread, *p, 0);
 303                if (rc)
 304                        goto scom_fail;
 305        }
 306
 307scom_fail:
 308        if (rc)
 309                pr_err("Setting up initial TLB failed, err %d\n", rc);
 310
 311        if (rc == -SCOM_RAMC_INTERRUPT) {
 312                /* Interrupt, dump some status */
 313                int rc[10];
 314                u64 iar, srr0, srr1, esr, mas0, mas1, mas2, mas7_3, mas8, ccr2;
 315                rc[0] = a2_scom_getspr(scom, thread, SPRN_IAR, &iar);
 316                rc[1] = a2_scom_getspr(scom, thread, SPRN_SRR0, &srr0);
 317                rc[2] = a2_scom_getspr(scom, thread, SPRN_SRR1, &srr1);
 318                rc[3] = a2_scom_getspr(scom, thread, SPRN_ESR, &esr);
 319                rc[4] = a2_scom_getspr(scom, thread, SPRN_MAS0, &mas0);
 320                rc[5] = a2_scom_getspr(scom, thread, SPRN_MAS1, &mas1);
 321                rc[6] = a2_scom_getspr(scom, thread, SPRN_MAS2, &mas2);
 322                rc[7] = a2_scom_getspr(scom, thread, SPRN_MAS7_MAS3, &mas7_3);
 323                rc[8] = a2_scom_getspr(scom, thread, SPRN_MAS8, &mas8);
 324                rc[9] = a2_scom_getspr(scom, thread, SPRN_A2_CCR2, &ccr2);
 325                pr_err(" -> retreived IAR =0x%llx (err %d)\n", iar, rc[0]);
 326                pr_err("    retreived SRR0=0x%llx (err %d)\n", srr0, rc[1]);
 327                pr_err("    retreived SRR1=0x%llx (err %d)\n", srr1, rc[2]);
 328                pr_err("    retreived ESR =0x%llx (err %d)\n", esr, rc[3]);
 329                pr_err("    retreived MAS0=0x%llx (err %d)\n", mas0, rc[4]);
 330                pr_err("    retreived MAS1=0x%llx (err %d)\n", mas1, rc[5]);
 331                pr_err("    retreived MAS2=0x%llx (err %d)\n", mas2, rc[6]);
 332                pr_err("    retreived MS73=0x%llx (err %d)\n", mas7_3, rc[7]);
 333                pr_err("    retreived MAS8=0x%llx (err %d)\n", mas8, rc[8]);
 334                pr_err("    retreived CCR2=0x%llx (err %d)\n", ccr2, rc[9]);
 335        }
 336
 337        return rc;
 338}
 339
 340int __devinit a2_scom_startup_cpu(unsigned int lcpu, int thr_idx,
 341                                  struct device_node *np)
 342{
 343        u64 init_iar, init_msr, init_ccr2;
 344        unsigned long start_here;
 345        int rc, core_setup;
 346        scom_map_t scom;
 347        u64 pccr0;
 348
 349        scom = get_scom(lcpu, np, &core_setup);
 350        if (!scom) {
 351                printk(KERN_ERR "Couldn't map SCOM for CPU%d\n", lcpu);
 352                return -1;
 353        }
 354
 355        pr_devel("Bringing up CPU%d using SCOM...\n", lcpu);
 356
 357        pccr0 = scom_read(scom, SCOM_PCCR0);
 358        scom_write(scom, SCOM_PCCR0, pccr0 | SCOM_PCCR0_ENABLE_DEBUG |
 359                                     SCOM_PCCR0_ENABLE_RAM);
 360
 361        /* Stop the thead with THRCTL. If we are setting up the TLB we stop all
 362         * threads. We also disable asynchronous interrupts while RAMing.
 363         */
 364        if (core_setup)
 365                scom_write(scom, SCOM_THRCTL_OR,
 366                              SCOM_THRCTL_T0_STOP |
 367                              SCOM_THRCTL_T1_STOP |
 368                              SCOM_THRCTL_T2_STOP |
 369                              SCOM_THRCTL_T3_STOP |
 370                              SCOM_THRCTL_ASYNC_DIS);
 371        else
 372                scom_write(scom, SCOM_THRCTL_OR, SCOM_THRCTL_T0_STOP >> thr_idx);
 373
 374        /* Flush its pipeline just in case */
 375        scom_write(scom, SCOM_RAMC, ((u64)thr_idx << 17) |
 376                      SCOM_RAMC_FLUSH | SCOM_RAMC_ENABLE);
 377
 378        a2_scom_getspr(scom, thr_idx, SPRN_IAR, &init_iar);
 379        a2_scom_getspr(scom, thr_idx, 0x0ff0, &init_msr);
 380        a2_scom_getspr(scom, thr_idx, SPRN_A2_CCR2, &init_ccr2);
 381
 382        /* Set MSR to MSR_CM (0x0ff0 is magic value for MSR_CM) */
 383        rc = a2_scom_setspr(scom, thr_idx, 0x0ff0, MSR_CM);
 384        if (rc) {
 385                pr_err("Failed to set MSR ! err %d\n", rc);
 386                return rc;
 387        }
 388
 389        /* RAM in an sync/isync for the sake of it */
 390        a2_scom_ram(scom, thr_idx, 0x7c0004ac, 0);
 391        a2_scom_ram(scom, thr_idx, 0x4c00012c, 0);
 392
 393        if (core_setup) {
 394                pr_devel("CPU%d is first thread in core, initializing TLB...\n",
 395                         lcpu);
 396                rc = a2_scom_initial_tlb(scom, thr_idx);
 397                if (rc)
 398                        goto fail;
 399        }
 400
 401        start_here = *(unsigned long *)(core_setup ? generic_secondary_smp_init
 402                                        : generic_secondary_thread_init);
 403        pr_devel("CPU%d entry point at 0x%lx...\n", lcpu, start_here);
 404
 405        rc |= a2_scom_setspr(scom, thr_idx, SPRN_IAR, start_here);
 406        rc |= a2_scom_setgpr(scom, thr_idx, 3, 0,
 407                             get_hard_smp_processor_id(lcpu));
 408        /*
 409         * Tell book3e_secondary_core_init not to set up the TLB, we've
 410         * already done that.
 411         */
 412        rc |= a2_scom_setgpr(scom, thr_idx, 4, 0, 1);
 413
 414        rc |= a2_scom_setspr(scom, thr_idx, SPRN_TENS, 0x1 << thr_idx);
 415
 416        scom_write(scom, SCOM_RAMC, 0);
 417        scom_write(scom, SCOM_THRCTL_AND, ~(SCOM_THRCTL_T0_STOP >> thr_idx));
 418        scom_write(scom, SCOM_PCCR0, pccr0);
 419fail:
 420        pr_devel("  SCOM initialization %s\n", rc ? "failed" : "succeeded");
 421        if (rc) {
 422                pr_err("Old IAR=0x%08llx MSR=0x%08llx CCR2=0x%08llx\n",
 423                       init_iar, init_msr, init_ccr2);
 424        }
 425
 426        return rc;
 427}
 428