linux/drivers/bus/arm-cci.c
<<
>>
Prefs
   1/*
   2 * CCI cache coherent interconnect driver
   3 *
   4 * Copyright (C) 2013 ARM Ltd.
   5 * Author: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License version 2 as
   9 * published by the Free Software Foundation.
  10 *
  11 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
  12 * kind, whether express or implied; without even the implied warranty
  13 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 * GNU General Public License for more details.
  15 */
  16
  17#include <linux/arm-cci.h>
  18#include <linux/io.h>
  19#include <linux/module.h>
  20#include <linux/of_address.h>
  21#include <linux/slab.h>
  22
  23#include <asm/cacheflush.h>
  24#include <asm/smp_plat.h>
  25
  26#define CCI_PORT_CTRL           0x0
  27#define CCI_CTRL_STATUS         0xc
  28
  29#define CCI_ENABLE_SNOOP_REQ    0x1
  30#define CCI_ENABLE_DVM_REQ      0x2
  31#define CCI_ENABLE_REQ          (CCI_ENABLE_SNOOP_REQ | CCI_ENABLE_DVM_REQ)
  32
  33struct cci_nb_ports {
  34        unsigned int nb_ace;
  35        unsigned int nb_ace_lite;
  36};
  37
  38enum cci_ace_port_type {
  39        ACE_INVALID_PORT = 0x0,
  40        ACE_PORT,
  41        ACE_LITE_PORT,
  42};
  43
  44struct cci_ace_port {
  45        void __iomem *base;
  46        unsigned long phys;
  47        enum cci_ace_port_type type;
  48        struct device_node *dn;
  49};
  50
  51static struct cci_ace_port *ports;
  52static unsigned int nb_cci_ports;
  53
  54static void __iomem *cci_ctrl_base;
  55static unsigned long cci_ctrl_phys;
  56
  57struct cpu_port {
  58        u64 mpidr;
  59        u32 port;
  60};
  61
  62/*
  63 * Use the port MSB as valid flag, shift can be made dynamic
  64 * by computing number of bits required for port indexes.
  65 * Code disabling CCI cpu ports runs with D-cache invalidated
  66 * and SCTLR bit clear so data accesses must be kept to a minimum
  67 * to improve performance; for now shift is left static to
  68 * avoid one more data access while disabling the CCI port.
  69 */
  70#define PORT_VALID_SHIFT        31
  71#define PORT_VALID              (0x1 << PORT_VALID_SHIFT)
  72
  73static inline void init_cpu_port(struct cpu_port *port, u32 index, u64 mpidr)
  74{
  75        port->port = PORT_VALID | index;
  76        port->mpidr = mpidr;
  77}
  78
  79static inline bool cpu_port_is_valid(struct cpu_port *port)
  80{
  81        return !!(port->port & PORT_VALID);
  82}
  83
  84static inline bool cpu_port_match(struct cpu_port *port, u64 mpidr)
  85{
  86        return port->mpidr == (mpidr & MPIDR_HWID_BITMASK);
  87}
  88
  89static struct cpu_port cpu_port[NR_CPUS];
  90
  91/**
  92 * __cci_ace_get_port - Function to retrieve the port index connected to
  93 *                      a cpu or device.
  94 *
  95 * @dn: device node of the device to look-up
  96 * @type: port type
  97 *
  98 * Return value:
  99 *      - CCI port index if success
 100 *      - -ENODEV if failure
 101 */
 102static int __cci_ace_get_port(struct device_node *dn, int type)
 103{
 104        int i;
 105        bool ace_match;
 106        struct device_node *cci_portn;
 107
 108        cci_portn = of_parse_phandle(dn, "cci-control-port", 0);
 109        for (i = 0; i < nb_cci_ports; i++) {
 110                ace_match = ports[i].type == type;
 111                if (ace_match && cci_portn == ports[i].dn)
 112                        return i;
 113        }
 114        return -ENODEV;
 115}
 116
 117int cci_ace_get_port(struct device_node *dn)
 118{
 119        return __cci_ace_get_port(dn, ACE_LITE_PORT);
 120}
 121EXPORT_SYMBOL_GPL(cci_ace_get_port);
 122
 123static void __init cci_ace_init_ports(void)
 124{
 125        int port, ac, cpu;
 126        u64 hwid;
 127        const u32 *cell;
 128        struct device_node *cpun, *cpus;
 129
 130        cpus = of_find_node_by_path("/cpus");
 131        if (WARN(!cpus, "Missing cpus node, bailing out\n"))
 132                return;
 133
 134        if (WARN_ON(of_property_read_u32(cpus, "#address-cells", &ac)))
 135                ac = of_n_addr_cells(cpus);
 136
 137        /*
 138         * Port index look-up speeds up the function disabling ports by CPU,
 139         * since the logical to port index mapping is done once and does
 140         * not change after system boot.
 141         * The stashed index array is initialized for all possible CPUs
 142         * at probe time.
 143         */
 144        for_each_child_of_node(cpus, cpun) {
 145                if (of_node_cmp(cpun->type, "cpu"))
 146                        continue;
 147                cell = of_get_property(cpun, "reg", NULL);
 148                if (WARN(!cell, "%s: missing reg property\n", cpun->full_name))
 149                        continue;
 150
 151                hwid = of_read_number(cell, ac);
 152                cpu = get_logical_index(hwid & MPIDR_HWID_BITMASK);
 153
 154                if (cpu < 0 || !cpu_possible(cpu))
 155                        continue;
 156                port = __cci_ace_get_port(cpun, ACE_PORT);
 157                if (port < 0)
 158                        continue;
 159
 160                init_cpu_port(&cpu_port[cpu], port, cpu_logical_map(cpu));
 161        }
 162
 163        for_each_possible_cpu(cpu) {
 164                WARN(!cpu_port_is_valid(&cpu_port[cpu]),
 165                        "CPU %u does not have an associated CCI port\n",
 166                        cpu);
 167        }
 168}
 169/*
 170 * Functions to enable/disable a CCI interconnect slave port
 171 *
 172 * They are called by low-level power management code to disable slave
 173 * interfaces snoops and DVM broadcast.
 174 * Since they may execute with cache data allocation disabled and
 175 * after the caches have been cleaned and invalidated the functions provide
 176 * no explicit locking since they may run with D-cache disabled, so normal
 177 * cacheable kernel locks based on ldrex/strex may not work.
 178 * Locking has to be provided by BSP implementations to ensure proper
 179 * operations.
 180 */
 181
 182/**
 183 * cci_port_control() - function to control a CCI port
 184 *
 185 * @port: index of the port to setup
 186 * @enable: if true enables the port, if false disables it
 187 */
 188static void notrace cci_port_control(unsigned int port, bool enable)
 189{
 190        void __iomem *base = ports[port].base;
 191
 192        writel_relaxed(enable ? CCI_ENABLE_REQ : 0, base + CCI_PORT_CTRL);
 193        /*
 194         * This function is called from power down procedures
 195         * and must not execute any instruction that might
 196         * cause the processor to be put in a quiescent state
 197         * (eg wfi). Hence, cpu_relax() can not be added to this
 198         * read loop to optimize power, since it might hide possibly
 199         * disruptive operations.
 200         */
 201        while (readl_relaxed(cci_ctrl_base + CCI_CTRL_STATUS) & 0x1)
 202                        ;
 203}
 204
 205/**
 206 * cci_disable_port_by_cpu() - function to disable a CCI port by CPU
 207 *                             reference
 208 *
 209 * @mpidr: mpidr of the CPU whose CCI port should be disabled
 210 *
 211 * Disabling a CCI port for a CPU implies disabling the CCI port
 212 * controlling that CPU cluster. Code disabling CPU CCI ports
 213 * must make sure that the CPU running the code is the last active CPU
 214 * in the cluster ie all other CPUs are quiescent in a low power state.
 215 *
 216 * Return:
 217 *      0 on success
 218 *      -ENODEV on port look-up failure
 219 */
 220int notrace cci_disable_port_by_cpu(u64 mpidr)
 221{
 222        int cpu;
 223        bool is_valid;
 224        for (cpu = 0; cpu < nr_cpu_ids; cpu++) {
 225                is_valid = cpu_port_is_valid(&cpu_port[cpu]);
 226                if (is_valid && cpu_port_match(&cpu_port[cpu], mpidr)) {
 227                        cci_port_control(cpu_port[cpu].port, false);
 228                        return 0;
 229                }
 230        }
 231        return -ENODEV;
 232}
 233EXPORT_SYMBOL_GPL(cci_disable_port_by_cpu);
 234
 235/**
 236 * cci_enable_port_for_self() - enable a CCI port for calling CPU
 237 *
 238 * Enabling a CCI port for the calling CPU implies enabling the CCI
 239 * port controlling that CPU's cluster. Caller must make sure that the
 240 * CPU running the code is the first active CPU in the cluster and all
 241 * other CPUs are quiescent in a low power state  or waiting for this CPU
 242 * to complete the CCI initialization.
 243 *
 244 * Because this is called when the MMU is still off and with no stack,
 245 * the code must be position independent and ideally rely on callee
 246 * clobbered registers only.  To achieve this we must code this function
 247 * entirely in assembler.
 248 *
 249 * On success this returns with the proper CCI port enabled.  In case of
 250 * any failure this never returns as the inability to enable the CCI is
 251 * fatal and there is no possible recovery at this stage.
 252 */
 253asmlinkage void __naked cci_enable_port_for_self(void)
 254{
 255        asm volatile ("\n"
 256"       .arch armv7-a\n"
 257"       mrc     p15, 0, r0, c0, c0, 5   @ get MPIDR value \n"
 258"       and     r0, r0, #"__stringify(MPIDR_HWID_BITMASK)" \n"
 259"       adr     r1, 5f \n"
 260"       ldr     r2, [r1] \n"
 261"       add     r1, r1, r2              @ &cpu_port \n"
 262"       add     ip, r1, %[sizeof_cpu_port] \n"
 263
 264        /* Loop over the cpu_port array looking for a matching MPIDR */
 265"1:     ldr     r2, [r1, %[offsetof_cpu_port_mpidr_lsb]] \n"
 266"       cmp     r2, r0                  @ compare MPIDR \n"
 267"       bne     2f \n"
 268
 269        /* Found a match, now test port validity */
 270"       ldr     r3, [r1, %[offsetof_cpu_port_port]] \n"
 271"       tst     r3, #"__stringify(PORT_VALID)" \n"
 272"       bne     3f \n"
 273
 274        /* no match, loop with the next cpu_port entry */
 275"2:     add     r1, r1, %[sizeof_struct_cpu_port] \n"
 276"       cmp     r1, ip                  @ done? \n"
 277"       blo     1b \n"
 278
 279        /* CCI port not found -- cheaply try to stall this CPU */
 280"cci_port_not_found: \n"
 281"       wfi \n"
 282"       wfe \n"
 283"       b       cci_port_not_found \n"
 284
 285        /* Use matched port index to look up the corresponding ports entry */
 286"3:     bic     r3, r3, #"__stringify(PORT_VALID)" \n"
 287"       adr     r0, 6f \n"
 288"       ldmia   r0, {r1, r2} \n"
 289"       sub     r1, r1, r0              @ virt - phys \n"
 290"       ldr     r0, [r0, r2]            @ *(&ports) \n"
 291"       mov     r2, %[sizeof_struct_ace_port] \n"
 292"       mla     r0, r2, r3, r0          @ &ports[index] \n"
 293"       sub     r0, r0, r1              @ virt_to_phys() \n"
 294
 295        /* Enable the CCI port */
 296"       ldr     r0, [r0, %[offsetof_port_phys]] \n"
 297"       mov     r3, #"__stringify(CCI_ENABLE_REQ)" \n"
 298"       str     r3, [r0, #"__stringify(CCI_PORT_CTRL)"] \n"
 299
 300        /* poll the status reg for completion */
 301"       adr     r1, 7f \n"
 302"       ldr     r0, [r1] \n"
 303"       ldr     r0, [r0, r1]            @ cci_ctrl_base \n"
 304"4:     ldr     r1, [r0, #"__stringify(CCI_CTRL_STATUS)"] \n"
 305"       tst     r1, #1 \n"
 306"       bne     4b \n"
 307
 308"       mov     r0, #0 \n"
 309"       bx      lr \n"
 310
 311"       .align  2 \n"
 312"5:     .word   cpu_port - . \n"
 313"6:     .word   . \n"
 314"       .word   ports - 6b \n"
 315"7:     .word   cci_ctrl_phys - . \n"
 316        : :
 317        [sizeof_cpu_port] "i" (sizeof(cpu_port)),
 318#ifndef __ARMEB__
 319        [offsetof_cpu_port_mpidr_lsb] "i" (offsetof(struct cpu_port, mpidr)),
 320#else
 321        [offsetof_cpu_port_mpidr_lsb] "i" (offsetof(struct cpu_port, mpidr)+4),
 322#endif
 323        [offsetof_cpu_port_port] "i" (offsetof(struct cpu_port, port)),
 324        [sizeof_struct_cpu_port] "i" (sizeof(struct cpu_port)),
 325        [sizeof_struct_ace_port] "i" (sizeof(struct cci_ace_port)),
 326        [offsetof_port_phys] "i" (offsetof(struct cci_ace_port, phys)) );
 327
 328        unreachable();
 329}
 330
 331/**
 332 * __cci_control_port_by_device() - function to control a CCI port by device
 333 *                                  reference
 334 *
 335 * @dn: device node pointer of the device whose CCI port should be
 336 *      controlled
 337 * @enable: if true enables the port, if false disables it
 338 *
 339 * Return:
 340 *      0 on success
 341 *      -ENODEV on port look-up failure
 342 */
 343int notrace __cci_control_port_by_device(struct device_node *dn, bool enable)
 344{
 345        int port;
 346
 347        if (!dn)
 348                return -ENODEV;
 349
 350        port = __cci_ace_get_port(dn, ACE_LITE_PORT);
 351        if (WARN_ONCE(port < 0, "node %s ACE lite port look-up failure\n",
 352                                dn->full_name))
 353                return -ENODEV;
 354        cci_port_control(port, enable);
 355        return 0;
 356}
 357EXPORT_SYMBOL_GPL(__cci_control_port_by_device);
 358
 359/**
 360 * __cci_control_port_by_index() - function to control a CCI port by port index
 361 *
 362 * @port: port index previously retrieved with cci_ace_get_port()
 363 * @enable: if true enables the port, if false disables it
 364 *
 365 * Return:
 366 *      0 on success
 367 *      -ENODEV on port index out of range
 368 *      -EPERM if operation carried out on an ACE PORT
 369 */
 370int notrace __cci_control_port_by_index(u32 port, bool enable)
 371{
 372        if (port >= nb_cci_ports || ports[port].type == ACE_INVALID_PORT)
 373                return -ENODEV;
 374        /*
 375         * CCI control for ports connected to CPUS is extremely fragile
 376         * and must be made to go through a specific and controlled
 377         * interface (ie cci_disable_port_by_cpu(); control by general purpose
 378         * indexing is therefore disabled for ACE ports.
 379         */
 380        if (ports[port].type == ACE_PORT)
 381                return -EPERM;
 382
 383        cci_port_control(port, enable);
 384        return 0;
 385}
 386EXPORT_SYMBOL_GPL(__cci_control_port_by_index);
 387
 388static const struct cci_nb_ports cci400_ports = {
 389        .nb_ace = 2,
 390        .nb_ace_lite = 3
 391};
 392
 393static const struct of_device_id arm_cci_matches[] = {
 394        {.compatible = "arm,cci-400", .data = &cci400_ports },
 395        {},
 396};
 397
 398static const struct of_device_id arm_cci_ctrl_if_matches[] = {
 399        {.compatible = "arm,cci-400-ctrl-if", },
 400        {},
 401};
 402
 403static int __init cci_probe(void)
 404{
 405        struct cci_nb_ports const *cci_config;
 406        int ret, i, nb_ace = 0, nb_ace_lite = 0;
 407        struct device_node *np, *cp;
 408        struct resource res;
 409        const char *match_str;
 410        bool is_ace;
 411
 412        np = of_find_matching_node(NULL, arm_cci_matches);
 413        if (!np)
 414                return -ENODEV;
 415
 416        cci_config = of_match_node(arm_cci_matches, np)->data;
 417        if (!cci_config)
 418                return -ENODEV;
 419
 420        nb_cci_ports = cci_config->nb_ace + cci_config->nb_ace_lite;
 421
 422        ports = kcalloc(sizeof(*ports), nb_cci_ports, GFP_KERNEL);
 423        if (!ports)
 424                return -ENOMEM;
 425
 426        ret = of_address_to_resource(np, 0, &res);
 427        if (!ret) {
 428                cci_ctrl_base = ioremap(res.start, resource_size(&res));
 429                cci_ctrl_phys = res.start;
 430        }
 431        if (ret || !cci_ctrl_base) {
 432                WARN(1, "unable to ioremap CCI ctrl\n");
 433                ret = -ENXIO;
 434                goto memalloc_err;
 435        }
 436
 437        for_each_child_of_node(np, cp) {
 438                if (!of_match_node(arm_cci_ctrl_if_matches, cp))
 439                        continue;
 440
 441                i = nb_ace + nb_ace_lite;
 442
 443                if (i >= nb_cci_ports)
 444                        break;
 445
 446                if (of_property_read_string(cp, "interface-type",
 447                                        &match_str)) {
 448                        WARN(1, "node %s missing interface-type property\n",
 449                                  cp->full_name);
 450                        continue;
 451                }
 452                is_ace = strcmp(match_str, "ace") == 0;
 453                if (!is_ace && strcmp(match_str, "ace-lite")) {
 454                        WARN(1, "node %s containing invalid interface-type property, skipping it\n",
 455                                        cp->full_name);
 456                        continue;
 457                }
 458
 459                ret = of_address_to_resource(cp, 0, &res);
 460                if (!ret) {
 461                        ports[i].base = ioremap(res.start, resource_size(&res));
 462                        ports[i].phys = res.start;
 463                }
 464                if (ret || !ports[i].base) {
 465                        WARN(1, "unable to ioremap CCI port %d\n", i);
 466                        continue;
 467                }
 468
 469                if (is_ace) {
 470                        if (WARN_ON(nb_ace >= cci_config->nb_ace))
 471                                continue;
 472                        ports[i].type = ACE_PORT;
 473                        ++nb_ace;
 474                } else {
 475                        if (WARN_ON(nb_ace_lite >= cci_config->nb_ace_lite))
 476                                continue;
 477                        ports[i].type = ACE_LITE_PORT;
 478                        ++nb_ace_lite;
 479                }
 480                ports[i].dn = cp;
 481        }
 482
 483         /* initialize a stashed array of ACE ports to speed-up look-up */
 484        cci_ace_init_ports();
 485
 486        /*
 487         * Multi-cluster systems may need this data when non-coherent, during
 488         * cluster power-up/power-down. Make sure it reaches main memory.
 489         */
 490        sync_cache_w(&cci_ctrl_base);
 491        sync_cache_w(&cci_ctrl_phys);
 492        sync_cache_w(&ports);
 493        sync_cache_w(&cpu_port);
 494        __sync_cache_range_w(ports, sizeof(*ports) * nb_cci_ports);
 495        pr_info("ARM CCI driver probed\n");
 496        return 0;
 497
 498memalloc_err:
 499
 500        kfree(ports);
 501        return ret;
 502}
 503
 504static int cci_init_status = -EAGAIN;
 505static DEFINE_MUTEX(cci_probing);
 506
 507static int __init cci_init(void)
 508{
 509        if (cci_init_status != -EAGAIN)
 510                return cci_init_status;
 511
 512        mutex_lock(&cci_probing);
 513        if (cci_init_status == -EAGAIN)
 514                cci_init_status = cci_probe();
 515        mutex_unlock(&cci_probing);
 516        return cci_init_status;
 517}
 518
 519/*
 520 * To sort out early init calls ordering a helper function is provided to
 521 * check if the CCI driver has beed initialized. Function check if the driver
 522 * has been initialized, if not it calls the init function that probes
 523 * the driver and updates the return value.
 524 */
 525bool __init cci_probed(void)
 526{
 527        return cci_init() == 0;
 528}
 529EXPORT_SYMBOL_GPL(cci_probed);
 530
 531early_initcall(cci_init);
 532MODULE_LICENSE("GPL");
 533MODULE_DESCRIPTION("ARM CCI support");
 534
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.