diff mbox

[RFC,4/4] ibm-fsp/firenze: Nest Intrumentation code

Message ID 1426757313-20981-5-git-send-email-maddy@linux.vnet.ibm.com
State Changes Requested
Headers show

Commit Message

maddy March 19, 2015, 9:28 a.m. UTC
This patch addes Nest instrumentation OPAL side code.
Patch does two things. 1) At the time of boot, it detects
the Nest instrumentation feature and created device-tree
entries to pass the information to kernel. Secondly, it
implements an opal call to control the PORE Thread Scheduler
(PTS) from kernel.

Currently we do not have the Nest instrumentation detection
mechanism ready. This should happen via LID file. Currently
the LID file is under developement and does not contain
the Chip level events or the layout for the chip level events.

So, have added comments and TODOs in the code that needs changes
once the LID file is ready.

Signed-off-by: Madhavan Srinivasan <maddy@linux.vnet.ibm.com>
---
 hw/Makefile.inc |   2 +-
 hw/uncore.c     | 250 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 251 insertions(+), 1 deletion(-)
 create mode 100644 hw/uncore.c

Comments

Stewart Smith April 22, 2015, 2:02 a.m. UTC | #1
Madhavan Srinivasan <maddy@linux.vnet.ibm.com> writes:
> +/*
> + * OPAL call to start and stop PTS.
> + */

This comment is really not needed, it adds no extra information than the
opal_call declaration below.

> +static int64_t opal_uncore_control(uint32_t value)



> +{
> +	struct proc_chip *chip;
> +	int rc = IMA_PTS_ERROR;
> +
> +	chip = get_chip(pir_to_chip_id(this_cpu()->pir));
> +
> +	if (value)
> +		rc = pore_slw_ima_scom(chip->id, IMA_PTS_START);
> +	 else
> +		rc = pore_slw_ima_scom(chip->id, IMA_PTS_STOP);
> +
> +	return rc;
> +}
> +opal_call (OPAL_UNCORE_CONTROL, opal_uncore_control, 1);

You will need to add documentation to doc/opal-api/

It may be better to define the options as:
1 = enable
0 = disable
any other value = OPAL_PARAMETER returned.

