[ipq806x] Bus scaling APIs for all NSS drivers - HLOS, GMAC and Crypto
CRs-Fixed: 572301
Change-Id: Ibe0985f7c468c4e80478d019ac4b9e9abc0992ca
Signed-off-by: Pamidipati, Vijay <vpamidip@codeaurora.org>
diff --git a/Makefile b/Makefile
index cdc94c7..bc2cd5c 100755
--- a/Makefile
+++ b/Makefile
@@ -17,7 +17,7 @@
# ###################################################
obj-m += qca-nss-drv.o
-qca-nss-drv-objs := nss_init.o nss_core.o nss_tx_rx.o nss_stats.o
+qca-nss-drv-objs := nss_init.o nss_core.o nss_tx_rx.o nss_stats.o nss_pm.o
obj-m += qca-nss-connmgr-ipv4.o
obj-m += qca-nss-connmgr-ipv6.o
@@ -35,6 +35,7 @@
ccflags-y += -I$(obj)/nss_hal/include -DNSS_DEBUG_LEVEL=0 -DNSS_EMPTY_BUFFER_SIZE=1792 -DNSS_PKT_STATS_ENABLED=0
ccflags-y += -DNSS_CONNMGR_DEBUG_LEVEL=0
ccflags-y += -DNSS_TUNIPIP6_DEBUG_LEVEL=0
+ccflags-y += -DNSS_PM_DEBUG_LEVEL=0
obj ?= .
diff --git a/nss_api_if.h b/nss_api_if.h
index 5a17259..1d9f33f 100755
--- a/nss_api_if.h
+++ b/nss_api_if.h
@@ -94,6 +94,28 @@
uint32_t event; /* NSS_LAG_{RELEASE/ENSLAVE} */
};
+/*
+ * @brief NSS PM Clients
+ * NSS clients that can request for Bus/Clock performance levels
+ **/
+typedef enum nss_pm_client {
+ NSS_PM_CLIENT_GMAC,
+ NSS_PM_CLIENT_CRYPTO,
+ NSS_PM_CLIENT_NETAP,
+ NSS_PM_MAX_CLIENTS,
+} nss_pm_client_t;
+
+/**
+ * @brief NSS Performance Levels
+ * This is passed as parameter to NSS PM perf level requests
+ */
+typedef enum nss_pm_perf_level {
+ NSS_PM_PERF_LEVEL_SUSPEND = 0,
+ NSS_PM_PERF_LEVEL_IDLE,
+ NSS_PM_PERF_LEVEL_NOMINAL,
+ NSS_PM_PERF_LEVEL_TURBO,
+ NSS_PM_PERF_MAX_LEVELS,
+} nss_pm_perf_level_t;
/**
* IPv4 rule sync reasons.
@@ -511,6 +533,14 @@
} nss_cb_unregister_status_t;
/**
+ * PM Client interface status
+ */
+typedef enum {
+ NSS_PM_API_SUCCESS = 0,
+ NSS_PM_API_FAILED,
+} nss_pm_interface_status_t;
+
+/**
* NSS GMAC event type
*/
typedef enum {
@@ -1047,5 +1077,31 @@
*/
nss_tx_status_t nss_freq_change(void *ctx, uint32_t eng, uint32_t start_or_end);
+/**
+ * @brief Register PM Driver Client
+ *
+ * @param client_id Identifies the Client driver registering with PM driver
+ *
+ * @return
+ */
+extern void *nss_pm_client_register(nss_pm_client_t client_id);
+
+/**
+ * @brief Unregister PM Driver Client
+ *
+ * @param client_id Identifies the Client driver registering with PM driver
+ *
+ * @return
+ */
+int nss_pm_client_unregister(nss_pm_client_t client_id);
+
+/**
+ * @brief Update Bus Bandwidth level for a client
+ *
+ * @param handle - Client Handle
+ * @param lvl - Perf Level
+ */
+extern nss_pm_interface_status_t nss_pm_set_perf_level(void *handle, nss_pm_perf_level_t lvl);
+
/**@}*/
#endif /** __NSS_API_IF_H */
diff --git a/nss_init.c b/nss_init.c
index 6547bd5..ccb2f07 100755
--- a/nss_init.c
+++ b/nss_init.c
@@ -19,8 +19,9 @@
* NSS init APIs
*
*/
-
#include "nss_core.h"
+#include "nss_pm.h"
+
#include <nss_hal.h>
#include <nss_clocks.h>
@@ -693,6 +694,11 @@
nss_wq = create_workqueue("nss_freq_queue");
/*
+ * Initialize NSS Bus PM module
+ */
+ nss_pm_init();
+
+ /*
* Register platform_driver
*/
return platform_driver_register(&nss_driver);
diff --git a/nss_pm.c b/nss_pm.c
new file mode 100644
index 0000000..01bbb80
--- /dev/null
+++ b/nss_pm.c
@@ -0,0 +1,332 @@
+
+/*
+ **************************************************************************
+ * Copyright (c) 2013, Qualcomm Atheros, Inc.
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all copies.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ **************************************************************************
+ */
+/*
+ * nss_pm.c
+ * NSS Power Management APIs
+ *
+ */
+#include <linux/debugfs.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+
+#include "nss_pm.h"
+
+/*
+ * Global NSS PM structure
+ */
+struct nss_pm_global_ctx ctx;
+
+/*
+ * Bus vector table for GMAC driver
+ */
+static struct msm_bus_paths nss_gmac_bw_level_tbl[NSS_PM_PERF_MAX_LEVELS] = {
+ [NSS_PM_PERF_LEVEL_SUSPEND] = GMAC_BW_MBPS(0, 0),
+ /* 0 MHz to DDR, 0 MHz to TCM */
+ [NSS_PM_PERF_LEVEL_IDLE] = GMAC_BW_MBPS(133, 5),
+ /* 133 MHz to DDR, 5 MHz to TCM */
+ [NSS_PM_PERF_LEVEL_NOMINAL] = GMAC_BW_MBPS(200, 400),
+ /* 200 MHz to DDR, 10 MHz to TCM */
+ [NSS_PM_PERF_LEVEL_TURBO] = GMAC_BW_MBPS(266, 533),
+ /* 266 MHz to DDR, 20 MHz to TCM */
+};
+
+/*
+ * Bus vector table for Crypto driver
+ */
+static struct msm_bus_paths nss_crypto_bw_level_tbl[NSS_PM_PERF_MAX_LEVELS] = {
+ [NSS_PM_PERF_LEVEL_SUSPEND] = CRYPTO_BW_MBPS(0, 0),
+ /* 0 MHz to DDR, 0 MHz to TCM */
+ [NSS_PM_PERF_LEVEL_IDLE] = CRYPTO_BW_MBPS(133, 5),
+ /* 133 MHz to DDR, 5 MHz to TCM */
+ [NSS_PM_PERF_LEVEL_NOMINAL] = CRYPTO_BW_MBPS(200, 400),
+ /* 200 MHz to DDR, 10 MHz to TCM */
+ [NSS_PM_PERF_LEVEL_TURBO] = CRYPTO_BW_MBPS(266, 533),
+ /* 266 MHz to DDR, 20 MHz to TCM */
+};
+
+/*
+ * Bus vector table for NSS HLOS driver
+ */
+static struct msm_bus_paths nss_netap_bw_level_tbl[NSS_PM_PERF_MAX_LEVELS] = {
+ [NSS_PM_PERF_LEVEL_SUSPEND] = NETAP_BW_MBPS(0, 0),
+ /* 0 MHz to DDR, 0 MHz to TCM */
+ [NSS_PM_PERF_LEVEL_IDLE] = NETAP_BW_MBPS(133, 133),
+ /* 133 MHz to DDR and TCM */
+ [NSS_PM_PERF_LEVEL_NOMINAL] = NETAP_BW_MBPS(400, 400),
+ /* 400 MHz to DDR and TCM */
+ [NSS_PM_PERF_LEVEL_TURBO] = NETAP_BW_MBPS(533, 533),
+ /* 533 MHz to DDR and TCM */
+};
+
+/*
+ * Bus Driver Platform data for GMAC, Crypto and Netap clients
+ */
+static struct msm_bus_scale_pdata nss_bus_scale[] = {
+ [NSS_PM_CLIENT_GMAC] = {
+ .usecase = nss_gmac_bw_level_tbl,
+ .num_usecases = ARRAY_SIZE(nss_gmac_bw_level_tbl),
+ .active_only = 1,
+ .name = "qca-nss-gmac",
+ },
+
+ [NSS_PM_CLIENT_CRYPTO] = {
+ .usecase = nss_crypto_bw_level_tbl,
+ .num_usecases = ARRAY_SIZE(nss_crypto_bw_level_tbl),
+ .active_only = 1,
+ .name = "qca-nss-crypto",
+ },
+
+ [NSS_PM_CLIENT_NETAP] = {
+ .usecase = nss_netap_bw_level_tbl,
+ .num_usecases = ARRAY_SIZE(nss_netap_bw_level_tbl),
+ .active_only = 1,
+ .name = "qca-nss-drv",
+ },
+};
+
+/*
+ * nss_pm_dbg_perf_level_get
+ * debugfs hook to get the current performance level
+ */
+static int nss_pm_dbg_perf_level_get(void *data, u64 *val)
+{
+ nss_pm_client_data_t *pm_client;
+
+ pm_client = (nss_pm_client_data_t *)data;
+ *val = pm_client->current_perf_lvl;
+
+ return NSS_PM_API_SUCCESS;
+}
+
+/*
+ * nss_pm_dbg_autoscale_get
+ * debugfs hook to get the current autoscale setting
+ */
+static int nss_pm_dbg_autoscale_get(void *data, u64 *val)
+{
+ nss_pm_client_data_t *pm_client;
+
+ pm_client = (nss_pm_client_data_t *)data;
+ *val = pm_client->auto_scale;
+
+ return NSS_PM_API_SUCCESS;
+}
+
+/*
+ * nss_pm_dbg_perf_level_set
+ * debugfs hook to set perf level for a client
+ */
+static int nss_pm_dbg_perf_level_set(void *data, u64 val)
+{
+ uint32_t perf_level;
+
+ perf_level = (uint32_t) val;
+
+ if (perf_level >= NSS_PM_PERF_MAX_LEVELS ||
+ perf_level < NSS_PM_PERF_LEVEL_IDLE) {
+ nss_pm_warning("unsupported performance level %d \n", perf_level);
+ return NSS_PM_API_FAILED;
+ }
+
+ nss_pm_set_perf_level(data, perf_level);
+ return NSS_PM_API_SUCCESS;
+}
+
+/*
+ * nss_pm_dbg_autoscale_set
+ * debugfs hook to enable auto scaling for a client
+ */
+static int nss_pm_dbg_autoscale_set(void *data, u64 val)
+{
+ nss_pm_client_data_t *pm_client;
+
+ if (val > 1) {
+ nss_pm_warning(" Invalid set value, valid values are 0/1 \n");
+ return NSS_PM_API_FAILED;
+ }
+
+ pm_client->auto_scale = (uint32_t)val;
+ return NSS_PM_API_SUCCESS;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(perf_level_fops, nss_pm_dbg_perf_level_get, nss_pm_dbg_perf_level_set, "%llu\n");
+
+DEFINE_SIMPLE_ATTRIBUTE(autoscale_fops, nss_pm_dbg_autoscale_get, nss_pm_dbg_autoscale_set, "%llu\n");
+
+/*
+ * nss_pm_client_register
+ * Initialize GMAC specific PM parameters
+ *
+ * Creates debugfs hooks for user-space control of NSS Client PM
+ * Initializes Bus BW to Idle Perf level
+ * Returns PM handle to the caller.
+ *
+ */
+void *nss_pm_client_register(nss_pm_client_t client_id)
+{
+ int ret;
+ struct dentry *pm_dentry;
+ nss_pm_client_data_t *pm_client;
+
+ if (unlikely(client_id >= NSS_PM_MAX_CLIENTS)) {
+ nss_pm_warning("nss_pm_client_register invalid client id %d \n", client_id);
+ goto error;
+ }
+
+ pm_client = &ctx.nss_pm_client[client_id];
+
+ pm_client->bus_perf_client = msm_bus_scale_register_client(&nss_bus_scale[client_id]);
+ if (!pm_client->bus_perf_client) {
+ nss_pm_warning("unable to register bus client \n");
+ goto error;
+ }
+
+ ret = msm_bus_scale_client_update_request(pm_client->bus_perf_client, NSS_PM_PERF_LEVEL_IDLE);
+ if (ret) {
+ nss_pm_warning("initial bandwidth req failed (%d)\n", ret);
+ msm_bus_scale_unregister_client((uint32_t) pm_client->bus_perf_client);
+ goto error;
+ }
+
+ pm_client->current_perf_lvl = NSS_PM_PERF_LEVEL_IDLE;
+
+ switch (client_id) {
+ case NSS_PM_CLIENT_GMAC:
+ pm_dentry = debugfs_create_dir("gmac" , ctx.pm_dentry);
+ break;
+
+ case NSS_PM_CLIENT_CRYPTO:
+ pm_dentry = debugfs_create_dir("crypto" , ctx.pm_dentry);
+ break;
+
+ case NSS_PM_CLIENT_NETAP:
+ pm_dentry = debugfs_create_dir("netap" , ctx.pm_dentry);
+ break;
+
+ default:
+ nss_pm_warning("debugfs create failed invalid client id %d \n", client_id);
+ msm_bus_scale_unregister_client((uint32_t) pm_client->bus_perf_client);
+ goto error;
+
+ }
+
+ if (unlikely(pm_dentry == NULL)) {
+ nss_pm_info("debugfs not created for %d client pm \n", client_id);
+ goto out;
+ }
+
+ pm_client->dentry = pm_dentry;
+
+ if (!debugfs_create_file("perf_level", S_IRUGO | S_IWUSR, pm_dentry, pm_client, &perf_level_fops)) {
+ nss_pm_info("debugfs perf_level file not created for %d client pm \n", client_id);
+ }
+
+ if (!debugfs_create_file("auto-scale", S_IRUGO | S_IWUSR, pm_dentry, pm_client, &autoscale_fops)) {
+ nss_pm_info("debugfs auto-scale file not created for %d client pm \n", client_id);
+ }
+
+out:
+ return (void *)pm_client;
+error:
+ return NULL;
+}
+EXPORT_SYMBOL(nss_pm_client_register);
+
+/*
+ * nss_pm_client_unregister
+ * Unregister the client for any PM operations
+ */
+int nss_pm_client_unregister(nss_pm_client_t client_id)
+{
+ nss_pm_client_data_t *pm_client;
+
+ if (unlikely(client_id >= NSS_PM_MAX_CLIENTS)) {
+ nss_pm_warning("nss_pm_client_unregister invalid client id %d \n", client_id);
+ goto error;
+ }
+
+ pm_client = &ctx.nss_pm_client[client_id];
+
+ if (unlikely(pm_client == NULL)) {
+ nss_pm_warning("nss_pm_client_unregister client not registered %d \n", client_id);
+ goto error;
+ }
+
+ if (pm_client->bus_perf_client) {
+ msm_bus_scale_unregister_client((uint32_t) pm_client->bus_perf_client);
+ } else {
+ nss_pm_info("nss_pm_client_unregister: client not registered \n");
+ }
+
+ if (likely(pm_client->dentry != NULL)) {
+ debugfs_remove_recursive(pm_client->dentry);
+ }
+
+ return NSS_PM_API_SUCCESS;
+
+error:
+ return NSS_PM_API_FAILED;
+}
+
+/*
+ * nss_pm_set_perf_level()
+ * Sets the performance level of client specific Fabrics and Clocks to requested level
+ */
+nss_pm_interface_status_t nss_pm_set_perf_level(void *handle, nss_pm_perf_level_t lvl)
+{
+ int ret = 0;
+ nss_pm_client_data_t *pm_client;
+
+ pm_client = (nss_pm_client_data_t *) handle;
+ if (pm_client->current_perf_lvl == lvl) {
+ nss_pm_trace("Already at perf level %d , ignoring request \n", lvl);
+ return NSS_PM_API_SUCCESS;
+ }
+
+ if (!pm_client->bus_perf_client) {
+ nss_pm_warning("Bus driver client not registered.request failed \n");
+ return NSS_PM_API_FAILED;
+ }
+
+ /* Update bandwidth if request has changed. This may sleep. */
+ ret = msm_bus_scale_client_update_request(pm_client->bus_perf_client, lvl);
+ if (ret) {
+ nss_pm_warning("bandwidth request failed (%d)\n", ret);
+ return NSS_PM_API_FAILED;
+ }
+
+ nss_pm_info("perf level request, current: %d new: %d \n", pm_client->current_perf_lvl, lvl);
+ pm_client->current_perf_lvl = lvl;
+
+ return NSS_PM_API_SUCCESS;
+}
+EXPORT_SYMBOL(nss_pm_set_perf_level);
+
+/*
+ * nss_pm_init()
+ * Initialize NSS PM top level structures
+ */
+void nss_pm_init(void) {
+
+ nss_pm_info("NSS Bus PM (platform - IPQ806x, build - %s:%s)\n", __DATE__, __TIME__);
+
+ ctx.pm_dentry = debugfs_create_dir("qca-nss-pm", NULL);
+
+ if (unlikely(ctx.pm_dentry == NULL)) {
+ nss_pm_warning("Failed to create qca-nss-drv directory in debugfs");
+ }
+}
diff --git a/nss_pm.h b/nss_pm.h
new file mode 100644
index 0000000..df728dd
--- /dev/null
+++ b/nss_pm.h
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2013, Qualcomm Atheros Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * nss_pm.h
+ * NSS PM Driver header file
+ */
+
+#ifndef __NSS_PM_H
+#define __NSS_PM_H
+
+#include <mach/msm_nss_gmac.h>
+#include <mach/msm_nss_crypto.h>
+#include <mach/msm_bus_board.h>
+#include <mach/msm_bus.h>
+#include "nss_api_if.h"
+
+/*
+ * NSS PM debug macros
+ */
+#if (NSS_PM_DEBUG_LEVEL < 1)
+#define nss_pm_assert(fmt, args...)
+#else
+#define nss_pm_assert(c) if (!(c)) { BUG_ON(!(c)); }
+#endif
+
+#if (NSS_PM_DEBUG_LEVEL < 2)
+#define nss_pm_warning(fmt, args...)
+#else
+#define nss_pm_warning(fmt, args...) printk(KERN_WARNING "nss_pm:"fmt, ##args)
+#endif
+
+#if (NSS_PM_DEBUG_LEVEL < 3)
+#define nss_pm_info(fmt, args...)
+#else
+#define nss_pm_info(fmt, args...) printk(KERN_INFO "nss_pm:"fmt, ##args)
+#endif
+
+#if (NSS_PM_DEBUG_LEVEL < 4)
+#define nss_pm_trace(fmt, args...)
+#else
+#define nss_pm_trace(fmt, args...) printk(KERN_DEBUG "nss_pm:"fmt, ##args)
+#endif
+
+
+/*
+ * PM Client data structure
+ */
+typedef struct {
+ uint32_t bus_perf_client;
+ uint32_t clk_handle;
+ uint32_t current_perf_lvl;
+ uint32_t auto_scale;
+ struct dentry *dentry;
+} nss_pm_client_data_t;
+
+/*
+ * NSS PM driver context
+ */
+struct nss_pm_global_ctx {
+ struct dentry *pm_dentry;
+ nss_pm_client_data_t nss_pm_client[NSS_PM_MAX_CLIENTS];
+};
+
+/*
+ * Macro defining Bus vector for GMAC driver
+ */
+#define GMAC_BW_MBPS(_data_bw, _desc_bw) \
+{ \
+ .vectors = (struct msm_bus_vectors[]){ \
+ {\
+ .src = MSM_BUS_MASTER_NSS_GMAC_0, \
+ .dst = MSM_BUS_SLAVE_EBI_CH0, \
+ .ab = (_data_bw) * 16 * 1000000ULL, \
+ .ib = (_data_bw) * 16 * 1000000ULL, \
+ }, \
+ { \
+ .src = MSM_BUS_MASTER_NSS_GMAC_0, \
+ .dst = MSM_BUS_SLAVE_NSS_TCM, \
+ .ab = (_desc_bw) * 8 * 1000000ULL, \
+ .ib = (_desc_bw) * 8 * 1000000ULL, \
+ }, \
+ }, \
+ .num_paths = 2, \
+}
+
+/*
+ * Macro defining Bus vector for NSS crypto driver
+ */
+#define CRYPTO_BW_MBPS(_data_bw, _desc_bw) \
+{ \
+ .vectors = (struct msm_bus_vectors[]){ \
+ {\
+ .src = MSM_BUS_MASTER_NSS_CRYPTO5_0, \
+ .dst = MSM_BUS_SLAVE_EBI_CH0, \
+ .ab = (_data_bw) * 16 * 1000000ULL, \
+ .ib = (_data_bw) * 16 * 1000000ULL, \
+ }, \
+ { \
+ .src = MSM_BUS_MASTER_NSS_CRYPTO5_0, \
+ .dst = MSM_BUS_SLAVE_NSS_TCM, \
+ .ab = (_desc_bw) * 8 * 1000000ULL, \
+ .ib = (_desc_bw) * 8 * 1000000ULL, \
+ }, \
+ }, \
+ .num_paths = 2, \
+}
+
+/*
+ * Macro defining Bus vector for NSS driver
+ *
+ */
+#define NETAP_BW_MBPS(_data_bw, _desc_bw) \
+{ \
+ .vectors = (struct msm_bus_vectors[]){ \
+ {\
+ .src = MSM_BUS_MASTER_UBI32_0, \
+ .dst = MSM_BUS_SLAVE_EBI_CH0, \
+ .ab = (_data_bw) * 16 * 1000000ULL, \
+ .ib = (_data_bw) * 16 * 1000000ULL, \
+ }, \
+ { \
+ .src = MSM_BUS_MASTER_UBI32_0, \
+ .dst = MSM_BUS_SLAVE_NSS_TCM, \
+ .ab = (_desc_bw) * 8 * 1000000ULL, \
+ .ib = (_desc_bw) * 8 * 1000000ULL, \
+ }, \
+ }, \
+ .num_paths = 2, \
+}
+
+/*
+ * Initialize NSS PM top level structures
+ */
+void nss_pm_init(void);
+
+#endif /** __NSS_PM_H */