/* Copyright 2013-2014 IBM Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * * We currently construct our associativity properties as such: * * - For "chip" devices (bridges, memory, ...), 4 entries: * * - CCM node ID * - HW card ID * - HW module ID * - Chip ID * * The information is constructed based on the chip ID which (unlike * pHyp) is our HW chip ID (aka "XSCOM" chip ID). We use it to retrieve * the other properties from the corresponding chip/xscom node in the * device-tree. If those properties are absent, 0 is used. * * - For "core" devices, we add a 5th entry: * * - Core ID * * Here too, we do not use the "cooked" HW processor ID from HDAT but * instead use the real HW core ID which is basically the interrupt * server number of thread 0 on that core. * * * The ibm,associativity-reference-points property is currently set to * 4,4 indicating that the chip ID is our only reference point. This * should be extended to encompass the node IDs eventually. */ #include #include #include #include #include #include #include #include static uint32_t get_chip_node_id(struct proc_chip *chip) { /* If the xscom node has an ibm,ccm-node-id property, use it */ if (dt_has_node_property(chip->devnode, "ibm,ccm-node-id", NULL)) return dt_prop_get_u32(chip->devnode, "ibm,ccm-node-id"); /* * Else use the 3 top bits of the chip ID which should be * the node on both P7 and P8 */ return chip->id >> 3; } void add_associativity_ref_point(void) { int ref2 = 0x4; /* * Note about our use of reference points: * * Linux currently supports up to three levels of NUMA. We use the * first reference point for the node ID and the second reference * point for a second level of affinity. We always use the chip ID * (4) for the first reference point. * * Choosing the second level of affinity is model specific * unfortunately. Current POWER8E models should use the DCM * as a second level of NUMA. * * If there is a way to obtain this information from the FSP * that would be ideal, but for now hardwire our POWER8E setting. * * For GPU nodes we add a third level of NUMA, such that the * distance of the GPU node from all other nodes is uniformly * the highest. */ if (PVR_TYPE(mfspr(SPR_PVR)) == PVR_TYPE_P8E) ref2 = 0x3; dt_add_property_cells(opal_node, "ibm,associativity-reference-points", 0x4, ref2, 0x2); } void add_chip_dev_associativity(struct dt_node *dev) { uint32_t chip_id = dt_get_chip_id(dev); struct proc_chip *chip = get_chip(chip_id); uint32_t hw_cid, hw_mid; if (!chip) return; hw_cid = dt_prop_get_u32_def(chip->devnode, "ibm,hw-card-id", 0); hw_mid = dt_prop_get_u32_def(chip->devnode, "ibm,hw-module-id", 0); dt_add_property_cells(dev, "ibm,associativity", 4, get_chip_node_id(chip), hw_cid, hw_mid, chip_id); } void add_core_associativity(struct cpu_thread *cpu) { struct proc_chip *chip = get_chip(cpu->chip_id); uint32_t hw_cid, hw_mid, core_id; if (!chip) return; if (proc_gen == proc_gen_p7) core_id = (cpu->pir >> 2) & 0x7; else if (proc_gen == proc_gen_p8) core_id = (cpu->pir >> 3) & 0xf; else if (proc_gen == proc_gen_p9) core_id = (cpu->pir >> 2) & 0x1f; else return; hw_cid = dt_prop_get_u32_def(chip->devnode, "ibm,hw-card-id", 0); hw_mid = dt_prop_get_u32_def(chip->devnode, "ibm,hw-module-id", 0); dt_add_property_cells(cpu->node, "ibm,associativity", 5, get_chip_node_id(chip), hw_cid, hw_mid, chip->id, core_id); }