Why is chip being this_cpu better than passing in what chip we want to
send it to? (Not saying it's better or worse, but why that API?)
maddy April 23, 2015, 2:59 a.m. UTC | #2
On Wednesday 22 April 2015 07:32 AM, Stewart Smith wrote:
> Madhavan Srinivasan <maddy@linux.vnet.ibm.com> writes:
>> +/*
>> + * OPAL call to start and stop PTS.
>> + */
> This comment is really not needed, it adds no extra information than the
> opal_call declaration below.
Ok.
>
>> +static int64_t opal_uncore_control(uint32_t value)
>
>
>> +{
>> +	struct proc_chip *chip;
>> +	int rc = IMA_PTS_ERROR;
>> +
>> +	chip = get_chip(pir_to_chip_id(this_cpu()->pir));
>> +
>> +	if (value)
>> +		rc = pore_slw_ima_scom(chip->id, IMA_PTS_START);
>> +	 else
>> +		rc = pore_slw_ima_scom(chip->id, IMA_PTS_STOP);
>> +
>> +	return rc;
>> +}
>> +opal_call (OPAL_UNCORE_CONTROL, opal_uncore_control, 1);
> You will need to add documentation to doc/opal-api/
>
> It may be better to define the options as:
> 1 = enable
> 0 = disable
> any other value = OPAL_PARAMETER returned.
>
> Why is chip being this_cpu better than passing in what chip we want to
> send it to? (Not saying it's better or worse, but why that API?)
If we need to pass it, then we need to figure that out in kernel
(may be using  topology_physical_package_id ), also currently
did not find any opal call sending chip id.

But this question scares me, is there a chance of kernel thread
which does opal call from a chip, can end up in a different
chip threads in opal side?

Thanks for review.
Maddy
diff mbox

Patch

diff --git a/hw/Makefile.inc b/hw/Makefile.inc
index 395a65f..7c4cac8 100644
--- a/hw/Makefile.inc
+++ b/hw/Makefile.inc
@@ -2,7 +2,7 @@ 
 
 SUBDIRS += hw
 HW_OBJS  = xscom.o chiptod.o gx.o cec.o lpc.o lpc-uart.o psi.o
-HW_OBJS += homer.o slw.o occ.o fsi-master.o centaur.o
+HW_OBJS += homer.o slw.o occ.o fsi-master.o centaur.o uncore.o
 HW_OBJS += nx.o nx-rng.o nx-crypto.o nx-842.o
 HW_OBJS += p7ioc.o p7ioc-inits.o p7ioc-phb.o p5ioc2.o p5ioc2-phb.o
 HW_OBJS += phb3.o sfc-ctrl.o fake-rtc.o bt.o p8-i2c.o prd.o
diff --git a/hw/uncore.c b/hw/uncore.c
new file mode 100644
index 0000000..793496a
--- /dev/null
+++ b/hw/uncore.c
@@ -0,0 +1,250 @@ 
+/* Copyright 2015 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.
+ * Locking notes:
+ */
+
+#include <skiboot.h>
+#include <device.h>
+#include <uncore.h>
+#include <chip.h>
+#include <cpu.h>
+#include <xscom.h>
+#include <timebase.h>
+#include <opal-api.h>
+
+/*
+ * Fixed offsets for memory controller read and write events.
+ * Data from PORE_SLW_IMA team, since catalog lid is
+ * under developement
+ */
+static u32 uncore_mcs_read_controller_offset[] =
+				{0x118, 0x120, 0x128, 0x130};
+static u32 uncore_mcs_write_controller_offset[] =
+				{0x198, 0x1A0, 0x1A8, 0x1B0};
+
+int setup_scom (uint32_t , uint64_t );
+
+static int dt_create_uncore_mcs(struct dt_node *ima)
+{
+	int i;
+	struct dt_node *subdev;
+	const char *unit = "MiB/s", *scale = "8";
+
+	/*
+	 * Create dt entry for each Unit.
+	 */
+	for(i=0; i<P8_IMA_MCS_COUNT; i++) {
+		subdev = dt_new_addr(ima, "mcs", i);
+		if(!subdev) {
+                        prlog(PR_DEBUG, "uncore subdev creation failed \n");
+                        return -1;
+		}
+
+		/*
+		 * Events Supported by this Unit
+		 * TODO:
+		 * Offset value should come from Catalog lid.
+		 */
+		dt_add_property_cells(subdev, "mcs_read", uncore_mcs_read_controller_offset[i]);
+		dt_add_property_string(subdev, "unit.mcs_read.unit", unit);
+		dt_add_property_string(subdev, "scale.mcs_read.scale", scale);
+		dt_add_property_cells(subdev, "mcs_write", uncore_mcs_write_controller_offset[i]);
+		dt_add_property_string(subdev, "unit.mcs_write.unit", unit);
+		dt_add_property_string(subdev, "scale.mcs_write.scale", scale);
+		dt_add_property_cells(subdev, "ibm,dev-id", i);
+	}
+
+	return 0;
+}
+
+static int dt_create_uncore_mcs_type (struct dt_node *uncore)
+{
+	struct dt_node *type;
+
+	/*
+	 * Create a Memory Controller Type (MCS)
+	 */
+	type = dt_new(uncore, "mcs");
+	if (!type) {
+		prlog(PR_DEBUG, "uncore mcs type creation failed \n");
+		return -1;
+	}
+
+	dt_add_property_string(type, "compatible", "ibm,uncore-mcs");
+	dt_add_property_cells(type, "sub_units", 0x4);
+
+	/*
+	 * Now create a sub node to add events and
+	 * other data.
+	 */
+	if (dt_create_uncore_mcs(type)) {
+		dt_free(type);
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * Each Nest unit will have a type folder
+ * and sub-folder for events and offset.
+ */
+static int dt_create_uncore_types(struct dt_node *uncore)
+{
+	/*
+	 * Currently will information about Memory
+	 * Controller (MCS Unit)
+	 * TODO:
+	 * Need to fix this by parsing Catalog lid.
+	 */
+	if (dt_create_uncore_mcs_type(uncore))
+		return -1;
+
+	return 0;
+}
+
+/*
+ * powerpc Nest instrumentation support init.
+ */
+void uncore_init(void)
+{
+	struct proc_chip *chip;
+	struct dt_node *dev;
+	const char *compat = "ibm,uncore-v1";
+	u64 addr=0;
+
+	/*
+	 * TODO:
+	 * Currently patch assumes we have Nest
+         * instrumentation enabled in the processor
+	 * it runs.
+	 *
+	 * Feature Detection:
+	 * Nest instrumentation feature detection
+	 * has to happen via a LID (81e00610).
+	 * This is ilid, called as "24x7 catalog", should
+	 * have information about both Core level and Chip
+	 * level events.
+	 *
+	 * But the catalog is under-development. We have
+	 * the LID as part of the FW, but it does not
+	 * contain any information about Chip level events
+	 * currently.
+	 *
+	 * load_catalog_lid()
+	 */
+
+	/*
+	 * Design is to pass the Nest counter information
+	 * to kernel via Device-tree. Top level node
+	 * ("uncore@<chip -id>") under "/" (root) created
+	 * to have all the nest data in one place. Since
+	 * Nest counters are per-chip, hence "@<chip-id>"
+	 *
+	 * Each Nest unit will have a sub node like mcs, pb
+	 * (Nest units) with information such as events,
+	 * offsets in Homer for counter data, unit, scale
+	 * and so on.
+	 */
+	for_each_chip(chip) {
+		dev = dt_new_addr(dt_root, "uncore", chip->id);
+		if(!dev) {
+			prlog(PR_DEBUG,"uncore dev creation failed \n");
+			return;
+		}
+
+		/*
+		 * Design:
+		 * PORE_SLW_IMA Engine will program
+		 * Nest counters with pre-defined set of
+		 * events (provided in catalog) and dump
+		 * counter data in a fixed HOMER offset 
+		 * (also provided in catalog).
+		 *
+		 * HOMER Region has reserved memory for
+		 * PORE_SLW_IMA from 0x320000 to 0x39FFFF 
+		 * 
+		 * PORE_SLW_IMA uses this region to dump
+		 * different Nest unit counter data.
+		 * This address is passed to kernel as base
+		 * address to map.
+		 *
+		 * Individual counter offsets are passed in
+		 * the event file of that unit.
+		 */
+		addr = chip->homer_base + SLW_IMA_OFFSET;
+
+		/*
+		 * Entry to search for uncore in kernel
+		 */
+		dt_add_property(dev, "ibm,uncore", NULL, 0);
+
+		/*
+		 * Only expose the Counter storage space in HOMER.
+		 */
+		dt_add_property_u64(dev, "reg", addr);
+		dt_add_property_cells(dev, "size", SLW_IMA_SIZE);
+		dt_add_property_string(dev, "compatible", compat);
+		dt_add_property_cells(dev, "#address-cells", 1);
+		dt_add_property_cells(dev, "#size-cells", 0);
+		dt_add_property_cells(dev, "ibm,chip-id", chip->id);
+
+		/*
+		 * TODO:
+		 * Parse the Catalog lid and get each Nest Unit
+		 * supported to create a DT node here.
+		 */
+		if(dt_create_uncore_types(dev)) {
+			dt_free(dev);
+			break;
+		}
+	}
+}
+
+/*
+ * PORE Thread Scheduler (PTS) schedules PORE Engine Threads
+ * such as PORE_SLW_IMA. Writing to specific scom controls
+ * PTS (big ON/OFF switch).
+ */
+int pore_slw_ima_scom (uint32_t chip_id, uint32_t command)
+{
+	int rc;
+
+	if (command)
+		rc = xscom_write(chip_id, IMA_PTS_SCOM, IMA_PTS_ENABLE);
+	else
+		rc = xscom_write(chip_id, IMA_PTS_SCOM, IMA_PTS_DISABLE);
+
+	return rc;
+}
+
+/*
+ * OPAL call to start and stop PTS.
+ */
+static int64_t opal_uncore_control(uint32_t value)
+{
+	struct proc_chip *chip;
+	int rc = IMA_PTS_ERROR;
+
+	chip = get_chip(pir_to_chip_id(this_cpu()->pir));
+
+	if (value)
+		rc = pore_slw_ima_scom(chip->id, IMA_PTS_START);
+	 else
+		rc = pore_slw_ima_scom(chip->id, IMA_PTS_STOP);
+
+	return rc;
+}
+opal_call (OPAL_UNCORE_CONTROL, opal_uncore_control, 1);