1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
  
     | 
    
      // SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
/* Copyright 2013-2019 IBM Corp. */
/*
 *
 * 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 <skiboot.h>
#include <opal.h>
#include <device.h>
#include <console.h>
#include <trace.h>
#include <chip.h>
#include <cpu.h>
#include <affinity.h>
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 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_p8)
		core_id = (cpu->pir >> 3) & 0xf;
	else if (proc_gen == proc_gen_p9)
		core_id = (cpu->pir >> 2) & 0x1f;
	else if (proc_gen == proc_gen_p10 || proc_gen == proc_gen_p11)
		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);
}
 
     |