Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drivers: bus: add ARM CCI support

On ARM multi-cluster systems coherency between cores running on
different clusters is managed by the cache-coherent interconnect (CCI).
It allows broadcasting of TLB invalidates and memory barriers and it
guarantees cache coherency at system level through snooping of slave
interfaces connected to it.

This patch enables the basic infrastructure required in Linux to handle and
programme the CCI component.

Non-local variables used by the CCI management functions called by power
down function calls after disabling the cache must be flushed out to main
memory in advance, otherwise incoherency of those values may occur if they
are sitting in the cache of some other CPU when power down functions
execute. Driver code ensures that relevant data structures are flushed
from inner and outer caches after the driver probe is completed.

CCI slave port resources are linked to set of CPUs through bus masters
phandle properties that link the interface resources to masters node in
the device tree.

Documentation describing the CCI DT bindings is provided with the patch.

Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Signed-off-by: Nicolas Pitre <nicolas.pitre@linaro.org>

authored by

Lorenzo Pieralisi and committed by
Nicolas Pitre
ed69bdd8 78ecad01

+668
+172
Documentation/devicetree/bindings/arm/cci.txt
··· 1 + ======================================================= 2 + ARM CCI cache coherent interconnect binding description 3 + ======================================================= 4 + 5 + ARM multi-cluster systems maintain intra-cluster coherency through a 6 + cache coherent interconnect (CCI) that is capable of monitoring bus 7 + transactions and manage coherency, TLB invalidations and memory barriers. 8 + 9 + It allows snooping and distributed virtual memory message broadcast across 10 + clusters, through memory mapped interface, with a global control register 11 + space and multiple sets of interface control registers, one per slave 12 + interface. 13 + 14 + Bindings for the CCI node follow the ePAPR standard, available from: 15 + 16 + www.power.org/documentation/epapr-version-1-1/ 17 + 18 + with the addition of the bindings described in this document which are 19 + specific to ARM. 20 + 21 + * CCI interconnect node 22 + 23 + Description: Describes a CCI cache coherent Interconnect component 24 + 25 + Node name must be "cci". 26 + Node's parent must be the root node /, and the address space visible 27 + through the CCI interconnect is the same as the one seen from the 28 + root node (ie from CPUs perspective as per DT standard). 29 + Every CCI node has to define the following properties: 30 + 31 + - compatible 32 + Usage: required 33 + Value type: <string> 34 + Definition: must be set to 35 + "arm,cci-400" 36 + 37 + - reg 38 + Usage: required 39 + Value type: <prop-encoded-array> 40 + Definition: A standard property. Specifies base physical 41 + address of CCI control registers common to all 42 + interfaces. 43 + 44 + - ranges: 45 + Usage: required 46 + Value type: <prop-encoded-array> 47 + Definition: A standard property. Follow rules in the ePAPR for 48 + hierarchical bus addressing. CCI interfaces 49 + addresses refer to the parent node addressing 50 + scheme to declare their register bases. 51 + 52 + CCI interconnect node can define the following child nodes: 53 + 54 + - CCI control interface nodes 55 + 56 + Node name must be "slave-if". 57 + Parent node must be CCI interconnect node. 58 + 59 + A CCI control interface node must contain the following 60 + properties: 61 + 62 + - compatible 63 + Usage: required 64 + Value type: <string> 65 + Definition: must be set to 66 + "arm,cci-400-ctrl-if" 67 + 68 + - interface-type: 69 + Usage: required 70 + Value type: <string> 71 + Definition: must be set to one of {"ace", "ace-lite"} 72 + depending on the interface type the node 73 + represents. 74 + 75 + - reg: 76 + Usage: required 77 + Value type: <prop-encoded-array> 78 + Definition: the base address and size of the 79 + corresponding interface programming 80 + registers. 81 + 82 + * CCI interconnect bus masters 83 + 84 + Description: masters in the device tree connected to a CCI port 85 + (inclusive of CPUs and their cpu nodes). 86 + 87 + A CCI interconnect bus master node must contain the following 88 + properties: 89 + 90 + - cci-control-port: 91 + Usage: required 92 + Value type: <phandle> 93 + Definition: a phandle containing the CCI control interface node 94 + the master is connected to. 95 + 96 + Example: 97 + 98 + cpus { 99 + #size-cells = <0>; 100 + #address-cells = <1>; 101 + 102 + CPU0: cpu@0 { 103 + device_type = "cpu"; 104 + compatible = "arm,cortex-a15"; 105 + cci-control-port = <&cci_control1>; 106 + reg = <0x0>; 107 + }; 108 + 109 + CPU1: cpu@1 { 110 + device_type = "cpu"; 111 + compatible = "arm,cortex-a15"; 112 + cci-control-port = <&cci_control1>; 113 + reg = <0x1>; 114 + }; 115 + 116 + CPU2: cpu@100 { 117 + device_type = "cpu"; 118 + compatible = "arm,cortex-a7"; 119 + cci-control-port = <&cci_control2>; 120 + reg = <0x100>; 121 + }; 122 + 123 + CPU3: cpu@101 { 124 + device_type = "cpu"; 125 + compatible = "arm,cortex-a7"; 126 + cci-control-port = <&cci_control2>; 127 + reg = <0x101>; 128 + }; 129 + 130 + }; 131 + 132 + dma0: dma@3000000 { 133 + compatible = "arm,pl330", "arm,primecell"; 134 + cci-control-port = <&cci_control0>; 135 + reg = <0x0 0x3000000 0x0 0x1000>; 136 + interrupts = <10>; 137 + #dma-cells = <1>; 138 + #dma-channels = <8>; 139 + #dma-requests = <32>; 140 + }; 141 + 142 + cci@2c090000 { 143 + compatible = "arm,cci-400"; 144 + #address-cells = <1>; 145 + #size-cells = <1>; 146 + reg = <0x0 0x2c090000 0 0x1000>; 147 + ranges = <0x0 0x0 0x2c090000 0x6000>; 148 + 149 + cci_control0: slave-if@1000 { 150 + compatible = "arm,cci-400-ctrl-if"; 151 + interface-type = "ace-lite"; 152 + reg = <0x1000 0x1000>; 153 + }; 154 + 155 + cci_control1: slave-if@4000 { 156 + compatible = "arm,cci-400-ctrl-if"; 157 + interface-type = "ace"; 158 + reg = <0x4000 0x1000>; 159 + }; 160 + 161 + cci_control2: slave-if@5000 { 162 + compatible = "arm,cci-400-ctrl-if"; 163 + interface-type = "ace"; 164 + reg = <0x5000 0x1000>; 165 + }; 166 + }; 167 + 168 + This CCI node corresponds to a CCI component whose control registers sits 169 + at address 0x000000002c090000. 170 + CCI slave interface @0x000000002c091000 is connected to dma controller dma0. 171 + CCI slave interface @0x000000002c094000 is connected to CPUs {CPU0, CPU1}; 172 + CCI slave interface @0x000000002c095000 is connected to CPUs {CPU2, CPU3};
+7
drivers/bus/Kconfig
··· 26 26 27 27 help 28 28 Driver to enable OMAP interconnect error handling driver. 29 + 30 + config ARM_CCI 31 + bool "ARM CCI driver support" 32 + depends on ARM 33 + help 34 + Driver supporting the CCI cache coherent interconnect for ARM 35 + platforms. 29 36 endmenu
+2
drivers/bus/Makefile
··· 7 7 8 8 # Interconnect bus driver for OMAP SoCs. 9 9 obj-$(CONFIG_OMAP_INTERCONNECT) += omap_l3_smx.o omap_l3_noc.o 10 + # CCI cache coherent interconnect for ARM platforms 11 + obj-$(CONFIG_ARM_CCI) += arm-cci.o
+426
drivers/bus/arm-cci.c
··· 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 + 33 + struct cci_nb_ports { 34 + unsigned int nb_ace; 35 + unsigned int nb_ace_lite; 36 + }; 37 + 38 + enum cci_ace_port_type { 39 + ACE_INVALID_PORT = 0x0, 40 + ACE_PORT, 41 + ACE_LITE_PORT, 42 + }; 43 + 44 + struct cci_ace_port { 45 + void __iomem *base; 46 + enum cci_ace_port_type type; 47 + struct device_node *dn; 48 + }; 49 + 50 + static struct cci_ace_port *ports; 51 + static unsigned int nb_cci_ports; 52 + 53 + static void __iomem *cci_ctrl_base; 54 + 55 + struct cpu_port { 56 + u64 mpidr; 57 + u32 port; 58 + }; 59 + /* 60 + * Use the port MSB as valid flag, shift can be made dynamic 61 + * by computing number of bits required for port indexes. 62 + * Code disabling CCI cpu ports runs with D-cache invalidated 63 + * and SCTLR bit clear so data accesses must be kept to a minimum 64 + * to improve performance; for now shift is left static to 65 + * avoid one more data access while disabling the CCI port. 66 + */ 67 + #define PORT_VALID_SHIFT 31 68 + #define PORT_VALID (0x1 << PORT_VALID_SHIFT) 69 + 70 + static inline void init_cpu_port(struct cpu_port *port, u32 index, u64 mpidr) 71 + { 72 + port->port = PORT_VALID | index; 73 + port->mpidr = mpidr; 74 + } 75 + 76 + static inline bool cpu_port_is_valid(struct cpu_port *port) 77 + { 78 + return !!(port->port & PORT_VALID); 79 + } 80 + 81 + static inline bool cpu_port_match(struct cpu_port *port, u64 mpidr) 82 + { 83 + return port->mpidr == (mpidr & MPIDR_HWID_BITMASK); 84 + } 85 + 86 + static struct cpu_port cpu_port[NR_CPUS]; 87 + 88 + /** 89 + * __cci_ace_get_port - Function to retrieve the port index connected to 90 + * a cpu or device. 91 + * 92 + * @dn: device node of the device to look-up 93 + * @type: port type 94 + * 95 + * Return value: 96 + * - CCI port index if success 97 + * - -ENODEV if failure 98 + */ 99 + static int __cci_ace_get_port(struct device_node *dn, int type) 100 + { 101 + int i; 102 + bool ace_match; 103 + struct device_node *cci_portn; 104 + 105 + cci_portn = of_parse_phandle(dn, "cci-control-port", 0); 106 + for (i = 0; i < nb_cci_ports; i++) { 107 + ace_match = ports[i].type == type; 108 + if (ace_match && cci_portn == ports[i].dn) 109 + return i; 110 + } 111 + return -ENODEV; 112 + } 113 + 114 + int cci_ace_get_port(struct device_node *dn) 115 + { 116 + return __cci_ace_get_port(dn, ACE_LITE_PORT); 117 + } 118 + EXPORT_SYMBOL_GPL(cci_ace_get_port); 119 + 120 + static void __init cci_ace_init_ports(void) 121 + { 122 + int port, ac, cpu; 123 + u64 hwid; 124 + const u32 *cell; 125 + struct device_node *cpun, *cpus; 126 + 127 + cpus = of_find_node_by_path("/cpus"); 128 + if (WARN(!cpus, "Missing cpus node, bailing out\n")) 129 + return; 130 + 131 + if (WARN_ON(of_property_read_u32(cpus, "#address-cells", &ac))) 132 + ac = of_n_addr_cells(cpus); 133 + 134 + /* 135 + * Port index look-up speeds up the function disabling ports by CPU, 136 + * since the logical to port index mapping is done once and does 137 + * not change after system boot. 138 + * The stashed index array is initialized for all possible CPUs 139 + * at probe time. 140 + */ 141 + for_each_child_of_node(cpus, cpun) { 142 + if (of_node_cmp(cpun->type, "cpu")) 143 + continue; 144 + cell = of_get_property(cpun, "reg", NULL); 145 + if (WARN(!cell, "%s: missing reg property\n", cpun->full_name)) 146 + continue; 147 + 148 + hwid = of_read_number(cell, ac); 149 + cpu = get_logical_index(hwid & MPIDR_HWID_BITMASK); 150 + 151 + if (cpu < 0 || !cpu_possible(cpu)) 152 + continue; 153 + port = __cci_ace_get_port(cpun, ACE_PORT); 154 + if (port < 0) 155 + continue; 156 + 157 + init_cpu_port(&cpu_port[cpu], port, cpu_logical_map(cpu)); 158 + } 159 + 160 + for_each_possible_cpu(cpu) { 161 + WARN(!cpu_port_is_valid(&cpu_port[cpu]), 162 + "CPU %u does not have an associated CCI port\n", 163 + cpu); 164 + } 165 + } 166 + /* 167 + * Functions to enable/disable a CCI interconnect slave port 168 + * 169 + * They are called by low-level power management code to disable slave 170 + * interfaces snoops and DVM broadcast. 171 + * Since they may execute with cache data allocation disabled and 172 + * after the caches have been cleaned and invalidated the functions provide 173 + * no explicit locking since they may run with D-cache disabled, so normal 174 + * cacheable kernel locks based on ldrex/strex may not work. 175 + * Locking has to be provided by BSP implementations to ensure proper 176 + * operations. 177 + */ 178 + 179 + /** 180 + * cci_port_control() - function to control a CCI port 181 + * 182 + * @port: index of the port to setup 183 + * @enable: if true enables the port, if false disables it 184 + */ 185 + static void notrace cci_port_control(unsigned int port, bool enable) 186 + { 187 + void __iomem *base = ports[port].base; 188 + 189 + writel_relaxed(enable ? CCI_ENABLE_REQ : 0, base + CCI_PORT_CTRL); 190 + /* 191 + * This function is called from power down procedures 192 + * and must not execute any instruction that might 193 + * cause the processor to be put in a quiescent state 194 + * (eg wfi). Hence, cpu_relax() can not be added to this 195 + * read loop to optimize power, since it might hide possibly 196 + * disruptive operations. 197 + */ 198 + while (readl_relaxed(cci_ctrl_base + CCI_CTRL_STATUS) & 0x1) 199 + ; 200 + } 201 + 202 + /** 203 + * cci_disable_port_by_cpu() - function to disable a CCI port by CPU 204 + * reference 205 + * 206 + * @mpidr: mpidr of the CPU whose CCI port should be disabled 207 + * 208 + * Disabling a CCI port for a CPU implies disabling the CCI port 209 + * controlling that CPU cluster. Code disabling CPU CCI ports 210 + * must make sure that the CPU running the code is the last active CPU 211 + * in the cluster ie all other CPUs are quiescent in a low power state. 212 + * 213 + * Return: 214 + * 0 on success 215 + * -ENODEV on port look-up failure 216 + */ 217 + int notrace cci_disable_port_by_cpu(u64 mpidr) 218 + { 219 + int cpu; 220 + bool is_valid; 221 + for (cpu = 0; cpu < nr_cpu_ids; cpu++) { 222 + is_valid = cpu_port_is_valid(&cpu_port[cpu]); 223 + if (is_valid && cpu_port_match(&cpu_port[cpu], mpidr)) { 224 + cci_port_control(cpu_port[cpu].port, false); 225 + return 0; 226 + } 227 + } 228 + return -ENODEV; 229 + } 230 + EXPORT_SYMBOL_GPL(cci_disable_port_by_cpu); 231 + 232 + /** 233 + * __cci_control_port_by_device() - function to control a CCI port by device 234 + * reference 235 + * 236 + * @dn: device node pointer of the device whose CCI port should be 237 + * controlled 238 + * @enable: if true enables the port, if false disables it 239 + * 240 + * Return: 241 + * 0 on success 242 + * -ENODEV on port look-up failure 243 + */ 244 + int notrace __cci_control_port_by_device(struct device_node *dn, bool enable) 245 + { 246 + int port; 247 + 248 + if (!dn) 249 + return -ENODEV; 250 + 251 + port = __cci_ace_get_port(dn, ACE_LITE_PORT); 252 + if (WARN_ONCE(port < 0, "node %s ACE lite port look-up failure\n", 253 + dn->full_name)) 254 + return -ENODEV; 255 + cci_port_control(port, enable); 256 + return 0; 257 + } 258 + EXPORT_SYMBOL_GPL(__cci_control_port_by_device); 259 + 260 + /** 261 + * __cci_control_port_by_index() - function to control a CCI port by port index 262 + * 263 + * @port: port index previously retrieved with cci_ace_get_port() 264 + * @enable: if true enables the port, if false disables it 265 + * 266 + * Return: 267 + * 0 on success 268 + * -ENODEV on port index out of range 269 + * -EPERM if operation carried out on an ACE PORT 270 + */ 271 + int notrace __cci_control_port_by_index(u32 port, bool enable) 272 + { 273 + if (port >= nb_cci_ports || ports[port].type == ACE_INVALID_PORT) 274 + return -ENODEV; 275 + /* 276 + * CCI control for ports connected to CPUS is extremely fragile 277 + * and must be made to go through a specific and controlled 278 + * interface (ie cci_disable_port_by_cpu(); control by general purpose 279 + * indexing is therefore disabled for ACE ports. 280 + */ 281 + if (ports[port].type == ACE_PORT) 282 + return -EPERM; 283 + 284 + cci_port_control(port, enable); 285 + return 0; 286 + } 287 + EXPORT_SYMBOL_GPL(__cci_control_port_by_index); 288 + 289 + static const struct cci_nb_ports cci400_ports = { 290 + .nb_ace = 2, 291 + .nb_ace_lite = 3 292 + }; 293 + 294 + static const struct of_device_id arm_cci_matches[] = { 295 + {.compatible = "arm,cci-400", .data = &cci400_ports }, 296 + {}, 297 + }; 298 + 299 + static const struct of_device_id arm_cci_ctrl_if_matches[] = { 300 + {.compatible = "arm,cci-400-ctrl-if", }, 301 + {}, 302 + }; 303 + 304 + static int __init cci_probe(void) 305 + { 306 + struct cci_nb_ports const *cci_config; 307 + int ret, i, nb_ace = 0, nb_ace_lite = 0; 308 + struct device_node *np, *cp; 309 + const char *match_str; 310 + bool is_ace; 311 + 312 + np = of_find_matching_node(NULL, arm_cci_matches); 313 + if (!np) 314 + return -ENODEV; 315 + 316 + cci_config = of_match_node(arm_cci_matches, np)->data; 317 + if (!cci_config) 318 + return -ENODEV; 319 + 320 + nb_cci_ports = cci_config->nb_ace + cci_config->nb_ace_lite; 321 + 322 + ports = kcalloc(sizeof(*ports), nb_cci_ports, GFP_KERNEL); 323 + if (!ports) 324 + return -ENOMEM; 325 + 326 + cci_ctrl_base = of_iomap(np, 0); 327 + 328 + if (!cci_ctrl_base) { 329 + WARN(1, "unable to ioremap CCI ctrl\n"); 330 + ret = -ENXIO; 331 + goto memalloc_err; 332 + } 333 + 334 + for_each_child_of_node(np, cp) { 335 + if (!of_match_node(arm_cci_ctrl_if_matches, cp)) 336 + continue; 337 + 338 + i = nb_ace + nb_ace_lite; 339 + 340 + if (i >= nb_cci_ports) 341 + break; 342 + 343 + if (of_property_read_string(cp, "interface-type", 344 + &match_str)) { 345 + WARN(1, "node %s missing interface-type property\n", 346 + cp->full_name); 347 + continue; 348 + } 349 + is_ace = strcmp(match_str, "ace") == 0; 350 + if (!is_ace && strcmp(match_str, "ace-lite")) { 351 + WARN(1, "node %s containing invalid interface-type property, skipping it\n", 352 + cp->full_name); 353 + continue; 354 + } 355 + 356 + ports[i].base = of_iomap(cp, 0); 357 + 358 + if (!ports[i].base) { 359 + WARN(1, "unable to ioremap CCI port %d\n", i); 360 + continue; 361 + } 362 + 363 + if (is_ace) { 364 + if (WARN_ON(nb_ace >= cci_config->nb_ace)) 365 + continue; 366 + ports[i].type = ACE_PORT; 367 + ++nb_ace; 368 + } else { 369 + if (WARN_ON(nb_ace_lite >= cci_config->nb_ace_lite)) 370 + continue; 371 + ports[i].type = ACE_LITE_PORT; 372 + ++nb_ace_lite; 373 + } 374 + ports[i].dn = cp; 375 + } 376 + 377 + /* initialize a stashed array of ACE ports to speed-up look-up */ 378 + cci_ace_init_ports(); 379 + 380 + /* 381 + * Multi-cluster systems may need this data when non-coherent, during 382 + * cluster power-up/power-down. Make sure it reaches main memory. 383 + */ 384 + sync_cache_w(&cci_ctrl_base); 385 + sync_cache_w(&ports); 386 + sync_cache_w(&cpu_port); 387 + __sync_cache_range_w(ports, sizeof(*ports) * nb_cci_ports); 388 + pr_info("ARM CCI driver probed\n"); 389 + return 0; 390 + 391 + memalloc_err: 392 + 393 + kfree(ports); 394 + return ret; 395 + } 396 + 397 + static int cci_init_status = -EAGAIN; 398 + static DEFINE_MUTEX(cci_probing); 399 + 400 + static int __init cci_init(void) 401 + { 402 + if (cci_init_status != -EAGAIN) 403 + return cci_init_status; 404 + 405 + mutex_lock(&cci_probing); 406 + if (cci_init_status == -EAGAIN) 407 + cci_init_status = cci_probe(); 408 + mutex_unlock(&cci_probing); 409 + return cci_init_status; 410 + } 411 + 412 + /* 413 + * To sort out early init calls ordering a helper function is provided to 414 + * check if the CCI driver has beed initialized. Function check if the driver 415 + * has been initialized, if not it calls the init function that probes 416 + * the driver and updates the return value. 417 + */ 418 + bool __init cci_probed(void) 419 + { 420 + return cci_init() == 0; 421 + } 422 + EXPORT_SYMBOL_GPL(cci_probed); 423 + 424 + early_initcall(cci_init); 425 + MODULE_LICENSE("GPL"); 426 + MODULE_DESCRIPTION("ARM CCI support");
+61
include/linux/arm-cci.h
··· 1 + /* 2 + * CCI cache coherent interconnect support 3 + * 4 + * Copyright (C) 2013 ARM Ltd. 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License as published by 8 + * the Free Software Foundation; either version 2 of the License, or 9 + * (at your option) any later version. 10 + * 11 + * This program is distributed in the hope that it will be useful, 12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 + * GNU General Public License for more details. 15 + * 16 + * You should have received a copy of the GNU General Public License 17 + * along with this program; if not, write to the Free Software 18 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 + */ 20 + 21 + #ifndef __LINUX_ARM_CCI_H 22 + #define __LINUX_ARM_CCI_H 23 + 24 + #include <linux/errno.h> 25 + #include <linux/types.h> 26 + 27 + struct device_node; 28 + 29 + #ifdef CONFIG_ARM_CCI 30 + extern bool cci_probed(void); 31 + extern int cci_ace_get_port(struct device_node *dn); 32 + extern int cci_disable_port_by_cpu(u64 mpidr); 33 + extern int __cci_control_port_by_device(struct device_node *dn, bool enable); 34 + extern int __cci_control_port_by_index(u32 port, bool enable); 35 + #else 36 + static inline bool cci_probed(void) { return false; } 37 + static inline int cci_ace_get_port(struct device_node *dn) 38 + { 39 + return -ENODEV; 40 + } 41 + static inline int cci_disable_port_by_cpu(u64 mpidr) { return -ENODEV; } 42 + static inline int __cci_control_port_by_device(struct device_node *dn, 43 + bool enable) 44 + { 45 + return -ENODEV; 46 + } 47 + static inline int __cci_control_port_by_index(u32 port, bool enable) 48 + { 49 + return -ENODEV; 50 + } 51 + #endif 52 + #define cci_disable_port_by_device(dev) \ 53 + __cci_control_port_by_device(dev, false) 54 + #define cci_enable_port_by_device(dev) \ 55 + __cci_control_port_by_device(dev, true) 56 + #define cci_disable_port_by_index(dev) \ 57 + __cci_control_port_by_index(dev, false) 58 + #define cci_enable_port_by_index(dev) \ 59 + __cci_control_port_by_index(dev, true) 60 + 61 + #endif