@@ -9045,6 +9045,12 @@ M: Deepak Saxena <dsaxena@plexity.net>
S: Maintained
F: drivers/char/hw_random/ixp4xx-rng.c
+INTEL KEEM BAY DDR SUBSYSTEM, NETWORK ON CHIP INTERCONNECT DRIVER
+M: Pandith N <pandith.n@intel.com>
+S: Supported
+F: drivers/interconnect/intel/
+F: include/uapi/linux/noc_uapi.h
+
INTEL KEEM BAY DRM DRIVER
M: Anitha Chrisanthus <anitha.chrisanthus@intel.com>
M: Edmund Dea <edmund.j.dea@intel.com>
@@ -12,6 +12,7 @@ menuconfig INTERCONNECT
if INTERCONNECT
source "drivers/interconnect/imx/Kconfig"
+source "drivers/interconnect/intel/Kconfig"
source "drivers/interconnect/qcom/Kconfig"
source "drivers/interconnect/samsung/Kconfig"
@@ -5,5 +5,6 @@ icc-core-objs := core.o bulk.o
obj-$(CONFIG_INTERCONNECT) += icc-core.o
obj-$(CONFIG_INTERCONNECT_IMX) += imx/
+obj-$(CONFIG_INTERCONNECT_INTEL) += intel/
obj-$(CONFIG_INTERCONNECT_QCOM) += qcom/
obj-$(CONFIG_INTERCONNECT_SAMSUNG) += samsung/
new file mode 100644
@@ -0,0 +1,19 @@
+# Copyright (C) 2019 Intel Corporation
+# SPDX-License-Identifier: GPL-2.0-only
+config INTERCONNECT_INTEL
+ bool "Intel Network-on-chip interconnect drivers"
+ help
+ Support for Intel's Network on chip interconnect hardware.
+
+config INTERCONNECT_INTEL_KEEMBAY
+ tristate "Intel Keem Bay Enable DDR profiling using NOC"
+ depends on INTERCONNECT_INTEL || ARCH_KEEMBAY || COMPILE_TEST
+ help
+ Enable this option for DDR bandwidth measurements using NOC
+
+ Add support for Network-on-chip (NOC) in DDR Subsystem(DSS).
+ DSS NOC has capabilities to enable and get statistics profiling.
+ NOC driver enables features to configure and capture NOC probe
+ counters, needed for DSS bandwidth measurement.
+ Say Y if using a processor that includes the Intel VPU such as
+ Keem Bay. If unsure, say N.
new file mode 100644
@@ -0,0 +1,5 @@
+# Copyright (C) 2019 Intel Corporation
+# SPDX-License-Identifier: GPL-2.0-only
+# Makefile for Keem Bay NOC
+#
+obj-$(CONFIG_INTERCONNECT_INTEL_KEEMBAY) += keembay-bwmon.o
new file mode 100644
@@ -0,0 +1,305 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (C) 2020 Intel Corporation
+ *
+ * Purpose: Intel Keem Bay NOC bandwidth measurement interface
+ *
+ */
+#include <linux/arm-smccc.h>
+#include <linux/compiler_types.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/noc_uapi.h>
+#include <linux/of_device.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
+#include "keembay-bwmon.h"
+
+/* Filter and counter offset */
+static const int f_offset[] = {0x44, 0x80, 0xbc, 0xf8};
+static const int c_offset[] = {0x134, 0x148, 0x15c, 0x170};
+static struct noc_device noc_dev;
+
+static inline u32 noc_readl(u32 offset)
+{
+ struct arm_smccc_res res;
+
+ arm_smccc_smc(PLATFORM_SIP_SVC_DSS_NOC_PROBE_READ, offset,
+ 0, 0, 0, 0, 0, 0, &res);
+ return res.a1;
+}
+
+static inline void noc_writel(u32 offset, u32 value)
+{
+ struct arm_smccc_res res;
+
+ arm_smccc_smc(PLATFORM_SIP_SVC_DSS_NOC_PROBE_WRITE, offset,
+ value, 0, 0, 0, 0, 0, &res);
+}
+
+/**
+ * flex_noc_setup() - Setup two counters for the NOC probe
+ * @noc: NOC type to setup counters
+ * @counter: Counter number to set up counter n and n+1
+ * @trace_port: trace port number to setup counters
+ *
+ * This function will setup the counters for the trace port given.
+ */
+int flex_noc_setup(enum noc_ss_type noc, enum noc_counter counter, int trace_port)
+{
+ int offset;
+
+ if (noc >= NOC_TYPE_MAX || counter >= NOC_COUNTER_MAX)
+ return -EINVAL;
+
+ offset = f_offset[counter / 2];
+
+ /* Stop ongoing stats */
+ noc_writel(MAINCTL, 0);
+ noc_writel(CFGCTL, 0);
+
+ /* Setup trace port and counters port select */
+ noc_writel(TRACEPORTSEL, trace_port);
+ noc_writel((c_offset[counter] + C_PORTSEL), trace_port);
+ noc_writel((c_offset[counter + 1] + C_PORTSEL), trace_port);
+
+ /* Setup counter sources & triggers, Alarm mode - OFF */
+ noc_writel((c_offset[counter] + C_SRC), COUNTERS_0_SRC_VAL);
+ noc_writel((c_offset[counter] + C_ALARMMODE), COUNTERS_ALARMMODE_VAL);
+ noc_writel((c_offset[counter + 1] + C_SRC), COUNTERS_1_SRC_VAL);
+ noc_writel((c_offset[counter + 1] + C_ALARMMODE),
+ COUNTERS_ALARMMODE_VAL);
+
+ /* Setup filters - RouteID mask, addr base, window size */
+ noc_writel((offset + F_ROUTEIDBASE), 0);
+ noc_writel((offset + F_ROUTEIDMASK), 0);
+ noc_writel((offset + F_ADDRBASE_LOW), 0);
+ noc_writel((offset + F_ADDRBASE_HIGH), 0);
+ noc_writel((offset + F_WINDOWSIZE), FILTER_WINDOW_VAL);
+ noc_writel((offset + F_OPCODE), FILTER_OPCODE_VAL);
+ noc_writel((offset + F_STATUS), FILTER_STATUS_VAL);
+ noc_writel((offset + F_LENGTH), FILTER_OPCODE_VAL);
+
+ return 0;
+}
+
+/**
+ * flexnoc_probe_start() - Start two counters for the NOC probe
+ * @noc: NOC type to setup counters
+ *
+ * This function will start the counters. When this
+ * function returns NOC_PROBE_CAPTURE_STARTED, it is guaranteed that NOC
+ * is setup for probing counters.
+ *
+ */
+enum noc_status flexnoc_probe_start(enum noc_ss_type noc)
+{
+ if (noc >= NOC_TYPE_MAX)
+ return NOC_PROBE_ERR_INVALID_ARGS;
+
+ /* Setting up probe */
+ noc_writel(MAINCTL, (1 << MAINCTL_STATEN_POS));
+ noc_writel(FILTERLUT, 1);
+ noc_writel(STATALARMMIN, 0);
+ noc_writel(STATALARMMAX, 1);
+ noc_writel(STATALARMEN, 1);
+ noc_writel(MAINCTL, ((1 << MAINCTL_STATEN_POS) |
+ (1 << MAINCTL_ALARM_EN_POS) |
+ (1 << MAINCTL_ALWAYS_CHAINABLE_POS)));
+ noc_writel(STATPERIOD, NOC_STATPERIOD_VAL);
+ noc_writel(FILTERLUT, 0x00000001);
+ noc_writel(CFGCTL, 0x00000001);
+
+ return NOC_PROBE_CAPTURE_STARTED;
+}
+
+/**
+ * flexnoc_counterp_capture() - Capture the counter statistic values
+ * @noc: NOC type to setup counters
+ * @counter: Counter number to capture statistics values for n and n+1
+ * @value: statistics values read are returned in this address passed
+ *
+ * This function will return the statistics value of started counters.
+ * When this function returns NOC_PROBE_COMPLETED, it is guaranteed that NOC
+ * counters are idle and finished probing.
+ * Algo : The values should not returned when counters are active/running.
+ * Once the counter is frozen, the values are good to read. There is an
+ * iteration logic implemented to check this. An maximum timeout config
+ * is provided to for capture timeout - NOC_CAPTURE_TIMEOUT_MSEC
+ *
+ */
+enum noc_status flexnoc_counter_capture(enum noc_ss_type noc,
+ enum noc_counter counter, u32 *value)
+{
+ unsigned long j0, j1, delay;
+ u32 c0_0, c0_1;
+
+ if (noc >= NOC_TYPE_MAX ||
+ counter >= NOC_COUNTER_MAX ||
+ !value)
+ return NOC_PROBE_ERR_INVALID_ARGS;
+
+ delay = msecs_to_jiffies(NOC_CAPTURE_TIMEOUT_MSEC);
+ j0 = jiffies;
+ j1 = j0 + delay;
+ do {
+ c0_0 = noc_readl((c_offset[counter] + C_VAL));
+ usleep_range(10000, 11000);
+ c0_1 = noc_readl((c_offset[counter] + C_VAL));
+ /* If mainctrl is zero , return error */
+ if (noc_readl(MAINCTL) == 0)
+ return NOC_PROBE_ERR_IN_PROGRESS;
+ /* If counters are zero, keep reading */
+ if (0 == c0_0 && 0 == c0_1) {
+ break;
+ } else if (c0_0 != c0_1) {
+ continue;
+ } else {
+ /* counters look good break the while */
+ break;
+ }
+ } while (time_before(jiffies, j1));
+
+ if (c0_0 != c0_1)
+ return NOC_PROBE_ERR_IN_PROGRESS;
+
+ c0_0 = noc_readl((c_offset[counter] + C_VAL));
+ c0_1 = noc_readl((c_offset[counter + 1] + C_VAL));
+ *value = (c0_0 | (c0_1 << 16));
+
+ return NOC_PROBE_COMPLETED;
+}
+
+static long noc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct flexnoc_countercapture capture_data;
+ void __user *argp = (void __user *)arg;
+ struct flexnoc_probestart probe_data;
+ struct flexnoc_setup setup_data;
+ int rc;
+
+ if (!arg) {
+ pr_err("NOC: Null pointer from user\n");
+ return -EINVAL;
+ }
+ switch (cmd) {
+ case NOC_SETUP:
+ if (copy_from_user(&setup_data,
+ argp, sizeof(setup_data))) {
+ return -EFAULT;
+ }
+ rc = flex_noc_setup(setup_data.noc_type, setup_data.counter,
+ setup_data.traceport);
+ setup_data.ret_id = rc;
+
+ if (copy_to_user(argp,
+ &setup_data, sizeof(setup_data))) {
+ return -EFAULT;
+ }
+ break;
+ case NOC_PROBE_START:
+ if (copy_from_user(&probe_data, argp,
+ sizeof(probe_data))) {
+ return -EFAULT;
+ }
+ rc = flexnoc_probe_start(probe_data.noc_type);
+ probe_data.ret_id = rc;
+
+ if (copy_to_user(argp,
+ &probe_data, sizeof(probe_data))) {
+ return -EFAULT;
+ }
+ break;
+ case NOC_COUNTER_CAPTURE:
+ if (copy_from_user(&capture_data, argp,
+ sizeof(capture_data))) {
+ return -EFAULT;
+ }
+ rc = flexnoc_counter_capture(capture_data.noc_type,
+ capture_data.counter,
+ &capture_data.bw_res);
+ capture_data.ret_id = rc;
+
+ if (copy_to_user(argp, &capture_data,
+ sizeof(capture_data))) {
+ return -EFAULT;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static const struct file_operations noc_fops = {
+ .owner = THIS_MODULE,
+ .unlocked_ioctl = noc_ioctl,
+};
+
+static int intel_noc_cdev_init(struct noc_device *nocdev)
+{
+ if ((alloc_chrdev_region(&nocdev->cdev, 0, 1, "nocdev")) < 0) {
+ pr_err("Cannot allocate major number for NOC\n");
+ return -EINVAL;
+ }
+
+ cdev_init(&nocdev->noc_cdev, &noc_fops);
+ if ((cdev_add(&nocdev->noc_cdev, nocdev->cdev, 1)) < 0) {
+ pr_err("Cannot add NOC device to the system\n");
+ goto r_class;
+ }
+
+ nocdev->dev_class = class_create(THIS_MODULE, "noc_class");
+ if (!nocdev->dev_class) {
+ pr_err("Cannot create the NOC class\n");
+ cdev_del(&nocdev->noc_cdev);
+ goto r_class;
+ }
+
+ if ((device_create(nocdev->dev_class, NULL, nocdev->cdev,
+ NULL, "noc")) == NULL) {
+ pr_err("Cannot create NOC device\n");
+ cdev_del(&nocdev->noc_cdev);
+ goto r_cdev;
+ }
+
+ return 0;
+
+r_cdev:
+ class_destroy(nocdev->dev_class);
+r_class:
+ unregister_chrdev_region(nocdev->cdev, 1);
+ return -EINVAL;
+}
+
+static void intel_noc_cdev_exit(struct noc_device *nocdev)
+{
+ cdev_del(&nocdev->noc_cdev);
+ class_destroy(nocdev->dev_class);
+ unregister_chrdev_region(nocdev->cdev, 1);
+}
+
+static int __init noc_driver_module_init(void)
+{
+ int ret;
+
+ ret = intel_noc_cdev_init(&noc_dev);
+ if (ret)
+ pr_err("NOC char device init failed\n");
+ return ret;
+}
+
+static void noc_driver_module_exit(void)
+{
+ intel_noc_cdev_exit(&noc_dev);
+}
+
+module_init(noc_driver_module_init);
+module_exit(noc_driver_module_exit);
+
+MODULE_DESCRIPTION("Intel Keem Bay NOC interconnect driver");
+MODULE_AUTHOR("Pandith N <pandith.n@intel.com>");
+MODULE_AUTHOR("Sudarshan Ravula <sudarshan.ravula@intel.com>");
+MODULE_LICENSE("GPL");
new file mode 100644
@@ -0,0 +1,110 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (C) 2020 Intel Corporation
+ *
+ * Purpose: Intel Keem Bay NOC bandwidth measurement interface
+ *
+ */
+#ifndef LINUX_NOCDRIVER_H
+#define LINUX_NOCDRIVER_H
+
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/types.h>
+#include <uapi/linux/noc_uapi.h>
+
+/**
+ * enum noc_status - NOC probe status
+ * @NOC_PROBE_CAPTURE_STARTED: Probe counters monitoring started
+ * @NOC_PROBE_ERR_IN_PROGRESS: Probe counters are active, capture failure
+ * @NOC_PROBE_ERR_INVALID_ARGS: NOC error, Invalid arguments passed
+ * @NOC_PROBE_ERR_COMPLETED: NOC counter values captured successfully
+ */
+enum noc_status {
+ NOC_PROBE_CAPTURE_STARTED,
+ NOC_PROBE_ERR_IN_PROGRESS,
+ NOC_PROBE_ERR_INVALID_ARGS,
+ NOC_PROBE_COMPLETED,
+};
+
+/**
+ * enum noc_counter - NOC counter
+ * @NOC_COUNTER_0: NOC Counter 0
+ * @NOC_COUNTER_1: NOC Counter 1
+ */
+enum noc_counter {
+ NOC_COUNTER_0,
+ NOC_COUNTER_1,
+ NOC_COUNTER_2,
+ NOC_COUNTER_MAX
+};
+
+/* NOC Control Register Probe offsets */
+#define ID_COREID 0x0000
+#define ID_REVISIONID 0x0004
+#define MAINCTL 0x0008
+#define CFGCTL 0x000C
+#define TRACEPORTSEL 0x0010
+#define FILTERLUT 0x0014
+#define TRACEALARMEN 0x0018
+#define TRACEALARMSTATUS 0x001C
+#define TRACEALARMCLR 0x0020
+#define STATPERIOD 0x0024
+#define STATGO 0x0028
+#define STATALARMMIN 0x002C
+#define STATALARMMAX 0x0030
+#define STATALARMSTATUS 0x0034
+#define STATALARMCLR 0x0038
+#define STATALARMEN 0x003C
+
+/* NOC Filter Registers offsets */
+#define F_ROUTEIDBASE 0x0000
+#define F_ROUTEIDMASK 0x0004
+#define F_ADDRBASE_LOW 0x0008
+#define F_ADDRBASE_HIGH 0x000C
+#define F_WINDOWSIZE 0x0010
+#define F_OPCODE 0x001C
+#define F_STATUS 0x0020
+#define F_LENGTH 0x0024
+#define F_URGENCY 0x0028
+#define F_USERBASE 0x002C
+#define F_USERMASK 0x0030
+
+/* NOC Counter Registers offsets */
+#define C_PORTSEL 0x0000
+#define C_SRC 0x0004
+#define C_ALARMMODE 0x0008
+#define C_VAL 0x000C
+
+/* NOC register secure access r/w */
+#define PLATFORM_SIP_SVC_DSS_NOC_PROBE_READ (0x8200ff28)
+#define PLATFORM_SIP_SVC_DSS_NOC_PROBE_WRITE (0x8200ff29)
+
+/* Timeout(msec) for checking active counters */
+#define NOC_CAPTURE_TIMEOUT_MSEC 2000
+#define NOC_STATPERIOD_VAL 0x1B
+
+#define COUNTERS_0_SRC_VAL 0x14
+#define COUNTERS_1_SRC_VAL 0x10
+#define COUNTERS_ALARMMODE_VAL 0x02
+#define FILTER_WINDOW_VAL 0xFFFFFFFF
+#define FILTER_OPCODE_VAL 0x0F
+#define FILTER_STATUS_VAL 0x03
+#define FILTER_LENGTH_VAL 0x03
+
+/* NOC Probe Main controli register fields */
+#define MAINCTL_STATEN_POS 3
+#define MAINCTL_ALARM_EN_POS 4
+#define MAINCTL_ALWAYS_CHAINABLE_POS 7
+
+struct noc_device {
+ struct class *dev_class;
+ struct cdev noc_cdev;
+ dev_t cdev;
+};
+
+int flex_noc_setup(enum noc_ss_type noc, enum noc_counter counter, int trace_port);
+enum noc_status flexnoc_probe_start(enum noc_ss_type noc);
+enum noc_status flexnoc_counter_capture(enum noc_ss_type noc,
+ enum noc_counter counter, u32 *value);
+
+#endif
new file mode 100644
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/* Copyright (C) 2020 Intel Corporation
+ *
+ * Purpose: Intel Keem Bay NOC interface for user space access.
+ */
+
+#ifndef __NOC_UAPI_H
+#define __NOC_UAPI_H
+
+#include <linux/types.h>
+
+#define NOC_MAGIC 'n'
+#define NOC_SETUP _IOW(NOC_MAGIC, 1, void*)
+#define NOC_PROBE_START _IOW(NOC_MAGIC, 2, void*)
+#define NOC_COUNTER_CAPTURE _IOW(NOC_MAGIC, 3, void*)
+
+enum noc_ss_type {
+ DSS_NOC = 0,
+ NOC_TYPE_MAX
+};
+
+struct flexnoc_setup {
+ enum noc_ss_type noc_type;
+ __u16 counter;
+ __u16 traceport;
+ __u16 ret_id;
+};
+
+struct flexnoc_probestart {
+ enum noc_ss_type noc_type;
+ __u16 ret_id;
+ __u32 captime;
+};
+
+struct flexnoc_countercapture {
+ enum noc_ss_type noc_type;
+ __u32 bw_res;
+ __u16 counter;
+ __u16 ret_id;
+};
+
+#endif /*_NOC__UAPI_H*/