[qca-nss-drv] Make N2H queue limit configurable.
Allow N2H queue size limit to be made configurable through a
procfs entry. This allows fine tuning of host path data
queues and can improve host path performance.
Change-Id: Ia6b17028d396e6a2889468ede77af1f141147ca0
Signed-off-by: Shashank Balashankar <sbalasha@codeaurora.org>
diff --git a/nss_n2h.c b/nss_n2h.c
index d962fa1..463f924 100644
--- a/nss_n2h.c
+++ b/nss_n2h.c
@@ -37,6 +37,7 @@
int nss_n2h_core1_mitigation_cfg __read_mostly = 1;
int nss_n2h_core0_add_buf_pool_size __read_mostly;
int nss_n2h_core1_add_buf_pool_size __read_mostly;
+int nss_n2h_queue_limit[NSS_MAX_CORES] __read_mostly = {NSS_DEFAULT_QUEUE_LIMIT, NSS_DEFAULT_QUEUE_LIMIT};
struct nss_n2h_registered_data {
nss_n2h_msg_callback_t n2h_callback;
@@ -50,6 +51,7 @@
static struct nss_n2h_cfg_pvt nss_n2h_bufcp[NSS_CORE_MAX];
static struct nss_n2h_cfg_pvt nss_n2h_wp;
static struct nss_n2h_cfg_pvt nss_n2h_q_cfg_pvt;
+static struct nss_n2h_cfg_pvt nss_n2h_q_lim_pvt;
/*
* nss_n2h_interface_handler()
@@ -1376,6 +1378,121 @@
return -EINVAL;
}
+/*
+ * nss_n2h_queue_limit_callback()
+ * Callback to handle the completion of queue limit command.
+ */
+static void nss_n2h_queue_limit_callback(void *app_data, struct nss_n2h_msg *nim)
+{
+ if (nim->cm.response != NSS_CMN_RESPONSE_ACK) {
+ nss_warning("n2h error response %d\n", nim->cm.response);
+ }
+
+ nss_n2h_q_lim_pvt.response = nim->cm.response;
+ complete(&nss_n2h_q_lim_pvt.complete);
+}
+
+/*
+ * nss_n2h_set_queue_limit_sync()
+ * Sets the n2h queue size limit synchronously.
+ */
+static int nss_n2h_set_queue_limit_sync(struct ctl_table *ctl, int write, void __user *buffer,
+ size_t *lenp, loff_t *ppos, uint32_t core_id)
+{
+ struct nss_top_instance *nss_top = &nss_top_main;
+ struct nss_ctx_instance *nss_ctx = &nss_top->nss[core_id];
+ struct nss_n2h_msg nim;
+ struct nss_n2h_queue_limit_config *nnqlc = NULL;
+ int ret, current_val;
+ nss_tx_status_t nss_tx_status;
+
+ /*
+ * Take a snap shot of current value
+ */
+ current_val = nss_n2h_queue_limit[core_id];
+
+ /*
+ * Write the variable with user input
+ */
+ ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
+ if (ret || (!write)) {
+ return ret;
+ }
+
+ /*
+ * We dont allow shortening of the queue size at run-time
+ */
+ if (nss_n2h_queue_limit[core_id] < current_val) {
+ nss_warning("%p: New queue limit %d less than previous value %d. Cant allow shortening\n",
+ nss_ctx, nss_n2h_queue_limit[core_id], current_val);
+ nss_n2h_queue_limit[core_id] = current_val;
+ return NSS_TX_FAILURE;
+ }
+
+ memset(&nim, 0, sizeof(struct nss_n2h_msg));
+ nss_n2h_msg_init(&nim, NSS_N2H_INTERFACE,
+ NSS_TX_METADATA_TYPE_N2H_QUEUE_LIMIT_CFG,
+ sizeof(struct nss_n2h_queue_limit_config), nss_n2h_queue_limit_callback, NULL);
+
+ nnqlc = &nim.msg.ql_cfg;
+ nnqlc->qlimit = nss_n2h_queue_limit[core_id];
+
+ /*
+ * Send synchronous message to firmware
+ */
+ down(&nss_n2h_q_lim_pvt.sem);
+
+ nss_tx_status = nss_n2h_tx_msg(nss_ctx, &nim);
+ if (nss_tx_status != NSS_TX_SUCCESS) {
+ nss_warning("%p: n2h queue limit message send failed\n", nss_ctx);
+ nss_n2h_queue_limit[core_id] = current_val;
+ up(&nss_n2h_q_lim_pvt.sem);
+ return nss_tx_status;
+ }
+
+ ret = wait_for_completion_timeout(&nss_n2h_q_lim_pvt.complete, msecs_to_jiffies(NSS_N2H_TX_TIMEOUT));
+ if (!ret) {
+ nss_warning("%p: Timeout expired for queue limit sync message\n", nss_ctx);
+ nss_n2h_queue_limit[core_id] = current_val;
+ up(&nss_n2h_q_lim_pvt.sem);
+ return NSS_TX_FAILURE;
+ }
+
+ /*
+ * If setting the queue limit failed, reset the value to original value
+ */
+ if (nss_n2h_q_lim_pvt.response != NSS_CMN_RESPONSE_ACK) {
+ nss_n2h_queue_limit[core_id] = current_val;
+ }
+
+ up(&nss_n2h_q_lim_pvt.sem);
+ return NSS_TX_SUCCESS;
+}
+
+/*
+ * nss_n2h_queue_limit_core0_handler()
+ * Sets the n2h queue size limit for core0
+ */
+static int nss_n2h_queue_limit_core0_handler(struct ctl_table *ctl,
+ int write, void __user *buffer,
+ size_t *lenp, loff_t *ppos)
+{
+ return nss_n2h_set_queue_limit_sync(ctl, write, buffer, lenp, ppos,
+ NSS_CORE_0);
+}
+
+/*
+ * nss_n2h_queue_limit_core1_handler()
+ * Sets the n2h queue size limit for core1
+ */
+static int nss_n2h_queue_limit_core1_handler(struct ctl_table *ctl,
+ int write, void __user *buffer,
+ size_t *lenp, loff_t *ppos)
+{
+ return nss_n2h_set_queue_limit_sync(ctl, write, buffer, lenp, ppos,
+ NSS_CORE_1);
+}
+
static struct ctl_table nss_n2h_table[] = {
{
.procname = "n2h_empty_pool_buf_core0",
@@ -1497,6 +1614,20 @@
.mode = 0644,
.proc_handler = &nss_n2h_buf_cfg_core1_handler,
},
+ {
+ .procname = "n2h_queue_limit_core0",
+ .data = &nss_n2h_queue_limit[NSS_CORE_0],
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &nss_n2h_queue_limit_core0_handler,
+ },
+ {
+ .procname = "n2h_queue_limit_core1",
+ .data = &nss_n2h_queue_limit[NSS_CORE_1],
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &nss_n2h_queue_limit_core1_handler,
+ },
{ }
};
@@ -1709,6 +1840,12 @@
sema_init(&nss_n2h_wp.sem, 1);
init_completion(&nss_n2h_wp.complete);
+ /*
+ * N2H queue config sema init
+ */
+ sema_init(&nss_n2h_q_lim_pvt.sem, 1);
+ init_completion(&nss_n2h_q_lim_pvt.complete);
+
nss_n2h_notify_register(NSS_CORE_0, NULL, NULL);
nss_n2h_notify_register(NSS_CORE_1, NULL, NULL);