[qca-nss-drv] Add support for async messaging in virt_if
Add support for asynchronous messaging in virt_if and
dynamic_interface.
CRs-Fixed: 853868
Change-Id: I06c0dc74d8fce74cab50d565560590351759a8d3
Signed-off-by: Sundarajan Srinivasan <sundaraj@codeaurora.org>
diff --git a/exports/nss_api_if.h b/exports/nss_api_if.h
index a6ef7e2..d1b52eb 100644
--- a/exports/nss_api_if.h
+++ b/exports/nss_api_if.h
@@ -85,7 +85,6 @@
#define NSS_MAX_VIRTUAL_INTERFACES 16
#define NSS_MAX_TUNNEL_INTERFACES 4
#define NSS_MAX_SPECIAL_INTERFACES 30
-#define NSS_MAX_DYNAMIC_INTERFACES 64
#define NSS_MAX_WIFI_RADIO_INTERFACES 3
/**
@@ -664,15 +663,6 @@
extern void *nss_create_virt_if(struct net_device *netdev);
/**
- * @brief Obtain NSS Interface number for a virtual interface context
- *
- * @param context Interface context
- *
- * @return int32_t The NSS interface number
- */
-int32_t nss_virt_if_get_interface_num(void *if_ctx);
-
-/**
* @brief Destroy virtual interface (VAPs)
*
* @param ctx Context provided by NSS driver during registration
diff --git a/exports/nss_dynamic_interface.h b/exports/nss_dynamic_interface.h
index e42c2b9..efc8ba6 100644
--- a/exports/nss_dynamic_interface.h
+++ b/exports/nss_dynamic_interface.h
@@ -22,22 +22,77 @@
#ifndef __NSS_DYNAMIC_INTERFACE_H
#define __NSS_DYNAMIC_INTERFACE_H
+#define NSS_MAX_DYNAMIC_INTERFACES 64
+
/**
* Dynamic Interface types
*/
enum nss_dynamic_interface_type {
- NSS_DYNAMIC_INTERFACE_TYPE_NONE = 0,
- NSS_DYNAMIC_INTERFACE_TYPE_GRE_REDIR = 1, /* GRE_REDIR Interface type */
- NSS_DYNAMIC_INTERFACE_TYPE_CAPWAP = 2, /* CAPWAP Interface type */
- NSS_DYNAMIC_INTERFACE_TYPE_TUN6RD = 3, /* TUN6RD Interface type */
- NSS_DYNAMIC_INTERFACE_TYPE_802_3_REDIR = 4, /* 802.3 redirect Interface type */
- NSS_DYNAMIC_INTERFACE_TYPE_WIFI = 5, /* Wifi redirect Interface type */
- NSS_DYNAMIC_INTERFACE_TYPE_RADIO_0 = 6, /* WIFI radio type0 */
- NSS_DYNAMIC_INTERFACE_TYPE_RADIO_1 = 7, /* WIFI radio type1 */
- NSS_DYNAMIC_INTERFACE_TYPE_RADIO_2 = 8, /* WIFI radio type2 */
+ NSS_DYNAMIC_INTERFACE_TYPE_NONE,
+ NSS_DYNAMIC_INTERFACE_TYPE_GRE_REDIR, /* GRE_REDIR Interface type */
+ NSS_DYNAMIC_INTERFACE_TYPE_CAPWAP, /* CAPWAP Interface type */
+ NSS_DYNAMIC_INTERFACE_TYPE_TUN6RD, /* TUN6RD Interface type */
+ NSS_DYNAMIC_INTERFACE_TYPE_802_3_REDIR, /* 802.3 redirect Interface type */
+ NSS_DYNAMIC_INTERFACE_TYPE_WIFI, /* Wifi redirect Interface type */
+ NSS_DYNAMIC_INTERFACE_TYPE_RADIO_0, /* WIFI radio type0 */
+ NSS_DYNAMIC_INTERFACE_TYPE_RADIO_1, /* WIFI radio type1 */
+ NSS_DYNAMIC_INTERFACE_TYPE_RADIO_2, /* WIFI radio type2 */
+ NSS_DYNAMIC_INTERFACE_TYPE_VIRTIF_DEPRECATED,
NSS_DYNAMIC_INTERFACE_TYPE_MAX
};
+typedef enum nss_dynamic_interface_type nss_dynamic_interface_assigned;
+
+/*
+ * Dynamic Interface request types
+ */
+enum nss_dynamic_interface_message_types {
+ NSS_DYNAMIC_INTERFACE_ALLOC_NODE, /* Alloc node message type */
+ NSS_DYNAMIC_INTERFACE_DEALLOC_NODE, /* Dealloc node message type */
+ NSS_DYNAMIC_INTERFACE_MAX,
+};
+
+/*
+ * Dynamic interface alloc node msg
+ */
+struct nss_dynamic_interface_alloc_node_msg {
+ enum nss_dynamic_interface_type type; /* Dynamic Interface type */
+ /*
+ * Response
+ */
+ int if_num; /* Interface number */
+};
+
+/*
+ * Dynamic interface dealloc node msg
+ */
+struct nss_dynamic_interface_dealloc_node_msg {
+ enum nss_dynamic_interface_type type; /* Dynamic Interface type */
+ int if_num; /* Interface number */
+};
+
+/*
+ * Message structure to send/receive Dynamic Interface messages
+ */
+struct nss_dynamic_interface_msg {
+ struct nss_cmn_msg cm; /* Common Message */
+ union {
+ struct nss_dynamic_interface_alloc_node_msg alloc_node; /* Msg: Allocate dynamic node */
+ struct nss_dynamic_interface_dealloc_node_msg dealloc_node; /* Msg: deallocate dynamic node */
+ } msg;
+};
+
+/*
+ * Private data structure of dynamic interface
+ */
+struct nss_dynamic_interface_pvt {
+ struct semaphore sem; /* Semaphore structure */
+ struct completion complete; /* completion structure */
+ int current_if_num; /* Current interface number */
+ enum nss_cmn_response response; /* Message response */
+ nss_dynamic_interface_assigned type[NSS_MAX_DYNAMIC_INTERFACES]; /* Array of assigned interface types */
+};
+
/**
* @brief allocate node for dynamic interface on NSS
*
@@ -75,4 +130,38 @@
*/
extern enum nss_dynamic_interface_type nss_dynamic_interface_get_type(int if_num);
+/**
+ * @brief Transmits an asynchronous message to firmware.
+ *
+ * @param nss_ctx context
+ * @param msg dynamic interface message to be sent to the firmware.
+ *
+ * @return message Tx status
+ */
+extern nss_tx_status_t nss_dynamic_interface_tx(struct nss_ctx_instance *nss_ctx, struct nss_dynamic_interface_msg *msg);
+
+/**
+ * @brief Dynamic interface message callback type
+ *
+ * @param app_data app_data returned to callback fn.
+ * @param msg nss common message
+ *
+ * @return void
+ */
+typedef void (*nss_dynamic_interface_msg_callback_t)(void *app_data, struct nss_cmn_msg *msg);
+
+/**
+ * @brief Initialize dynamic interface message
+ *
+ * @param ndm dynamic interface message to be initialized.
+ * @param if_num Interface number.
+ * @param type dynamic interface type
+ * @param len message length
+ * @param cb callback to be invoked
+ * @param app_data app_data passed to the callback fn.
+ *
+ * @return void
+ */
+void nss_dynamic_interface_msg_init(struct nss_dynamic_interface_msg *ndm, uint16_t if_num, uint32_t type, uint32_t len,
+ void *cb, void *app_data);
#endif /* __NSS_DYNAMIC_INTERFACE_H*/
diff --git a/exports/nss_virt_if.h b/exports/nss_virt_if.h
index 6ea97fd..506c114 100644
--- a/exports/nss_virt_if.h
+++ b/exports/nss_virt_if.h
@@ -123,6 +123,7 @@
struct nss_virt_if_handle {
struct nss_ctx_instance *nss_ctx; /*< NSS context */
int32_t if_num; /*< interface number */
+ struct net_device *ndev; /*< Associated netdevice */
struct nss_virt_if_pvt *pvt; /*< Private data structure */
struct nss_virt_if_stats stats; /*< virt_if stats */
atomic_t refcnt; /*< Reference count */
@@ -131,20 +132,44 @@
};
/**
- * @brief Create a virtual interface
+ * @brief Create a virtual interface, asynchronously
*
- * @param netdev net device associated with Wifi
- * @return Pointer to nss_virt_if_handle struct
+ * @param netdev net device associated with client
+ * @param cb callback to be invoked when the response from the FW is received
+ * @param app_data app_data to be passed to the callback.
+ *
+ * @return int command tx status
*/
-extern struct nss_virt_if_handle *nss_virt_if_create(struct net_device *netdev);
+extern int nss_virt_if_create(struct net_device *netdev, nss_virt_if_msg_callback_t cb, void *app_data);
/**
- * @brief Destroy the virtual interface associated with the if_num
+ * @brief Create a virtual interface, synchronously.
+ *
+ * @param netdev net device associated with WiFi
+ *
+ * @return Pointer to nss_virt_if_handle struct
+ */
+extern struct nss_virt_if_handle *nss_virt_if_create_sync(struct net_device *netdev);
+
+/**
+ * @brief Destroy the virtual interface associated with the if_num, asynchronously.
*
* @param handle virtual interface handle (provided during dynamic_interface allocation)
+ * @param cb callback to be invoked when the response from the FW is received
+ * @param app_data app_data to be passed to the callback.
+ *
* @return command Tx status
*/
-extern nss_tx_status_t nss_virt_if_destroy(struct nss_virt_if_handle *handle);
+extern nss_tx_status_t nss_virt_if_destroy(struct nss_virt_if_handle *handle, nss_virt_if_msg_callback_t cb, void *app_data);
+
+/**
+ * @brief Destroy the virtual interface associated with the if_num, synchronously.
+ *
+ * @param handle virtual interface handle (provided during dynamic_interface allocation)
+ *
+ * @return command Tx status
+ */
+extern nss_tx_status_t nss_virt_if_destroy_sync(struct nss_virt_if_handle *handle);
/**
* @brief Send message to virtual interface
@@ -180,11 +205,12 @@
nss_virt_if_data_callback_t data_callback,
struct net_device *netdev);
-
/**
* @brief Unregister virtual interface from NSS driver
*
* @param handle virtual interface handle
+ *
+ * @return void
*/
extern void nss_virt_if_unregister(struct nss_virt_if_handle *handle);
@@ -199,4 +225,13 @@
*/
extern int32_t nss_virt_if_copy_stats(int32_t if_num, int i, char *line);
+/**
+ * @brief Returns the virtual interface number associated with the handle.
+ *
+ * @param handle virtual interface handle(provided during dynamic_interface allocation)
+ *
+ * @return if_num virtual interface number.
+ */
+extern int32_t nss_virt_if_get_interface_num(struct nss_virt_if_handle *handle);
+
#endif /* __NSS_VIRT_IF_H */
diff --git a/nss_cmn.c b/nss_cmn.c
index 9fab600..853c1c6 100644
--- a/nss_cmn.c
+++ b/nss_cmn.c
@@ -1,6 +1,6 @@
/*
**************************************************************************
- * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014, 2015 The Linux Foundation. All rights reserved.
* 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.
@@ -139,7 +139,9 @@
*/
bool nss_cmn_interface_is_virtual(void *nss_ctx, int32_t interface_num)
{
- return (NSS_IS_IF_TYPE(DYNAMIC, interface_num) || NSS_IS_IF_TYPE(VIRTUAL, interface_num));
+ return ((nss_dynamic_interface_get_type(interface_num) == NSS_DYNAMIC_INTERFACE_TYPE_WIFI)
+ || (nss_dynamic_interface_get_type(interface_num) == NSS_DYNAMIC_INTERFACE_TYPE_802_3_REDIR)
+ || (nss_dynamic_interface_get_type(interface_num) == NSS_DYNAMIC_INTERFACE_TYPE_VIRTIF_DEPRECATED));
}
/*
diff --git a/nss_core.c b/nss_core.c
index 8ae4914..b6ef1a0 100755
--- a/nss_core.c
+++ b/nss_core.c
@@ -1620,7 +1620,7 @@
(uint16_t)(nbuf->end - nbuf->head), (uint32_t)nbuf->priority, mss, bit_flags);
#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3,6,0))
- if (unlikely(!NSS_IS_IF_TYPE(VIRTUAL, if_num))) {
+ if (unlikely(!nss_cmn_interface_is_virtual(nss_ctx, if_num))) {
if (likely(nbuf->destructor == NULL)) {
if (likely(skb_recycle_check(nbuf, nss_ctx->max_buf_size))) {
bit_flags |= H2N_BIT_FLAG_BUFFER_REUSE;
diff --git a/nss_core.h b/nss_core.h
index 35f57ac..78bda23 100755
--- a/nss_core.h
+++ b/nss_core.h
@@ -671,6 +671,7 @@
struct dentry *core_log_dentry; /* NSS Core's FW log file */
struct dentry *wifi_if_dentry; /* wifi_if stats dentry */
struct dentry *virt_if_dentry; /* virt_if stats dentry */
+ struct dentry *tx_rx_virt_if_dentry; /* tx_rx_virt_if stats dentry. Will be deprecated soon */
struct nss_ctx_instance nss[NSS_MAX_CORES];
/* NSS contexts */
/*
diff --git a/nss_dynamic_interface.c b/nss_dynamic_interface.c
index a340b94..920587d 100644
--- a/nss_dynamic_interface.c
+++ b/nss_dynamic_interface.c
@@ -21,22 +21,14 @@
static struct nss_dynamic_interface_pvt di;
/*
- * nss_dynamic_interface_msg_init()
- * Initialize dynamic interface message.
- */
-static void nss_dynamic_interface_msg_init(struct nss_dynamic_interface_msg *ndm, uint16_t if_num, uint32_t type, uint32_t len,
- void *cb, void *app_data)
-{
- nss_cmn_msg_init(&ndm->cm, if_num, type, len, cb, app_data);
-}
-
-/*
* nss_dynamic_interface_handler()
- * handle NSS -> HLOS messages for dynamic interfaces
+ * Handle NSS -> HLOS messages for dynamic interfaces
*/
static void nss_dynamic_interface_handler(struct nss_ctx_instance *nss_ctx, struct nss_cmn_msg *ncm, __attribute__((unused))void *app_data)
{
+ nss_dynamic_interface_msg_callback_t cb;
struct nss_dynamic_interface_msg *ndim = (struct nss_dynamic_interface_msg *)ncm;
+ int32_t if_num;
BUG_ON(ncm->interface != NSS_DYNAMIC_INTERFACE);
@@ -64,39 +56,103 @@
switch (ndim->cm.type) {
case NSS_DYNAMIC_INTERFACE_ALLOC_NODE:
if (ncm->response == NSS_CMN_RESPONSE_ACK) {
- nss_info("%p if_num %d\n", nss_ctx, ndim->msg.alloc_node.if_num);
+ nss_info("%p alloc_node response ack if_num %d\n", nss_ctx, ndim->msg.alloc_node.if_num);
di.current_if_num = ndim->msg.alloc_node.if_num;
+ if_num = di.current_if_num;
+ if (if_num > 0) {
+ di.type[if_num - NSS_DYNAMIC_IF_START] = ndim->msg.alloc_node.type;
+ } else {
+ nss_warning("%p: if_num < 0\n", nss_ctx);
+ }
}
- /*
- * Unblock the alloc_node message.
- */
- complete(&di.complete);
break;
case NSS_DYNAMIC_INTERFACE_DEALLOC_NODE:
if (ncm->response == NSS_CMN_RESPONSE_ACK) {
- nss_info("%p if_num %d\n", nss_ctx, ndim->msg.dealloc_node.if_num);
+ nss_info("%p dealloc_node response ack if_num %d\n", nss_ctx, ndim->msg.dealloc_node.if_num);
di.current_if_num = ndim->msg.dealloc_node.if_num;
+ if_num = di.current_if_num;
+ di.type[if_num - NSS_DYNAMIC_IF_START] = NSS_DYNAMIC_INTERFACE_TYPE_NONE;
}
- /*
- * Unblock the dealloc_node message.
- */
- complete(&di.complete);
break;
default:
nss_warning("%p: Received response %d for type %d, interface %d",
nss_ctx, ncm->response, ncm->type, ncm->interface);
+ return;
}
+
+ /*
+ * Do we have a callback?
+ */
+ if (!ncm->cb) {
+ nss_warning("%p: nss_dynamic_interface_handler cb is NULL\n", nss_ctx);
+ return;
+ }
+
+ /*
+ * Callback
+ */
+ cb = (nss_dynamic_interface_msg_callback_t)ncm->cb;
+ cb((void *)ncm->app_data, ncm);
+}
+
+/*
+ * nss_dynamic_interface_callback
+ * Callback to handle the message response from NSS FW.
+ */
+static void nss_dynamic_interface_callback(void *app_data, struct nss_cmn_msg *ncm)
+{
+ /*
+ * Unblock the sleeping function.
+ */
+ di.response = ncm->response;
+ complete(&di.complete);
+}
+
+/*
+ * nss_dynamic_interface_tx_sync()
+ * Send the message to NSS and wait till we get an ACK or NACK for this msg.
+ */
+static nss_tx_status_t nss_dynamic_interface_tx_sync(struct nss_ctx_instance *nss_ctx, struct nss_dynamic_interface_msg *ndim)
+{
+ nss_tx_status_t status;
+ int ret;
+
+ /*
+ * Acquring a semaphore , so that only one caller can send msg at a time.
+ */
+ down(&di.sem);
+ di.response = false;
+
+ status = nss_dynamic_interface_tx(nss_ctx, ndim);
+ if (status != NSS_TX_SUCCESS) {
+ up(&di.sem);
+ nss_warning("%p: not able to transmit msg successfully\n", nss_ctx);
+ return status;
+ }
+
+ /*
+ * Blocking call, wait till we get ACK for this msg.
+ */
+ ret = wait_for_completion_timeout(&di.complete, msecs_to_jiffies(NSS_DYNAMIC_INTERFACE_COMP_TIMEOUT));
+ if (ret == 0) {
+ up(&di.sem);
+ nss_warning("%p: Waiting for ack timed out\n", nss_ctx);
+ return NSS_TX_FAILURE;
+ }
+
+ up(&di.sem);
+ return status;
}
/*
* nss_dynamic_interface_tx()
- * Transmit a dynamic interface message to NSSFW
+ * Transmit a dynamic interface message to NSSFW, asynchronously.
*/
-static nss_tx_status_t nss_dynamic_interface_tx(struct nss_ctx_instance *nss_ctx, struct nss_dynamic_interface_msg *msg)
+nss_tx_status_t nss_dynamic_interface_tx(struct nss_ctx_instance *nss_ctx, struct nss_dynamic_interface_msg *msg)
{
struct nss_dynamic_interface_msg *nm;
struct nss_cmn_msg *ncm = &msg->cm;
@@ -156,33 +212,6 @@
}
/*
- * nss_dynamic_interface_tx_sync()
- * Send the message to NSS and wait till we get an ACK or NACK for this msg.
- */
-static nss_tx_status_t nss_dynamic_interface_tx_sync(struct nss_ctx_instance *nss_ctx, struct nss_dynamic_interface_msg *ndim)
-{
- nss_tx_status_t status;
- int ret;
-
- status = nss_dynamic_interface_tx(nss_ctx, ndim);
- if (status != NSS_TX_SUCCESS) {
- nss_warning("%p: not able to transmit msg successfully\n", nss_ctx);
- return status;
- }
-
- /*
- * Blocking call, wait till we get ACK for this msg.
- */
- ret = wait_for_completion_timeout(&di.complete, msecs_to_jiffies(NSS_DYNAMIC_INTERFACE_COMP_TIMEOUT));
- if (ret == 0) {
- nss_warning("%p: Waiting for ack timed out\n", nss_ctx);
- return NSS_TX_FAILURE;
- }
-
- return status;
-}
-
-/*
* nss_dynamic_interface_alloc_node()
* Allocates node of perticular type on NSS and returns interface_num for this node or -1 in case of failure.
*
@@ -192,80 +221,54 @@
int nss_dynamic_interface_alloc_node(enum nss_dynamic_interface_type type)
{
struct nss_ctx_instance *nss_ctx = NULL;
- struct nss_dynamic_interface_msg *ndim;
+ struct nss_dynamic_interface_msg ndim;
struct nss_dynamic_interface_alloc_node_msg *ndia;
uint32_t core_id;
nss_tx_status_t status;
- int if_num;
if (type >= NSS_DYNAMIC_INTERFACE_TYPE_MAX) {
nss_warning("Dynamic if msg drooped as type is wrong %d\n", type);
return -1;
}
- ndim = vmalloc(sizeof(struct nss_dynamic_interface_msg));
- if (!ndim) {
- nss_warning(" Not able to allocate memory for alloc node message\n");
- return -1;
- }
-
core_id = nss_top_main.dynamic_interface_table[type];
nss_ctx = (struct nss_ctx_instance *)&nss_top_main.nss[core_id];
- nss_dynamic_interface_msg_init(ndim, NSS_DYNAMIC_INTERFACE, NSS_DYNAMIC_INTERFACE_ALLOC_NODE,
- sizeof(struct nss_dynamic_interface_alloc_node_msg), NULL, NULL);
+ nss_dynamic_interface_msg_init(&ndim, NSS_DYNAMIC_INTERFACE, NSS_DYNAMIC_INTERFACE_ALLOC_NODE,
+ sizeof(struct nss_dynamic_interface_alloc_node_msg), nss_dynamic_interface_callback, (void *)nss_ctx);
- ndia = &ndim->msg.alloc_node;
+ ndia = &ndim.msg.alloc_node;
ndia->type = type;
/*
- * Initialize interface number to -1.
+ * Initialize if_num to -1. The allocated if_num is returned by the firmware
+ * in the response message.
*/
ndia->if_num = -1;
/*
- * Acquring a semaphore , so that only one caller can send msg at a time.
- */
- down(&di.sem);
-
- di.current_if_num = -1;
-
- /*
* Calling synchronous transmit function.
*/
- status = nss_dynamic_interface_tx_sync(nss_ctx, ndim);
+ status = nss_dynamic_interface_tx_sync(nss_ctx, &ndim);
if (status != NSS_TX_SUCCESS) {
- up(&di.sem);
- vfree(ndim);
nss_warning("%p not able to transmit alloc node msg\n", nss_ctx);
return -1;
}
/*
- * di.current_if_num contains the right interface number.
+ * Check di.response and return -1 if its a NACK else proceed.
*/
- if (di.current_if_num < 0) {
+ if (di.response != NSS_CMN_RESPONSE_ACK) {
nss_warning("%p Received NACK from NSS\n", nss_ctx);
+ return -1;
}
- if_num = di.current_if_num;
- if (if_num > 0) {
- di.if_num[if_num - NSS_DYNAMIC_IF_START].type = type;
- }
-
- /*
- * Release Semaphore
- */
- up(&di.sem);
-
- vfree(ndim);
-
- return if_num;
+ return di.current_if_num;
}
/*
* nss_dynamic_interface_dealloc_node()
- * Deallocate node of perticular type and if_num on NSS.
+ * Deallocate node of particular type and if_num in NSS.
*
* Note: This will just mark the state of node as not active, actual memory will be freed when reference count of that node becomes 0.
* This function should not be called from soft_irq or interrupt context because it blocks till ACK/NACK is received for the message
@@ -274,68 +277,45 @@
nss_tx_status_t nss_dynamic_interface_dealloc_node(int if_num, enum nss_dynamic_interface_type type)
{
struct nss_ctx_instance *nss_ctx = NULL;
- struct nss_dynamic_interface_msg *ndim;
+ struct nss_dynamic_interface_msg ndim;
struct nss_dynamic_interface_dealloc_node_msg *ndid;
uint32_t core_id;
nss_tx_status_t status;
if (type >= NSS_DYNAMIC_INTERFACE_TYPE_MAX) {
- nss_warning("Dynamic if msg dropped as type is wrong %d\n", type);
- return NSS_TX_FAILURE;
- }
-
- ndim = vmalloc(sizeof(struct nss_dynamic_interface_msg));
- if (!ndim) {
- nss_warning(" Not able to allocate memory for dealloc node message\n");
- return NSS_TX_FAILURE;
+ nss_warning("Dynamic if msg dropped as type is wrong type %d if_num %d\n", type, if_num);
+ return NSS_TX_FAILURE_BAD_PARAM;
}
core_id = nss_top_main.dynamic_interface_table[type];
nss_ctx = (struct nss_ctx_instance *)&nss_top_main.nss[core_id];
- nss_dynamic_interface_msg_init(ndim, NSS_DYNAMIC_INTERFACE, NSS_DYNAMIC_INTERFACE_DEALLOC_NODE,
- sizeof(struct nss_dynamic_interface_dealloc_node_msg), NULL, NULL);
+ if (nss_is_dynamic_interface(if_num) == false) {
+ nss_warning("%p: nss_dynamic_interface if_num is not in range %d\n", nss_ctx, if_num);
+ return NSS_TX_FAILURE_BAD_PARAM;
+ }
- ndid = &ndim->msg.dealloc_node;
+ nss_dynamic_interface_msg_init(&ndim, NSS_DYNAMIC_INTERFACE, NSS_DYNAMIC_INTERFACE_DEALLOC_NODE,
+ sizeof(struct nss_dynamic_interface_dealloc_node_msg), nss_dynamic_interface_callback, (void *)nss_ctx);
+
+ ndid = &ndim.msg.dealloc_node;
ndid->type = type;
ndid->if_num = if_num;
/*
- * Acquring a semaphore , so that only one caller can send msg at a time.
- */
- down(&di.sem);
-
- di.current_if_num = -1;
-
- /*
* Calling synchronous transmit function.
*/
- status = nss_dynamic_interface_tx_sync(nss_ctx, ndim);
+ status = nss_dynamic_interface_tx_sync(nss_ctx, &ndim);
if (status != NSS_TX_SUCCESS) {
- up (&di.sem);
- vfree(ndim);
nss_warning("%p not able to transmit alloc node msg\n", nss_ctx);
return status;
}
- if (di.current_if_num < 0) {
- up (&di.sem);
- vfree(ndim);
+ if (di.response != NSS_CMN_RESPONSE_ACK) {
nss_warning("%p Received NACK from NSS\n", nss_ctx);
- return NSS_TX_FAILURE;
+ return -1;
}
- if (if_num > 0) {
- di.if_num[if_num - NSS_DYNAMIC_IF_START].type = NSS_DYNAMIC_INTERFACE_TYPE_NONE;
- }
-
- /*
- * Release Semaphore
- */
- up(&di.sem);
-
- vfree(ndim);
-
return status;
}
@@ -370,7 +350,17 @@
return NSS_DYNAMIC_INTERFACE_TYPE_NONE;
}
- return di.if_num[if_num - NSS_DYNAMIC_IF_START].type;
+ return di.type[if_num - NSS_DYNAMIC_IF_START];
+}
+
+/*
+ * nss_dynamic_interface_msg_init()
+ * Initialize dynamic interface message.
+ */
+void nss_dynamic_interface_msg_init(struct nss_dynamic_interface_msg *ndm, uint16_t if_num, uint32_t type, uint32_t len,
+ void *cb, void *app_data)
+{
+ nss_cmn_msg_init(&ndm->cm, if_num, type, len, cb, app_data);
}
EXPORT_SYMBOL(nss_dynamic_interface_alloc_node);
diff --git a/nss_hlos_if.h b/nss_hlos_if.h
index 036e47e..ae96db5 100755
--- a/nss_hlos_if.h
+++ b/nss_hlos_if.h
@@ -308,68 +308,6 @@
};
/*
- * Dynamic interface messages
- */
-
-/*
- * Dynamic Interface request/response types
- */
-enum nss_dynamic_interface_message_types {
- NSS_DYNAMIC_INTERFACE_ALLOC_NODE, /* Alloc node message type */
- NSS_DYNAMIC_INTERFACE_DEALLOC_NODE, /* Dealloc node message type */
- NSS_DYNAMIC_INTERFACE_MAX,
-};
-
-/*
- * Dynamic interface alloc node msg
- */
-struct nss_dynamic_interface_alloc_node_msg {
- enum nss_dynamic_interface_type type; /* Dynamic Interface type */
- /*
- * Response
- */
- int if_num; /* Interface number */
-};
-
-/*
- * This structure is there to keep information
- * pertaining to each if_num allocated through
- * dynamic interface API
- */
-struct nss_dynamic_interface_assigned {
- enum nss_dynamic_interface_type type;
-};
-
-/*
- * Private data structure of dynamic interface
- */
-struct nss_dynamic_interface_pvt {
- struct semaphore sem; /* Semaphore structure */
- struct completion complete; /* completion structure */
- int current_if_num; /* Current interface number */
- struct nss_dynamic_interface_assigned if_num[NSS_MAX_DYNAMIC_INTERFACES];
-};
-
-/*
- * Dynamic interface dealloc node msg
- */
-struct nss_dynamic_interface_dealloc_node_msg {
- enum nss_dynamic_interface_type type; /* Dynamic Interface type */
- int if_num; /* Interface number */
-};
-
-/*
- * Message structure to send/receive Dynamic Interface messages
- */
-struct nss_dynamic_interface_msg {
- struct nss_cmn_msg cm; /* Common Message */
- union {
- struct nss_dynamic_interface_alloc_node_msg alloc_node; /* Msg: Allocate dynamic node */
- struct nss_dynamic_interface_dealloc_node_msg dealloc_node; /* Msg: deallocate dynamic node */
- } msg;
-};
-
-/*
* H2N Buffer Types
*/
#define H2N_BUFFER_EMPTY 0
diff --git a/nss_if.c b/nss_if.c
index b64f521..0ce06cc 100644
--- a/nss_if.c
+++ b/nss_if.c
@@ -39,11 +39,9 @@
return;
}
- /*
- * As the base class we allow both virtual and physical interfaces.
- */
- if (ncm->interface > NSS_TUNNEL_IF_START) {
- nss_warning("%p: response for another interface: %d", nss_ctx, ncm->interface);
+ if (!nss_is_dynamic_interface(ncm->interface) &&
+ !((ncm->interface >= NSS_PHYSICAL_IF_START) && (ncm->interface < NSS_VIRTUAL_IF_START))) {
+ nss_warning("%p: interface %d not in physical or dynamic if range\n", nss_ctx, ncm->interface);
return;
}
@@ -87,6 +85,12 @@
return NSS_TX_FAILURE_NOT_READY;
}
+ if (!nss_is_dynamic_interface(if_num) &&
+ !((if_num >= NSS_PHYSICAL_IF_START) && (if_num < NSS_VIRTUAL_IF_START))) {
+ nss_warning("%p: interface %d not in physical or dynamic if range\n", nss_ctx, if_num);
+ return NSS_TX_FAILURE_BAD_PARAM;
+ }
+
status = nss_core_send_buffer(nss_ctx, if_num, os_buf, NSS_IF_DATA_QUEUE_0, H2N_BUFFER_PACKET, 0);
if (unlikely(status != NSS_CORE_STATUS_SUCCESS)) {
nss_warning("%p: Unable to enqueue 'Phys If Tx' packet\n", nss_ctx);
@@ -126,13 +130,6 @@
/*
* Sanity check the message
*/
- /*
- * As the base class we allow both virtual and physical interfaces.
- */
- if (ncm->interface > NSS_TUNNEL_IF_START) {
- nss_warning("%p: tx request for another interface: %d", nss_ctx, ncm->interface);
- return NSS_TX_FAILURE;
- }
if (ncm->type > NSS_IF_MAX_MSG_TYPES) {
nss_warning("%p: message type out of range: %d", nss_ctx, ncm->type);
diff --git a/nss_stats.c b/nss_stats.c
index 71fd9ac..d5ed3e5 100644
--- a/nss_stats.c
+++ b/nss_stats.c
@@ -34,6 +34,8 @@
*/
extern struct nss_top_instance nss_top_main;
+extern int32_t nss_tx_rx_virt_if_copy_stats(int32_t if_num, int i, char *line);
+
uint64_t stats_shadow_pppoe_except[NSS_PPPOE_NUM_SESSION_PER_INTERFACE][NSS_PPPOE_EXCEPTION_EVENT_MAX];
/*
@@ -1783,6 +1785,87 @@
}
/*
+ * nss_stats_tx_rx_virt_if_read()
+ * Read tx_rx_virt_if statistics
+ */
+static ssize_t nss_stats_tx_rx_virt_if_read(struct file *fp, char __user *ubuf,
+ size_t sz, loff_t *ppos)
+{
+ struct nss_stats_data *data = fp->private_data;
+ int32_t if_num = NSS_DYNAMIC_IF_START;
+ int32_t max_if_num = if_num + NSS_MAX_DYNAMIC_INTERFACES;
+ size_t bytes = 0;
+ ssize_t bytes_read = 0;
+ char line[80];
+ int start, end;
+
+ if (data) {
+ if_num = data->if_num;
+ }
+
+ if (if_num > max_if_num) {
+ return 0;
+ }
+
+ for (; if_num < max_if_num; if_num++) {
+ if (nss_dynamic_interface_get_type(if_num) != NSS_DYNAMIC_INTERFACE_TYPE_VIRTIF_DEPRECATED)
+ continue;
+
+ bytes = scnprintf(line, sizeof(line), "if_num %d stats start:\n\n", if_num);
+ if ((bytes_read + bytes) > sz)
+ break;
+
+ if (copy_to_user(ubuf + bytes_read, line, bytes) != 0) {
+ bytes_read = -EFAULT;
+ goto end;
+ }
+
+ bytes_read += bytes;
+
+ start = 0;
+ end = 7;
+ while (bytes_read < sz && start < end) {
+ bytes = nss_tx_rx_virt_if_copy_stats(if_num, start, line);
+ if (!bytes)
+ break;
+
+ if ((bytes_read + bytes) > sz)
+ break;
+
+ if (copy_to_user(ubuf + bytes_read, line, bytes) != 0) {
+ bytes_read = -EFAULT;
+ goto end;
+ }
+
+ bytes_read += bytes;
+ start++;
+ }
+
+ bytes = scnprintf(line, sizeof(line), "if_num %d stats end:\n\n", if_num);
+ if (bytes_read > (sz - bytes))
+ break;
+
+ if (copy_to_user(ubuf + bytes_read, line, bytes) != 0) {
+ bytes_read = -EFAULT;
+ goto end;
+ }
+
+ bytes_read += bytes;
+ }
+
+ if (bytes_read > 0) {
+ *ppos = bytes_read;
+ }
+
+ if (data) {
+ data->if_num = if_num;
+ }
+
+end:
+ return bytes_read;
+}
+
+/*
* nss_stats_open()
*/
static int nss_stats_open(struct inode *inode, struct file *filp)
@@ -1893,6 +1976,8 @@
NSS_STATS_DECLARE_FILE_OPERATIONS(virt_if)
+NSS_STATS_DECLARE_FILE_OPERATIONS(tx_rx_virt_if)
+
/*
* wifi_stats_ops
*/
@@ -2097,6 +2182,13 @@
return;
}
+ nss_top_main.tx_rx_virt_if_dentry = debugfs_create_file("tx_rx_virt_if", 0400,
+ nss_top_main.stats_dentry, &nss_top_main, &nss_stats_tx_rx_virt_if_ops);
+ if (unlikely(nss_top_main.virt_if_dentry == NULL)) {
+ nss_warning("Failed to create qca-nss-drv/stats/tx_rx_virt_if file in debugfs");
+ return;
+ }
+
nss_log_init();
}
diff --git a/nss_tx_rx_common.h b/nss_tx_rx_common.h
index 94a3c93..95e67f4 100644
--- a/nss_tx_rx_common.h
+++ b/nss_tx_rx_common.h
@@ -60,14 +60,123 @@
#endif
/*
- * Handles associated with redir interfaces(virt_if & wifi_if).
+ * Deprecated Redirect
+ */
+
+/**
+ * @brief Request/Response types
+ */
+enum nss_tx_rx_virt_if_msg_types {
+ NSS_TX_RX_VIRT_IF_OPEN = NSS_IF_OPEN,
+ NSS_TX_RX_VIRT_IF_CLOSE = NSS_IF_CLOSE,
+ NSS_TX_RX_VIRT_IF_LINK_STATE_NOTIFY = NSS_IF_LINK_STATE_NOTIFY,
+ NSS_TX_RX_VIRT_IF_MTU_CHANGE = NSS_IF_MTU_CHANGE,
+ NSS_TX_RX_VIRT_IF_MAC_ADDR_SET = NSS_IF_MAC_ADDR_SET,
+ NSS_TX_RX_VIRT_IF_STATS_SYNC = NSS_IF_STATS,
+ NSS_TX_RX_VIRT_IF_ISHAPER_ASSIGN = NSS_IF_ISHAPER_ASSIGN,
+ NSS_TX_RX_VIRT_IF_BSHAPER_ASSIGN = NSS_IF_BSHAPER_ASSIGN,
+ NSS_TX_RX_VIRT_IF_ISHAPER_UNASSIGN = NSS_IF_ISHAPER_UNASSIGN,
+ NSS_TX_RX_VIRT_IF_BSHAPER_UNASSIGN = NSS_IF_BSHAPER_UNASSIGN,
+ NSS_TX_RX_VIRT_IF_ISHAPER_CONFIG = NSS_IF_ISHAPER_CONFIG,
+ NSS_TX_RX_VIRT_IF_BSHAPER_CONFIG = NSS_IF_BSHAPER_CONFIG,
+ NSS_TX_RX_VIRT_IF_TX_CREATE_MSG = NSS_IF_MAX_MSG_TYPES + 1,
+ NSS_TX_RX_VIRT_IF_TX_DESTROY_MSG,
+ NSS_TX_RX_VIRT_IF_STATS_SYNC_MSG,
+ NSS_TX_RX_VIRT_IF_MAX_MSG_TYPES,
+};
+
+/**
+ * virt_if error types
+ */
+enum nss_tx_rx_virt_if_error_types {
+ NSS_TX_RX_VIRT_IF_SUCCESS, /*< Success */
+ NSS_TX_RX_VIRT_IF_CORE_FAILURE, /*< nss core failure */
+ NSS_TX_RX_VIRT_IF_ALLOC_FAILURE, /*< Memory allocation failure */
+ NSS_TX_RX_VIRT_IF_DYNAMIC_IF_FAILURE, /*< Dynamic interface failure */
+ NSS_TX_RX_VIRT_IF_MSG_TX_FAILURE, /*< Message transmission failure */
+ NSS_TX_RX_VIRT_IF_REG_FAILURE, /*< Registration failure */
+ NSS_TX_RX_VIRT_IF_CORE_NOT_INITIALIZED, /*< NSS core not intialized */
+};
+
+/**
+ * Structure which contains stats received from NSS.
+ */
+struct nss_tx_rx_virt_if_stats {
+ struct nss_if_stats node_stats; /**< common stats */
+ uint32_t tx_enqueue_failed; /**< tx enqueue failures in the FW */
+ uint32_t shaper_enqueue_failed; /**< shaper enqueue failures in the FW */
+};
+
+/**
+ * The NSS virtual interface creation structure.
+ */
+struct nss_tx_rx_virt_if_create_msg {
+ uint32_t flags; /**< Interface flags */
+ uint8_t mac_addr[ETH_ALEN]; /**< MAC address */
+};
+
+/**
+ * The NSS virtual interface destruction structure.
+ */
+struct nss_tx_rx_virt_if_destroy_msg {
+ int32_t reserved; /**< place holder */
+};
+
+/**
+ * Message structure to send/receive virtual interface commands
+ */
+struct nss_tx_rx_virt_if_msg {
+ struct nss_cmn_msg cm;
+ /**< Message Header */
+ union {
+ union nss_if_msgs if_msgs;
+ struct nss_tx_rx_virt_if_create_msg if_create;
+ /**< Message: create virt if rule */
+ struct nss_tx_rx_virt_if_destroy_msg if_destroy;
+ /**< Message: destroy virt if rule */
+ struct nss_tx_rx_virt_if_stats stats;
+ /**< Message: stats */
+ } msg;
+};
+
+/*
+ * Private data structure for virt_if interface
+ */
+struct nss_tx_rx_virt_if_pvt {
+ struct semaphore sem;
+ struct completion complete;
+ int response;
+ int sem_init_done;
+};
+
+typedef void (*nss_tx_rx_virt_if_data_callback_t)(struct net_device *netdev, struct sk_buff *skb, struct napi_struct *napi);
+typedef void (*nss_tx_rx_virt_if_msg_callback_t)(void *app_data, struct nss_cmn_msg *msg);
+
+/*
+ * Handles associated with redir interfaces(virt_if & wifi_i).
* TODO: Once wifi moves to using the new interfaces, this will be deprecated.
*/
-struct nss_redir_handle {
- struct nss_wifi_if_handle *whandle;
- struct nss_virt_if_handle *vhandle;
+
+struct nss_tx_rx_virt_if_handle {
+ struct nss_ctx_instance *nss_ctx;
+ int32_t if_num;
+ struct nss_tx_rx_virt_if_pvt *pvt;
+ struct nss_tx_rx_virt_if_stats stats;
+ nss_tx_rx_virt_if_msg_callback_t cb;
+ void *app_data;
};
+/**
+ * @brief Get stats for redir interface from NSS driver
+ *
+ * @param if_num Interface number (provided during dynamic_interface allocation)
+ * @param i index of stats
+ * @param line buffer into which the stats will be copied.
+ *
+ * @return int32_t Returns 0 if if_num is not in range or the number of bytes copied.
+ */
+extern int32_t nss_tx_rx_virt_if_copy_stats(int32_t if_num, int i, char *line);
+
/*
* CB handlers for variour interfaces
*/
diff --git a/nss_tx_rx_virt_if.c b/nss_tx_rx_virt_if.c
index fc3eb2f..4ac7bbe 100644
--- a/nss_tx_rx_virt_if.c
+++ b/nss_tx_rx_virt_if.c
@@ -22,19 +22,163 @@
#include "nss_tx_rx_common.h"
#include <net/arp.h>
+#define NSS_TX_RX_VIRT_IF_TX_TIMEOUT 3000 /* 3 Seconds */
+#define NSS_TX_RX_VIRT_IF_GET_INDEX(if_num) (if_num-NSS_DYNAMIC_IF_START)
+#define NSS_TX_RX_VIRT_IF_802_3_PKT 0x2
+#define NSS_TX_RX_VIRT_IF_NATIVE_WIFI_PKT 0x3
+
extern int nss_ctl_redirect;
/*
+ * Data structure that holds the virtual interface context.
+ */
+static struct nss_tx_rx_virt_if_handle *nss_tx_rx_virt_if_handles[NSS_MAX_DYNAMIC_INTERFACES];
+
+/*
+ * Spinlock to protect the global data structure virt_handle.
+ */
+DEFINE_SPINLOCK(nss_tx_rx_virt_if_lock);
+
+/*
+ * nss_tx_rx_virt_if_stats_sync()
+ * Sync stats from the NSS FW
+ */
+static void nss_tx_rx_virt_if_stats_sync(struct nss_tx_rx_virt_if_handle *handle,
+ struct nss_tx_rx_virt_if_stats *nwis)
+{
+ struct nss_tx_rx_virt_if_stats *stats = &handle->stats;
+
+ stats->node_stats.rx_packets += nwis->node_stats.rx_packets;
+ stats->node_stats.rx_bytes += nwis->node_stats.rx_bytes;
+ stats->node_stats.rx_dropped += nwis->node_stats.rx_dropped;
+ stats->node_stats.tx_packets += nwis->node_stats.tx_packets;
+ stats->node_stats.tx_bytes += nwis->node_stats.tx_bytes;
+ stats->tx_enqueue_failed += nwis->tx_enqueue_failed;
+ stats->shaper_enqueue_failed += nwis->shaper_enqueue_failed;
+}
+
+/*
+ * nss_tx_rx_virt_if_msg_handler()
+ * Handle msg responses from the FW on virtual interfaces
+ */
+static void nss_tx_rx_virt_if_msg_handler(struct nss_ctx_instance *nss_ctx,
+ struct nss_cmn_msg *ncm,
+ __attribute__((unused))void *app_data)
+{
+ struct nss_tx_rx_virt_if_msg *nvim = (struct nss_tx_rx_virt_if_msg *)ncm;
+ int32_t if_num;
+
+ nss_tx_rx_virt_if_msg_callback_t cb;
+ struct nss_tx_rx_virt_if_handle *handle = NULL;
+
+ /*
+ * Sanity check the message type
+ */
+ if (ncm->type > NSS_VIRT_IF_MAX_MSG_TYPES) {
+ nss_warning("%p: message type out of range: %d", nss_ctx, ncm->type);
+ return;
+ }
+
+ /*
+ * Messages value that are within the base class are handled by the base class.
+ */
+ if (ncm->type < NSS_IF_MAX_MSG_TYPES) {
+ return nss_if_msg_handler(nss_ctx, ncm, app_data);
+ }
+
+ if (!NSS_IS_IF_TYPE(DYNAMIC, ncm->interface)) {
+ nss_warning("%p: response for another interface: %d", nss_ctx, ncm->interface);
+ return;
+ }
+
+ if_num = NSS_TX_RX_VIRT_IF_GET_INDEX(ncm->interface);
+
+ spin_lock_bh(&nss_tx_rx_virt_if_lock);
+ if (!nss_tx_rx_virt_if_handles[if_num]) {
+ spin_unlock_bh(&nss_tx_rx_virt_if_lock);
+ nss_warning("%p: redir_if handle is NULL\n", nss_ctx);
+ return;
+ }
+
+ handle = nss_tx_rx_virt_if_handles[if_num];
+ spin_unlock_bh(&nss_tx_rx_virt_if_lock);
+
+ switch (nvim->cm.type) {
+ case NSS_VIRT_IF_STATS_SYNC_MSG:
+ nss_tx_rx_virt_if_stats_sync(handle, &nvim->msg.stats);
+ break;
+ }
+
+ /*
+ * Log failures
+ */
+ nss_core_log_msg_failures(nss_ctx, ncm);
+
+ /*
+ * Update the callback and app_data for NOTIFY messages, IPv4 sends all notify messages
+ * to the same callback/app_data.
+ */
+ if (ncm->response == NSS_CMM_RESPONSE_NOTIFY) {
+ ncm->cb = (uint32_t)nss_ctx->nss_top->virt_if_msg_callback[ncm->interface];
+ ncm->app_data = (uint32_t)nss_ctx->nss_top->subsys_dp_register[ncm->interface].ndev;
+ }
+
+ /*
+ * Do we have a callback?
+ */
+ if (!ncm->cb) {
+ return;
+ }
+
+ /*
+ * Callback
+ */
+ cb = (nss_tx_rx_virt_if_msg_callback_t)ncm->cb;
+ cb((void *)ncm->app_data, ncm);
+}
+
+/*
+ * nss_tx_rx_virt_if_callback
+ * Callback to handle the completion of NSS ->HLOS messages.
+ */
+static void nss_tx_rx_virt_if_callback(void *app_data, struct nss_cmn_msg *ncm)
+{
+ struct nss_tx_rx_virt_if_handle *handle = (struct nss_tx_rx_virt_if_handle *)app_data;
+ struct nss_tx_rx_virt_if_pvt *nvip = handle->pvt;
+
+ if (ncm->response != NSS_CMN_RESPONSE_ACK) {
+ nss_warning("%p: redir_if Error response %d\n", handle->nss_ctx, ncm->response);
+ nvip->response = NSS_TX_FAILURE;
+ complete(&nvip->complete);
+ return;
+ }
+
+ nvip->response = NSS_TX_SUCCESS;
+ complete(&nvip->complete);
+}
+
+/*
* nss_register_virt_if()
*/
void *nss_register_virt_if(void *ctx,
nss_virt_if_rx_callback_t rx_callback,
struct net_device *netdev)
{
- struct nss_redir_handle *handle = (struct nss_redir_handle *)ctx;
+ struct nss_tx_rx_virt_if_handle *handle = (struct nss_tx_rx_virt_if_handle *)ctx;
- nss_wifi_if_register(handle->whandle, rx_callback, netdev);
- nss_virt_if_register(handle->vhandle, rx_callback, netdev);
+ int32_t if_num;
+
+ if (!handle) {
+ nss_warning("handle is NULL\n");
+ return NULL;
+ }
+
+ if_num = handle->if_num;
+
+ nss_top_main.subsys_dp_register[if_num].ndev = netdev;
+ nss_top_main.subsys_dp_register[if_num].cb = rx_callback;
+ nss_top_main.subsys_dp_register[if_num].app_data = NULL;
+ nss_top_main.subsys_dp_register[if_num].features = (uint32_t)netdev->features;
return ctx;
}
@@ -44,10 +188,22 @@
*/
void nss_unregister_virt_if(void *ctx)
{
- struct nss_redir_handle *handle = (struct nss_redir_handle *)ctx;
+ struct nss_tx_rx_virt_if_handle *handle = (struct nss_tx_rx_virt_if_handle *)ctx;
+ int32_t if_num;
- nss_wifi_if_unregister(handle->whandle);
- nss_virt_if_unregister(handle->vhandle);
+ if (!handle) {
+ nss_warning("handle is NULL\n");
+ return;
+ }
+
+ if_num = handle->if_num;
+
+ nss_top_main.subsys_dp_register[if_num].ndev = NULL;
+ nss_top_main.subsys_dp_register[if_num].cb = NULL;
+ nss_top_main.subsys_dp_register[if_num].app_data = NULL;
+ nss_top_main.subsys_dp_register[if_num].features = 0;
+
+ nss_top_main.if_rx_msg_callback[if_num] = NULL;
}
/*
@@ -56,13 +212,75 @@
*/
nss_tx_status_t nss_tx_virt_if_recvbuf(void *ctx, struct sk_buff *skb, uint32_t nwifi)
{
- struct nss_redir_handle *handle = (struct nss_redir_handle *)ctx;
+ struct nss_tx_rx_virt_if_handle *handle = (struct nss_tx_rx_virt_if_handle *)ctx;
+ int32_t if_num = handle->if_num;
+ struct nss_ctx_instance *nss_ctx = handle->nss_ctx;
+ nss_tx_status_t status;
- if (nwifi) {
- return nss_wifi_if_tx_buf(handle->whandle, skb);
- } else {
- return nss_virt_if_tx_buf(handle->vhandle, skb);
+ if (unlikely(nss_ctl_redirect == 0)) {
+ return NSS_TX_FAILURE_NOT_ENABLED;
}
+
+ if (unlikely(skb->vlan_tci)) {
+ return NSS_TX_FAILURE_NOT_SUPPORTED;
+ }
+
+ nss_assert(NSS_IS_IF_TYPE(DYNAMIC, if_num));
+ nss_trace("%p: Virtual Rx packet, if_num:%d, skb:%p", nss_ctx, if_num, skb);
+
+ /*
+ * Get the NSS context that will handle this packet and check that it is initialised and ready
+ */
+ NSS_VERIFY_CTX_MAGIC(nss_ctx);
+ if (unlikely(nss_ctx->state != NSS_CORE_STATE_INITIALIZED)) {
+ nss_warning("%p: Virtual Rx packet dropped as core not ready", nss_ctx);
+ return NSS_TX_FAILURE_NOT_READY;
+ }
+
+ /*
+ * Sanity check the SKB to ensure that it's suitable for us
+ */
+ if (unlikely(skb->len <= ETH_HLEN)) {
+ nss_warning("%p: Virtual Rx packet: %p too short", nss_ctx, skb);
+ return NSS_TX_FAILURE_TOO_SHORT;
+ }
+
+ if (unlikely(skb_shinfo(skb)->nr_frags != 0)) {
+ /*
+ * TODO: If we have a connection matching rule for this skbuff,
+ * do we need to flush it??
+ */
+ nss_warning("%p: Delivering the packet to Linux because of fragmented skb: %p\n", nss_ctx, skb);
+ return NSS_TX_FAILURE_NOT_SUPPORTED;
+ }
+
+ /*
+ * We differentiate between skbs with priority to identify native vs non-native wifi pkts
+ */
+ if (nwifi) {
+ skb->priority = NSS_TX_RX_VIRT_IF_NATIVE_WIFI_PKT;
+ } else {
+ skb->priority = NSS_TX_RX_VIRT_IF_802_3_PKT;
+ }
+
+ /*
+ * Direct the buffer to the NSS
+ */
+ status = nss_core_send_buffer(nss_ctx, if_num, skb, NSS_IF_DATA_QUEUE_0,
+ H2N_BUFFER_PACKET, H2N_BIT_FLAG_VIRTUAL_BUFFER);
+ if (unlikely(status != NSS_CORE_STATUS_SUCCESS)) {
+ nss_warning("%p: Virtual Rx packet unable to enqueue\n", nss_ctx);
+ return NSS_TX_FAILURE_QUEUE;
+ }
+
+ /*
+ * Kick the NSS awake so it can process our new entry.
+ */
+ nss_hal_send_interrupt(nss_ctx->nmap,
+ nss_ctx->h2n_desc_rings[NSS_IF_DATA_QUEUE_0].desc_ring.int_bit,
+ NSS_REGS_H2N_INTR_STATUS_DATA_COMMAND_QUEUE);
+ NSS_PKT_STATS_INCREMENT(nss_ctx, &nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_TX_PACKET]);
+ return NSS_TX_SUCCESS;
}
/*
@@ -95,50 +313,410 @@
}
/*
- * nss_create_virt_if()
+ * nss_tx_rx_virt_if_msg_init()
+ * Initialize redir specific message structure.
*/
-void *nss_create_virt_if(struct net_device *netdev)
+static void nss_tx_rx_virt_if_msg_init(struct nss_tx_rx_virt_if_msg *nrim,
+ uint16_t if_num,
+ uint32_t type,
+ uint32_t len,
+ nss_tx_rx_virt_if_msg_callback_t cb,
+ struct nss_tx_rx_virt_if_handle *app_data)
{
- struct nss_redir_handle *handles;
+ nss_cmn_msg_init(&nrim->cm, if_num, type, len, (void *)cb, (void *)app_data);
+}
- handles = (struct nss_redir_handle *)kzalloc(sizeof(struct nss_redir_handle), GFP_KERNEL);
- if (!handles) {
- nss_warning("%s: kzalloc failed\n", __func__);
+/*
+ * nss_tx_rx_virt_if_handle_create_sync()
+ * Initialize redir handle which holds the if_num and stats per interface.
+ */
+static struct nss_tx_rx_virt_if_handle *nss_tx_rx_virt_if_handle_create(struct nss_ctx_instance *nss_ctx, int32_t if_num, int32_t *cmd_rsp)
+{
+ int32_t index;
+ struct nss_tx_rx_virt_if_handle *handle;
+
+ index = NSS_TX_RX_VIRT_IF_GET_INDEX(if_num);
+
+ handle = (struct nss_tx_rx_virt_if_handle *)kzalloc(sizeof(struct nss_tx_rx_virt_if_handle),
+ GFP_KERNEL);
+ if (!handle) {
+ nss_warning("%p: handle memory alloc failed\n", nss_ctx);
+ *cmd_rsp = NSS_TX_RX_VIRT_IF_ALLOC_FAILURE;
goto error1;
}
- handles->whandle = nss_wifi_if_create(netdev);
- if (!handles->whandle) {
- nss_warning("%s: nss_wifi_if creation failed\n", __func__);
+ handle->nss_ctx = nss_ctx;
+ handle->if_num = if_num;
+ handle->pvt = (struct nss_tx_rx_virt_if_pvt *)kzalloc(sizeof(struct nss_tx_rx_virt_if_pvt),
+ GFP_KERNEL);
+ if (!handle->pvt) {
+ nss_warning("%p: failure allocating memory for nss_tx_rx_virt_if_pvt\n", nss_ctx);
+ *cmd_rsp = NSS_TX_RX_VIRT_IF_ALLOC_FAILURE;
goto error2;
}
- handles->vhandle = nss_virt_if_create(netdev);
- if (!handles->vhandle) {
- nss_warning("%s: nss_virt_if creation failed\n", __func__);
- goto error3;
- }
+ handle->cb = NULL;
+ handle->app_data = NULL;
- return (void *)handles;
-error3:
- nss_wifi_if_destroy(handles->whandle);
+ spin_lock_bh(&nss_tx_rx_virt_if_lock);
+ nss_tx_rx_virt_if_handles[index] = handle;
+ spin_unlock_bh(&nss_tx_rx_virt_if_lock);
+
+ *cmd_rsp = NSS_VIRT_IF_SUCCESS;
+
+ return handle;
+
error2:
- kfree(handles);
+ kfree(handle);
error1:
return NULL;
}
/*
+ * nss_tx_rx_virt_if_register_handler_sync()
+ * register msg handler for redir interface and initialize semaphore and completion.
+ */
+static uint32_t nss_tx_rx_virt_if_register_handler(struct nss_tx_rx_virt_if_handle *handle)
+{
+ uint32_t ret;
+ struct nss_tx_rx_virt_if_pvt *nrip = NULL;
+ int32_t if_num = handle->if_num;
+
+ ret = nss_core_register_handler(if_num, nss_tx_rx_virt_if_msg_handler, NULL);
+ if (ret != NSS_CORE_STATUS_SUCCESS) {
+ nss_warning("%d: Message handler failed to be registered for interface\n", if_num);
+ return NSS_TX_RX_VIRT_IF_CORE_FAILURE;
+ }
+
+ nrip = handle->pvt;
+ if (!nrip->sem_init_done) {
+ sema_init(&nrip->sem, 1);
+ init_completion(&nrip->complete);
+ nrip->sem_init_done = 1;
+ }
+
+ return NSS_TX_RX_VIRT_IF_SUCCESS;
+}
+
+/*
+ * nss_tx_rx_virt_if_tx_msg()
+ */
+nss_tx_status_t nss_tx_rx_virt_if_tx_msg(struct nss_ctx_instance *nss_ctx, struct nss_tx_rx_virt_if_msg *nrim)
+{
+ int32_t status;
+ struct sk_buff *nbuf;
+ struct nss_cmn_msg *ncm = &nrim->cm;
+ struct nss_tx_rx_virt_if_msg *nrim2;
+
+ if (unlikely(nss_ctx->state != NSS_CORE_STATE_INITIALIZED)) {
+ nss_warning("Interface could not be created as core not ready");
+ return NSS_TX_FAILURE;
+ }
+
+ /*
+ * Sanity check the message
+ */
+ if (!NSS_IS_IF_TYPE(DYNAMIC, ncm->interface)) {
+ nss_warning("%p: tx request for another interface: %d", nss_ctx, ncm->interface);
+ return NSS_TX_FAILURE;
+ }
+
+ if (ncm->type > NSS_TX_RX_VIRT_IF_MAX_MSG_TYPES) {
+ nss_warning("%p: message type out of range: %d", nss_ctx, ncm->type);
+ return NSS_TX_FAILURE;
+ }
+
+ if (ncm->len > sizeof(struct nss_tx_rx_virt_if_msg)) {
+ nss_warning("%p: invalid length: %d. Length of redir msg is %d",
+ nss_ctx, ncm->len, sizeof(struct nss_tx_rx_virt_if_msg));
+ return NSS_TX_FAILURE;
+ }
+
+ nbuf = dev_alloc_skb(NSS_NBUF_PAYLOAD_SIZE);
+ if (unlikely(!nbuf)) {
+ NSS_PKT_STATS_INCREMENT(nss_ctx, &nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_NBUF_ALLOC_FAILS]);
+ nss_warning("%p: redir interface %d: command allocation failed", nss_ctx, ncm->interface);
+ return NSS_TX_FAILURE;
+ }
+
+ nrim2 = (struct nss_tx_rx_virt_if_msg *)skb_put(nbuf, sizeof(struct nss_tx_rx_virt_if_msg));
+ memcpy(nrim2, nrim, sizeof(struct nss_tx_rx_virt_if_msg));
+
+ status = nss_core_send_buffer(nss_ctx, 0, nbuf, NSS_IF_CMD_QUEUE, H2N_BUFFER_CTRL, 0);
+ if (status != NSS_CORE_STATUS_SUCCESS) {
+ dev_kfree_skb_any(nbuf);
+ nss_warning("%p: Unable to enqueue 'virtual interface' command\n", nss_ctx);
+ return NSS_TX_FAILURE;
+ }
+
+ nss_hal_send_interrupt(nss_ctx->nmap,
+ nss_ctx->h2n_desc_rings[NSS_IF_CMD_QUEUE].desc_ring.int_bit,
+ NSS_REGS_H2N_INTR_STATUS_DATA_COMMAND_QUEUE);
+
+ /*
+ * The context returned is the redir interface # which is, essentially, the index into the if_ctx
+ * array that is holding the net_device pointer
+ */
+ return NSS_TX_SUCCESS;
+}
+
+/*
+ * nss_tx_rx_virt_if_tx_msg_sync
+ * Send a message from HLOS to NSS synchronously.
+ */
+static nss_tx_status_t nss_tx_rx_virt_if_tx_msg_sync(struct nss_tx_rx_virt_if_handle *handle,
+ struct nss_tx_rx_virt_if_msg *nvim)
+{
+ nss_tx_status_t status;
+ int ret = 0;
+ struct nss_tx_rx_virt_if_pvt *nrip = handle->pvt;
+ struct nss_ctx_instance *nss_ctx = handle->nss_ctx;
+
+ down(&nrip->sem);
+
+ status = nss_tx_rx_virt_if_tx_msg(nss_ctx, nvim);
+ if (status != NSS_TX_SUCCESS) {
+ nss_warning("%p: nss_tx_rx_virt_if_msg failed\n", nss_ctx);
+ up(&nrip->sem);
+ return status;
+ }
+
+ ret = wait_for_completion_timeout(&nrip->complete,
+ msecs_to_jiffies(NSS_TX_RX_VIRT_IF_TX_TIMEOUT));
+ if (!ret) {
+ nss_warning("%p: redir_if tx failed due to timeout\n", nss_ctx);
+ nrip->response = NSS_TX_FAILURE;
+ }
+
+ status = nrip->response;
+ up(&nrip->sem);
+
+ return status;
+}
+
+/*
+ * nss_tx_rx_virt_if_handle_destroy()
+ * Destroy the redir handle either due to request from user or due to error, synchronously.
+ */
+static int nss_tx_rx_virt_if_handle_destroy(struct nss_tx_rx_virt_if_handle *handle)
+{
+ nss_tx_status_t status;
+ int32_t if_num = handle->if_num;
+ int32_t index = NSS_TX_RX_VIRT_IF_GET_INDEX(if_num);
+ struct nss_ctx_instance *nss_ctx = handle->nss_ctx;
+
+ status = nss_dynamic_interface_dealloc_node(if_num, NSS_DYNAMIC_INTERFACE_TYPE_VIRTIF_DEPRECATED);
+ if (status != NSS_TX_SUCCESS) {
+ nss_warning("%p: Dynamic interface destroy failed status %d\n", nss_ctx, status);
+ return status;
+ }
+
+ spin_lock_bh(&nss_tx_rx_virt_if_lock);
+ nss_tx_rx_virt_if_handles[index] = NULL;
+ spin_unlock_bh(&nss_tx_rx_virt_if_lock);
+
+ kfree(handle->pvt);
+ kfree(handle);
+
+ return status;
+}
+
+/*
+ * nss_create_virt_if()
+ * Create a virtual interface synchronously.
+ */
+void *nss_create_virt_if(struct net_device *netdev)
+{
+ struct nss_ctx_instance *nss_ctx = &nss_top_main.nss[nss_top_main.wlan_handler_id];
+ struct nss_tx_rx_virt_if_msg nrim;
+ struct nss_tx_rx_virt_if_create_msg *nrcm;
+ uint32_t ret;
+ struct nss_tx_rx_virt_if_handle *handle = NULL;
+ int32_t if_num;
+
+ if (unlikely(nss_ctx->state != NSS_CORE_STATE_INITIALIZED)) {
+ nss_warning("%p: Interface could not be created as core not ready\n", nss_ctx);
+ return NULL;
+ }
+
+ if_num = nss_dynamic_interface_alloc_node(NSS_DYNAMIC_INTERFACE_TYPE_VIRTIF_DEPRECATED);
+ if (if_num < 0) {
+ nss_warning("%p: failure allocating redir if\n", nss_ctx);
+ return NULL;
+ }
+
+ handle = nss_tx_rx_virt_if_handle_create(nss_ctx, if_num, &ret);
+ if (!handle) {
+ nss_warning("%p:redir_if handle creation failed ret %d\n", nss_ctx, ret);
+ nss_dynamic_interface_dealloc_node(if_num, NSS_DYNAMIC_INTERFACE_TYPE_VIRTIF_DEPRECATED);
+ return NULL;
+ }
+
+ /* Initializes the semaphore and also sets the msg handler for if_num */
+ ret = nss_tx_rx_virt_if_register_handler(handle);
+ if (ret != NSS_VIRT_IF_SUCCESS) {
+ nss_warning("%p: Registration handler failed reason: %d\n", nss_ctx, ret);
+ goto error;
+ }
+
+ nss_tx_rx_virt_if_msg_init(&nrim, handle->if_num, NSS_TX_RX_VIRT_IF_TX_CREATE_MSG,
+ sizeof(struct nss_tx_rx_virt_if_create_msg), nss_tx_rx_virt_if_callback, handle);
+
+ nrcm = &nrim.msg.if_create;
+ nrcm->flags = 0;
+ memcpy(nrcm->mac_addr, netdev->dev_addr, ETH_ALEN);
+
+ ret = nss_tx_rx_virt_if_tx_msg_sync(handle, &nrim);
+ if (ret != NSS_TX_SUCCESS) {
+ nss_warning("%p: nss_tx_rx_virt_if_tx_msg_sync failed %u\n", nss_ctx, ret);
+ goto error;
+ }
+
+ spin_lock_bh(&nss_top_main.lock);
+ if (!nss_top_main.subsys_dp_register[handle->if_num].ndev) {
+ nss_top_main.subsys_dp_register[handle->if_num].ndev = netdev;
+ }
+ spin_unlock_bh(&nss_top_main.lock);
+
+ /*
+ * Hold a reference to the net_device
+ */
+ dev_hold(netdev);
+
+ /*
+ * The context returned is the handle interface # which contains all the info related to
+ * the interface if_num.
+ */
+
+ return (void*)handle;
+
+error:
+ nss_tx_rx_virt_if_handle_destroy(handle);
+ return NULL;
+}
+
+/*
* nss_destroy_virt_if()
+ * Destroy a virtual interface synchronously.
*/
nss_tx_status_t nss_destroy_virt_if(void *ctx)
{
- struct nss_redir_handle *handle = (struct nss_redir_handle *)ctx;
+ struct nss_tx_rx_virt_if_handle *handle = (struct nss_tx_rx_virt_if_handle *)ctx;
+ nss_tx_status_t status;
+ struct net_device *dev;
+ int32_t if_num;
+ struct nss_ctx_instance *nss_ctx;
+ uint32_t ret;
- nss_wifi_if_destroy(handle->whandle);
- nss_virt_if_destroy(handle->vhandle);
+ if (!handle) {
+ nss_warning("handle is NULL\n");
+ return NSS_TX_FAILURE_BAD_PARAM;
+ }
- return NSS_TX_SUCCESS;
+ if_num = handle->if_num;
+ nss_ctx = handle->nss_ctx;
+
+ if (unlikely(nss_ctx->state != NSS_CORE_STATE_INITIALIZED)) {
+ nss_warning("%p: Interface could not be destroyed as core not ready\n", nss_ctx);
+ return NSS_TX_FAILURE_NOT_READY;
+ }
+
+ spin_lock_bh(&nss_top_main.lock);
+ if (!nss_top_main.subsys_dp_register[if_num].ndev) {
+ spin_unlock_bh(&nss_top_main.lock);
+ nss_warning("%p: Unregister redir interface %d: no context\n", nss_ctx, if_num);
+ return NSS_TX_FAILURE_BAD_PARAM;
+ }
+
+ dev = nss_top_main.subsys_dp_register[if_num].ndev;
+ nss_top_main.subsys_dp_register[if_num].ndev = NULL;
+ spin_unlock_bh(&nss_top_main.lock);
+ dev_put(dev);
+
+ status = nss_tx_rx_virt_if_handle_destroy(handle);
+ if (status != NSS_TX_SUCCESS) {
+ nss_warning("%p: handle destroy failed for if_num %d\n", nss_ctx, if_num);
+ return NSS_TX_FAILURE;
+ }
+
+ ret = nss_core_unregister_handler(if_num);
+ if (ret != NSS_CORE_STATUS_SUCCESS) {
+ nss_warning("%p: Not able to unregister handler for redir_if interface %d with NSS core\n", nss_ctx, if_num);
+ return NSS_TX_FAILURE_BAD_PARAM;
+ }
+
+ return status;
+}
+
+/*
+ * nss_tx_rx_virt_if_copy_stats()
+ * Copy stats from the redir_if handle to buffer(line)
+ */
+int32_t nss_tx_rx_virt_if_copy_stats(int32_t if_num, int i, char *line)
+{
+ int32_t bytes = 0;
+ struct nss_tx_rx_virt_if_stats *stats;
+ int32_t ifnum;
+ uint32_t len = 80;
+ struct nss_tx_rx_virt_if_handle *handle = NULL;
+
+ if (if_num < 0) {
+ nss_warning("invalid if_num\n");
+ return 0;
+ }
+
+ ifnum = NSS_TX_RX_VIRT_IF_GET_INDEX(if_num);
+
+ spin_lock_bh(&nss_tx_rx_virt_if_lock);
+ if (!nss_tx_rx_virt_if_handles[ifnum]) {
+ spin_unlock_bh(&nss_tx_rx_virt_if_lock);
+ goto end;
+ }
+
+ handle = nss_tx_rx_virt_if_handles[ifnum];
+ spin_unlock_bh(&nss_tx_rx_virt_if_lock);
+
+ stats = &handle->stats;
+
+ switch (i) {
+ case 0:
+ bytes = scnprintf(line, len, "rx_packets=%d\n",
+ stats->node_stats.rx_packets);
+ break;
+
+ case 1:
+ bytes = scnprintf(line, len, "rx_bytes=%d\n",
+ stats->node_stats.rx_bytes);
+ break;
+
+ case 2:
+ bytes = scnprintf(line, len, "rx_dropped=%d\n",
+ stats->node_stats.rx_dropped);
+ break;
+
+ case 3:
+ bytes = scnprintf(line, len, "tx_packets=%d\n",
+ stats->node_stats.tx_packets);
+ break;
+
+ case 4:
+ bytes = scnprintf(line, len, "tx_bytes=%d\n",
+ stats->node_stats.tx_bytes);
+ break;
+
+ case 5:
+ bytes = scnprintf(line, len, "tx_enqueue_failed=%d\n",
+ stats->tx_enqueue_failed);
+ break;
+
+ case 6:
+ bytes = scnprintf(line, len, "shaper_enqueue_failed=%d\n",
+ stats->shaper_enqueue_failed);
+ break;
+ }
+
+end:
+ return bytes;
}
EXPORT_SYMBOL(nss_tx_virt_if_rxbuf);
@@ -147,4 +725,3 @@
EXPORT_SYMBOL(nss_destroy_virt_if);
EXPORT_SYMBOL(nss_register_virt_if);
EXPORT_SYMBOL(nss_unregister_virt_if);
-
diff --git a/nss_virt_if.c b/nss_virt_if.c
index 9b53f8d..92b80e8 100644
--- a/nss_virt_if.c
+++ b/nss_virt_if.c
@@ -23,19 +23,19 @@
#include <net/arp.h>
#define NSS_VIRT_IF_TX_TIMEOUT 3000 /* 3 Seconds */
-#define NSS_VIRT_IF_INDEX_OFFSET(if_num) (if_num-NSS_DYNAMIC_IF_START)
+#define NSS_VIRT_IF_GET_INDEX(if_num) (if_num-NSS_DYNAMIC_IF_START)
extern int nss_ctl_redirect;
/*
* Data structure that holds the virtual interface context.
*/
-static struct nss_virt_if_handle *virt_handle[NSS_MAX_DYNAMIC_INTERFACES];
+static struct nss_virt_if_handle *nss_virt_if_handle_t[NSS_MAX_DYNAMIC_INTERFACES];
/*
* Spinlock to protect the global data structure virt_handle.
*/
-DEFINE_SPINLOCK(virt_if_lock);
+DEFINE_SPINLOCK(nss_virt_if_lock);
/*
* nss_virt_if_stats_sync()
@@ -84,23 +84,22 @@
return nss_if_msg_handler(nss_ctx, ncm, app_data);
}
- if (((!NSS_IS_IF_TYPE(DYNAMIC, ncm->interface)) &&
- (!NSS_IS_IF_TYPE(VIRTUAL, ncm->interface)))) {
+ if (!NSS_IS_IF_TYPE(DYNAMIC, ncm->interface)) {
nss_warning("%p: response for another interface: %d", nss_ctx, ncm->interface);
return;
}
- if_num = NSS_VIRT_IF_INDEX_OFFSET(ncm->interface);
+ if_num = NSS_VIRT_IF_GET_INDEX(ncm->interface);
- spin_lock_bh(&virt_if_lock);
- if (!virt_handle[if_num]) {
- spin_unlock_bh(&virt_if_lock);
+ spin_lock_bh(&nss_virt_if_lock);
+ if (!nss_virt_if_handle_t[if_num]) {
+ spin_unlock_bh(&nss_virt_if_lock);
nss_warning("%p: virt_if handle is NULL\n", nss_ctx);
return;
}
- handle = virt_handle[if_num];
- spin_unlock_bh(&virt_if_lock);
+ handle = nss_virt_if_handle_t[if_num];
+ spin_unlock_bh(&nss_virt_if_lock);
switch (nvim->cm.type) {
case NSS_VIRT_IF_STATS_SYNC_MSG:
@@ -157,6 +156,586 @@
}
/*
+ * nss_virt_if_tx_msg_sync
+ * Send a message from HLOS to NSS synchronously.
+ */
+static nss_tx_status_t nss_virt_if_tx_msg_sync(struct nss_virt_if_handle *handle,
+ struct nss_virt_if_msg *nvim)
+{
+ nss_tx_status_t status;
+ int ret = 0;
+ struct nss_virt_if_pvt *nwip = handle->pvt;
+ struct nss_ctx_instance *nss_ctx = handle->nss_ctx;
+
+ down(&nwip->sem);
+
+ status = nss_virt_if_tx_msg(nss_ctx, nvim);
+ if (status != NSS_TX_SUCCESS) {
+ nss_warning("%p: nss_virt_if_msg failed\n", nss_ctx);
+ up(&nwip->sem);
+ return status;
+ }
+
+ ret = wait_for_completion_timeout(&nwip->complete,
+ msecs_to_jiffies(NSS_VIRT_IF_TX_TIMEOUT));
+ if (!ret) {
+ nss_warning("%p: virt_if tx failed due to timeout\n", nss_ctx);
+ nwip->response = NSS_TX_FAILURE;
+ }
+
+ status = nwip->response;
+ up(&nwip->sem);
+
+ return status;
+}
+
+/*
+ * nss_virt_if_msg_init()
+ * Initialize virt specific message structure.
+ */
+static void nss_virt_if_msg_init(struct nss_virt_if_msg *nvim,
+ uint16_t if_num,
+ uint32_t type,
+ uint32_t len,
+ nss_virt_if_msg_callback_t cb,
+ struct nss_virt_if_handle *app_data)
+{
+ nss_cmn_msg_init(&nvim->cm, if_num, type, len, (void *)cb, (void *)app_data);
+}
+
+/*
+ * nss_virt_if_register_handler()
+ * register msg handler for virtual interface.
+ */
+static uint32_t nss_virt_if_register_handler(struct nss_virt_if_handle *handle)
+{
+ uint32_t ret;
+ int32_t if_num = handle->if_num;
+
+ ret = nss_core_register_handler(if_num, nss_virt_if_msg_handler, NULL);
+ if (ret != NSS_CORE_STATUS_SUCCESS) {
+ nss_warning("%d: Message handler failed to be registered for interface\n", if_num);
+ return NSS_VIRT_IF_CORE_FAILURE;
+ }
+
+ return NSS_VIRT_IF_SUCCESS;
+}
+
+/*
+ * nss_virt_if_handle_destroy_cb()
+ * Callback to handle the response of destroy message.
+ */
+static void nss_virt_if_handle_destroy_cb(void *app_data, struct nss_dynamic_interface_msg *ndim)
+{
+ nss_virt_if_msg_callback_t cb;
+ void *data;
+ uint32_t index;
+ struct nss_virt_if_handle *handle = (struct nss_virt_if_handle *)app_data;
+
+ cb = handle->cb;
+ data = handle->app_data;
+
+ if (ndim->cm.response != NSS_CMN_RESPONSE_ACK) {
+ nss_warning("%p: Received NACK from DI\n", handle->nss_ctx);
+ goto callback;
+ }
+
+ index = NSS_VIRT_IF_GET_INDEX(handle->if_num);
+ spin_lock_bh(&nss_virt_if_lock);
+ nss_virt_if_handle_t[index] = NULL;
+ spin_unlock_bh(&nss_virt_if_lock);
+
+ kfree(handle);
+callback:
+ if (!cb) {
+ nss_warning("callback is NULL\n");
+ return;
+ }
+
+ cb(data, &ndim->cm);
+}
+
+/*
+ * nss_virt_if_handle_destroy()
+ * Destroy the virt handle either due to request from WLAN or due to error.
+ */
+static int nss_virt_if_handle_destroy(struct nss_virt_if_handle *handle)
+{
+ nss_tx_status_t status;
+ int32_t if_num = handle->if_num;
+ struct nss_ctx_instance *nss_ctx = handle->nss_ctx;
+ struct nss_dynamic_interface_msg ndim;
+ struct nss_dynamic_interface_dealloc_node_msg *ndid;
+
+ nss_dynamic_interface_msg_init(&ndim, NSS_DYNAMIC_INTERFACE, NSS_DYNAMIC_INTERFACE_DEALLOC_NODE,
+ sizeof(struct nss_dynamic_interface_dealloc_node_msg), nss_virt_if_handle_destroy_cb, (void *)handle);
+
+ ndid = &ndim.msg.dealloc_node;
+ ndid->type = NSS_DYNAMIC_INTERFACE_TYPE_802_3_REDIR;
+ ndid->if_num = if_num;
+
+ /*
+ * Send an asynchronous message to the firmware.
+ */
+ status = nss_dynamic_interface_tx(nss_ctx, &ndim);
+ if (status != NSS_TX_SUCCESS) {
+ nss_warning("%p: Dynamic interface destroy failed status %d\n", nss_ctx, status);
+ return status;
+ }
+
+ return status;
+}
+
+/*
+ * nss_virt_if_handle_destroy_sync()
+ * Destroy the virt handle either due to request from user or due to error, synchronously.
+ */
+static int nss_virt_if_handle_destroy_sync(struct nss_virt_if_handle *handle)
+{
+ nss_tx_status_t status;
+ int32_t if_num = handle->if_num;
+ int32_t index = NSS_VIRT_IF_GET_INDEX(if_num);
+ struct nss_ctx_instance *nss_ctx = handle->nss_ctx;
+
+ status = nss_dynamic_interface_dealloc_node(if_num, NSS_DYNAMIC_INTERFACE_TYPE_802_3_REDIR);
+ if (status != NSS_TX_SUCCESS) {
+ nss_warning("%p: Dynamic interface destroy failed status %d\n", nss_ctx, status);
+ return status;
+ }
+
+ spin_lock_bh(&nss_virt_if_lock);
+ nss_virt_if_handle_t[index] = NULL;
+ spin_unlock_bh(&nss_virt_if_lock);
+
+ kfree(handle->pvt);
+ kfree(handle);
+
+ return status;
+}
+
+/*
+ * nss_virt_if_handle_create_cb()
+ * Callback to handle the response from dynamic interface for an alloc node msg.
+ */
+static void nss_virt_if_handle_create_cb(void *app_data, struct nss_dynamic_interface_msg *ndim)
+{
+ struct nss_virt_if_handle *handle = (struct nss_virt_if_handle *)app_data;
+ nss_virt_if_msg_callback_t cb;
+ struct nss_virt_if_msg nvim;
+ struct nss_virt_if_create_msg *nvcm;
+ void *data;
+ int32_t if_num;
+ uint32_t index;
+ int ret;
+
+ cb = handle->cb;
+ data = handle->app_data;
+
+ if (ndim->cm.response != NSS_CMN_RESPONSE_ACK) {
+ nss_warning("%p: received NACK from NSS %d\n", handle->nss_ctx, ndim->cm.response);
+ kfree(handle);
+ goto fail;
+ }
+
+ if_num = ndim->msg.alloc_node.if_num;
+
+ spin_lock_bh(&nss_virt_if_lock);
+ handle->if_num = if_num;
+ index = NSS_VIRT_IF_GET_INDEX(if_num);
+ nss_virt_if_handle_t[index] = handle;
+ spin_unlock_bh(&nss_virt_if_lock);
+
+ /* Register the msg handler for if_num */
+ ret = nss_virt_if_register_handler(handle);
+ if (ret != NSS_VIRT_IF_SUCCESS) {
+ nss_warning("%p: Registration handler failed reason: %d\n", handle->nss_ctx, ret);
+ nss_virt_if_handle_destroy(handle);
+ goto fail;
+ }
+
+ /*
+ * Send virt_if message to the Firmware to copy the netdev's macaddr
+ */
+ nss_virt_if_msg_init(&nvim, handle->if_num, NSS_VIRT_IF_TX_CREATE_MSG,
+ sizeof(struct nss_virt_if_create_msg), NULL, NULL);
+
+ nvcm = &nvim.msg.if_create;
+ nvcm->flags = 0;
+ memcpy(nvcm->mac_addr, handle->ndev->dev_addr, ETH_ALEN);
+
+ ret = nss_virt_if_tx_msg(handle->nss_ctx, &nvim);
+ if (ret != NSS_TX_SUCCESS) {
+ nss_warning("%p: nss_virt_if_tx_msg failed %u\n", handle->nss_ctx, ret);
+ nss_virt_if_handle_destroy(handle);
+ goto fail;
+ }
+
+ spin_lock_bh(&nss_top_main.lock);
+ if (!nss_top_main.subsys_dp_register[handle->if_num].ndev) {
+ nss_top_main.subsys_dp_register[handle->if_num].ndev = handle->ndev;
+ }
+ spin_unlock_bh(&nss_top_main.lock);
+
+ /*
+ * Hold a reference to the net_device
+ */
+ dev_hold(handle->ndev);
+
+ /*
+ * The context returned is the handle which contains all the info related to
+ * the interface if_num.
+ */
+
+fail:
+ if (!cb) {
+ nss_warning("cb is NULL\n");
+ return;
+ }
+
+ cb(data, &ndim->cm);
+}
+
+/*
+ * nss_virt_if_handle_create()
+ * Create and initialize virt_if handle.
+ */
+static struct nss_virt_if_handle *nss_virt_if_handle_create(struct nss_ctx_instance *nss_ctx,
+ struct net_device *ndev,
+ nss_virt_if_msg_callback_t cb,
+ void *app_data,
+ int *cmd_rsp)
+{
+ struct nss_virt_if_handle *handle;
+
+ handle = (struct nss_virt_if_handle *)kzalloc(sizeof(struct nss_virt_if_handle),
+ GFP_ATOMIC);
+ if (!handle) {
+ nss_warning("%p: handle memory alloc failed\n", nss_ctx);
+ *cmd_rsp = NSS_VIRT_IF_ALLOC_FAILURE;
+ goto error;
+ }
+
+ /*
+ * Save the callback & appdata of the user. The callback will be invoked from
+ * nss_virt_if_handle_create_cb.
+ */
+ handle->nss_ctx = nss_ctx;
+ handle->ndev = ndev;
+ handle->cb = cb;
+ handle->app_data = app_data;
+
+ *cmd_rsp = NSS_VIRT_IF_SUCCESS;
+
+ return handle;
+
+error:
+ return NULL;
+}
+
+/*
+ * nss_virt_if_handle_create_sync()
+ * Initialize virt handle which holds the if_num and stats per interface.
+ */
+static struct nss_virt_if_handle *nss_virt_if_handle_create_sync(struct nss_ctx_instance *nss_ctx, int32_t if_num, int32_t *cmd_rsp)
+{
+ int32_t index;
+ struct nss_virt_if_handle *handle;
+
+ index = NSS_VIRT_IF_GET_INDEX(if_num);
+
+ handle = (struct nss_virt_if_handle *)kzalloc(sizeof(struct nss_virt_if_handle),
+ GFP_KERNEL);
+ if (!handle) {
+ nss_warning("%p: handle memory alloc failed\n", nss_ctx);
+ *cmd_rsp = NSS_VIRT_IF_ALLOC_FAILURE;
+ goto error1;
+ }
+
+ handle->nss_ctx = nss_ctx;
+ handle->if_num = if_num;
+ handle->pvt = (struct nss_virt_if_pvt *)kzalloc(sizeof(struct nss_virt_if_pvt),
+ GFP_KERNEL);
+ if (!handle->pvt) {
+ nss_warning("%p: failure allocating memory for nss_virt_if_pvt\n", nss_ctx);
+ *cmd_rsp = NSS_VIRT_IF_ALLOC_FAILURE;
+ goto error2;
+ }
+
+ handle->cb = NULL;
+ handle->app_data = NULL;
+
+ spin_lock_bh(&nss_virt_if_lock);
+ nss_virt_if_handle_t[index] = handle;
+ spin_unlock_bh(&nss_virt_if_lock);
+
+ *cmd_rsp = NSS_VIRT_IF_SUCCESS;
+
+ return handle;
+
+error2:
+ kfree(handle);
+error1:
+ return NULL;
+}
+
+/*
+ * nss_virt_if_register_handler_sync()
+ * register msg handler for virtual interface and initialize semaphore and completion.
+ */
+static uint32_t nss_virt_if_register_handler_sync(struct nss_virt_if_handle *handle)
+{
+ uint32_t ret;
+ struct nss_virt_if_pvt *nvip = NULL;
+ int32_t if_num = handle->if_num;
+
+ ret = nss_core_register_handler(if_num, nss_virt_if_msg_handler, NULL);
+ if (ret != NSS_CORE_STATUS_SUCCESS) {
+ nss_warning("%d: Message handler failed to be registered for interface\n", if_num);
+ return NSS_VIRT_IF_CORE_FAILURE;
+ }
+
+ nvip = handle->pvt;
+ if (!nvip->sem_init_done) {
+ sema_init(&nvip->sem, 1);
+ init_completion(&nvip->complete);
+ nvip->sem_init_done = 1;
+ }
+
+ return NSS_VIRT_IF_SUCCESS;
+}
+
+/*
+ * nss_virt_if_create()
+ * Create a virtual interface and associate it with the netdev, asynchronously.
+ */
+int nss_virt_if_create(struct net_device *netdev, nss_virt_if_msg_callback_t cb, void *app_data)
+{
+ struct nss_ctx_instance *nss_ctx = &nss_top_main.nss[nss_top_main.wlan_handler_id];
+ struct nss_dynamic_interface_msg ndim;
+ struct nss_dynamic_interface_alloc_node_msg *ndia;
+ int ret;
+ struct nss_virt_if_handle *handle = NULL;
+
+ if (unlikely(nss_ctx->state != NSS_CORE_STATE_INITIALIZED)) {
+ nss_warning("%p: Interface could not be created as core not ready\n", nss_ctx);
+ return NSS_VIRT_IF_CORE_FAILURE;
+ }
+
+ /*
+ * Create the virt_if handle and associate the cb and app_data with it.
+ */
+ handle = nss_virt_if_handle_create(nss_ctx, netdev, cb, app_data, &ret);
+ if (!handle) {
+ nss_warning("%p:virt_if handle create failed ret %d\n", nss_ctx, ret);
+ return ret;
+ }
+
+ ndia = &ndim.msg.alloc_node;
+ ndia->type = NSS_DYNAMIC_INTERFACE_TYPE_802_3_REDIR;
+
+ /*
+ * Construct a dynamic interface message and send it to the firmware.
+ */
+ nss_dynamic_interface_msg_init(&ndim, NSS_DYNAMIC_INTERFACE, NSS_DYNAMIC_INTERFACE_ALLOC_NODE,
+ sizeof(struct nss_dynamic_interface_alloc_node_msg), nss_virt_if_handle_create_cb, (void *)handle);
+
+ ret = nss_dynamic_interface_tx(nss_ctx, &ndim);
+ if (ret != NSS_TX_SUCCESS) {
+ nss_warning("%p: failure allocating virt if\n", nss_ctx);
+ ret = NSS_VIRT_IF_DYNAMIC_IF_FAILURE;
+ kfree(handle);
+ return ret;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(nss_virt_if_create);
+
+/*
+ * nss_virt_if_create_sync()
+ * Create a virt interface, synchronously and associate it with the netdev
+ */
+struct nss_virt_if_handle *nss_virt_if_create_sync(struct net_device *netdev)
+{
+ struct nss_ctx_instance *nss_ctx = &nss_top_main.nss[nss_top_main.wlan_handler_id];
+ struct nss_virt_if_msg nvim;
+ struct nss_virt_if_create_msg *nvcm;
+ uint32_t ret;
+ struct nss_virt_if_handle *handle = NULL;
+ int32_t if_num;
+
+ if (unlikely(nss_ctx->state != NSS_CORE_STATE_INITIALIZED)) {
+ nss_warning("%p: Interface could not be created as core not ready\n", nss_ctx);
+ return NULL;
+ }
+
+ if_num = nss_dynamic_interface_alloc_node(NSS_DYNAMIC_INTERFACE_TYPE_802_3_REDIR);
+ if (if_num < 0) {
+ nss_warning("%p: failure allocating virt if\n", nss_ctx);
+ return NULL;
+ }
+
+ handle = nss_virt_if_handle_create_sync(nss_ctx, if_num, &ret);
+ if (!handle) {
+ nss_warning("%p:virt_if handle creation failed ret %d\n", nss_ctx, ret);
+ nss_dynamic_interface_dealloc_node(if_num, NSS_DYNAMIC_INTERFACE_TYPE_802_3_REDIR);
+ return NULL;
+ }
+
+ /* Initializes the semaphore and also sets the msg handler for if_num */
+ ret = nss_virt_if_register_handler_sync(handle);
+ if (ret != NSS_VIRT_IF_SUCCESS) {
+ nss_warning("%p: Registration handler failed reason: %d\n", nss_ctx, ret);
+ goto error;
+ }
+
+ nss_virt_if_msg_init(&nvim, handle->if_num, NSS_VIRT_IF_TX_CREATE_MSG,
+ sizeof(struct nss_virt_if_create_msg), nss_virt_if_callback, handle);
+
+ nvcm = &nvim.msg.if_create;
+ nvcm->flags = 0;
+ memcpy(nvcm->mac_addr, netdev->dev_addr, ETH_ALEN);
+
+ ret = nss_virt_if_tx_msg_sync(handle, &nvim);
+ if (ret != NSS_TX_SUCCESS) {
+ nss_warning("%p: nss_virt_if_tx_msg_sync failed %u\n", nss_ctx, ret);
+ goto error;
+ }
+
+ spin_lock_bh(&nss_top_main.lock);
+ if (!nss_top_main.subsys_dp_register[handle->if_num].ndev) {
+ nss_top_main.subsys_dp_register[handle->if_num].ndev = netdev;
+ }
+ spin_unlock_bh(&nss_top_main.lock);
+
+ /*
+ * Hold a reference to the net_device
+ */
+ dev_hold(netdev);
+
+ /*
+ * The context returned is the handle interface # which contains all the info related to
+ * the interface if_num.
+ */
+
+ return handle;
+
+error:
+ nss_virt_if_handle_destroy_sync(handle);
+ return NULL;
+}
+EXPORT_SYMBOL(nss_virt_if_create_sync);
+
+/*
+ * nss_virt_if_destroy()
+ * Destroy the virt interface associated with the interface number, by sending
+ * sending an asynchronous message to dynamic interface.
+ */
+nss_tx_status_t nss_virt_if_destroy(struct nss_virt_if_handle *handle, nss_virt_if_msg_callback_t cb, void *app_data)
+{
+ nss_tx_status_t status;
+ struct net_device *dev;
+ int32_t if_num;
+ struct nss_ctx_instance *nss_ctx;
+ uint32_t ret;
+
+ if (!handle) {
+ nss_warning("handle is NULL\n");
+ return NSS_TX_FAILURE_BAD_PARAM;
+ }
+
+ if_num = handle->if_num;
+ nss_ctx = handle->nss_ctx;
+ handle->cb = cb;
+ handle->app_data = app_data;
+
+ if (unlikely(nss_ctx->state != NSS_CORE_STATE_INITIALIZED)) {
+ nss_warning("%p: Interface could not be destroyed as core not ready\n", nss_ctx);
+ return NSS_TX_FAILURE_NOT_READY;
+ }
+
+ spin_lock_bh(&nss_top_main.lock);
+ if (!nss_top_main.subsys_dp_register[if_num].ndev) {
+ spin_unlock_bh(&nss_top_main.lock);
+ nss_warning("%p: Unregister virt interface %d: no context\n", nss_ctx, if_num);
+ return NSS_TX_FAILURE_BAD_PARAM;
+ }
+
+ dev = nss_top_main.subsys_dp_register[if_num].ndev;
+ nss_top_main.subsys_dp_register[if_num].ndev = NULL;
+ spin_unlock_bh(&nss_top_main.lock);
+ dev_put(dev);
+
+ status = nss_virt_if_handle_destroy(handle);
+ if (status != NSS_TX_SUCCESS) {
+ nss_warning("%p: handle destroy tx failed %d\n", nss_ctx, status);
+ return NSS_TX_FAILURE;
+ }
+
+ ret = nss_core_unregister_handler(if_num);
+ if (ret != NSS_CORE_STATUS_SUCCESS) {
+ nss_warning("Not able to unregister handler for virt_if interface %d with NSS core\n", if_num);
+ return NSS_TX_FAILURE_BAD_PARAM;
+ }
+
+ return status;
+}
+EXPORT_SYMBOL(nss_virt_if_destroy);
+
+/*
+ * nss_virt_if_destroy_sync()
+ * Destroy the virt interface associated with the interface number, synchronously.
+ */
+nss_tx_status_t nss_virt_if_destroy_sync(struct nss_virt_if_handle *handle)
+{
+ nss_tx_status_t status;
+ struct net_device *dev;
+ int32_t if_num;
+ struct nss_ctx_instance *nss_ctx;
+ uint32_t ret;
+
+ if (!handle) {
+ nss_warning("handle is NULL\n");
+ return NSS_TX_FAILURE_BAD_PARAM;
+ }
+
+ if_num = handle->if_num;
+ nss_ctx = handle->nss_ctx;
+
+ if (unlikely(nss_ctx->state != NSS_CORE_STATE_INITIALIZED)) {
+ nss_warning("%p: Interface could not be destroyed as core not ready\n", nss_ctx);
+ return NSS_TX_FAILURE_NOT_READY;
+ }
+
+ spin_lock_bh(&nss_top_main.lock);
+ if (!nss_top_main.subsys_dp_register[if_num].ndev) {
+ spin_unlock_bh(&nss_top_main.lock);
+ nss_warning("%p: Unregister virt interface %d: no context\n", nss_ctx, if_num);
+ return NSS_TX_FAILURE_BAD_PARAM;
+ }
+
+ dev = nss_top_main.subsys_dp_register[if_num].ndev;
+ nss_top_main.subsys_dp_register[if_num].ndev = NULL;
+ spin_unlock_bh(&nss_top_main.lock);
+ dev_put(dev);
+
+ status = nss_virt_if_handle_destroy_sync(handle);
+ if (status != NSS_TX_SUCCESS) {
+ nss_warning("%p: handle destroy failed for if_num %d\n", nss_ctx, if_num);
+ return NSS_TX_FAILURE;
+ }
+
+ ret = nss_core_unregister_handler(if_num);
+ if (ret != NSS_CORE_STATUS_SUCCESS) {
+ nss_warning("%p: Not able to unregister handler for virt_if interface %d with NSS core\n", nss_ctx, if_num);
+ return NSS_TX_FAILURE_BAD_PARAM;
+ }
+
+ return status;
+}
+EXPORT_SYMBOL(nss_virt_if_destroy_sync);
+
+/*
* nss_virt_if_tx_buf()
* HLOS interface has received a packet which we redirect to the NSS, if appropriate to do so.
*/
@@ -175,7 +754,7 @@
return NSS_TX_FAILURE_NOT_SUPPORTED;
}
- nss_assert(NSS_IS_IF_TYPE(DYNAMIC, if_num) || NSS_IS_IF_TYPE(VIRTUAL, if_num));
+ nss_assert(NSS_IS_IF_TYPE(DYNAMIC, if_num));
nss_trace("%p: Virtual Rx packet, if_num:%d, skb:%p", nss_ctx, if_num, skb);
/*
@@ -226,268 +805,6 @@
EXPORT_SYMBOL(nss_virt_if_tx_buf);
/*
- * nss_virt_if_tx_msg_sync
- * Send a message from HLOS to NSS synchronously.
- */
-static nss_tx_status_t nss_virt_if_tx_msg_sync(struct nss_virt_if_handle *handle,
- struct nss_virt_if_msg *nvim)
-{
- nss_tx_status_t status;
- int ret = 0;
- struct nss_virt_if_pvt *nwip = handle->pvt;
- struct nss_ctx_instance *nss_ctx = handle->nss_ctx;
-
- down(&nwip->sem);
-
- status = nss_virt_if_tx_msg(nss_ctx, nvim);
- if (status != NSS_TX_SUCCESS) {
- nss_warning("%p: nss_virt_if_msg failed\n", nss_ctx);
- up(&nwip->sem);
- return status;
- }
-
- ret = wait_for_completion_timeout(&nwip->complete,
- msecs_to_jiffies(NSS_VIRT_IF_TX_TIMEOUT));
- if (!ret) {
- nss_warning("%p: virt_if tx failed due to timeout\n", nss_ctx);
- nwip->response = NSS_TX_FAILURE;
- }
-
- status = nwip->response;
- up(&nwip->sem);
-
- return status;
-}
-
-/*
- * nss_virt_if_handle_destroy()
- * Destroy the virt handle either due to request from WLAN or due to error.
- */
-static int nss_virt_if_handle_destroy(struct nss_virt_if_handle *handle)
-{
- nss_tx_status_t status;
- int32_t if_num = handle->if_num;
- int32_t index = NSS_VIRT_IF_INDEX_OFFSET(if_num);
- struct nss_ctx_instance *nss_ctx = handle->nss_ctx;
-
- spin_lock_bh(&virt_if_lock);
- virt_handle[index] = NULL;
- spin_unlock_bh(&virt_if_lock);
-
- status = nss_dynamic_interface_dealloc_node(if_num, NSS_DYNAMIC_INTERFACE_TYPE_802_3_REDIR);
- if (status != NSS_TX_SUCCESS) {
- nss_warning("%p: Dynamic interface destroy failed status %d\n", nss_ctx, status);
- return status;
- }
-
- kfree(handle->pvt);
- kfree(handle);
-
- return status;
-}
-
-/*
- * nss_virt_if_handle_init()
- * Initialize virt handle which holds the if_num and stats per interface.
- */
-static struct nss_virt_if_handle *nss_virt_if_handle_create(struct nss_ctx_instance *nss_ctx, int32_t *cmd_rsp)
-{
- int32_t index;
- int32_t if_num = 0;
- struct nss_virt_if_handle *handle;
-
- if_num = nss_dynamic_interface_alloc_node(NSS_DYNAMIC_INTERFACE_TYPE_802_3_REDIR);
- if (if_num < 0) {
- nss_warning("%p: failure allocating virt if\n", nss_ctx);
- *cmd_rsp = NSS_VIRT_IF_DYNAMIC_IF_FAILURE;
- return NULL;
- }
-
- index = NSS_VIRT_IF_INDEX_OFFSET(if_num);
-
- handle = (struct nss_virt_if_handle *)kzalloc(sizeof(struct nss_virt_if_handle),
- GFP_KERNEL);
- if (!handle) {
- nss_warning("%p: handle memory alloc failed\n", nss_ctx);
- *cmd_rsp = NSS_VIRT_IF_ALLOC_FAILURE;
- goto error1;
- }
-
- handle->nss_ctx = nss_ctx;
- handle->if_num = if_num;
- handle->pvt = (struct nss_virt_if_pvt *)kzalloc(sizeof(struct nss_virt_if_pvt),
- GFP_KERNEL);
- if (!handle->pvt) {
- nss_warning("%p: failure allocating memory for nss_virt_if_pvt\n", nss_ctx);
- *cmd_rsp = NSS_VIRT_IF_ALLOC_FAILURE;
- goto error2;
- }
-
- handle->cb = NULL;
- handle->app_data = NULL;
-
- spin_lock_bh(&virt_if_lock);
- virt_handle[index] = handle;
- spin_unlock_bh(&virt_if_lock);
-
- *cmd_rsp = NSS_VIRT_IF_SUCCESS;
-
- return handle;
-
-error2:
- kfree(handle);
-error1:
- nss_dynamic_interface_dealloc_node(if_num, NSS_DYNAMIC_INTERFACE_TYPE_802_3_REDIR);
- return NULL;
-}
-
-/* nss_virt_if_msg_init()
- * Initialize virt specific message structure.
- */
-static void nss_virt_if_msg_init(struct nss_virt_if_msg *nvim,
- uint16_t if_num,
- uint32_t type,
- uint32_t len,
- nss_virt_if_msg_callback_t cb,
- struct nss_virt_if_handle *app_data)
-{
- nss_cmn_msg_init(&nvim->cm, if_num, type, len, (void *)cb, (void *)app_data);
-}
-
-/*
- * nss_virt_if_register_handler()
- * register handler for statically allocated virtual interface on NSS with NSS core.
- */
-static uint32_t nss_virt_if_register_handler(struct nss_virt_if_handle *handle)
-{
- uint32_t ret;
- struct nss_virt_if_pvt *nvip = NULL;
- int32_t if_num = handle->if_num;
-
- ret = nss_core_register_handler(if_num, nss_virt_if_msg_handler, NULL);
- if (ret != NSS_CORE_STATUS_SUCCESS) {
- nss_warning("%d: Message handler failed to be registered for interface\n", if_num);
- return NSS_VIRT_IF_CORE_FAILURE;
- }
-
- nvip = handle->pvt;
- if (!nvip->sem_init_done) {
- sema_init(&nvip->sem, 1);
- init_completion(&nvip->complete);
- nvip->sem_init_done = 1;
- }
-
- return NSS_VIRT_IF_SUCCESS;
-}
-
-/*
- * nss_virt_if_create()
- * Create a virt interface and associate it with the netdev
- */
-struct nss_virt_if_handle *nss_virt_if_create(struct net_device *netdev)
-{
- struct nss_ctx_instance *nss_ctx = &nss_top_main.nss[nss_top_main.wlan_handler_id];
- struct nss_virt_if_msg nvim;
- struct nss_virt_if_create_msg *nvcm;
- uint32_t ret;
- struct nss_virt_if_handle *handle = NULL;
-
- if (unlikely(nss_ctx->state != NSS_CORE_STATE_INITIALIZED)) {
- nss_warning("%p: Interface could not be created as core not ready\n", nss_ctx);
- return NULL;
- }
-
- handle = nss_virt_if_handle_create(nss_ctx, &ret);
- if (!handle) {
- nss_warning("%p:virt_if handle creation failed ret %d\n", nss_ctx, ret);
- return NULL;
- }
-
- /* Initializes the semaphore and also sets the msg handler for if_num */
- ret = nss_virt_if_register_handler(handle);
- if (ret != NSS_VIRT_IF_SUCCESS) {
- nss_warning("%p: Registration handler failed reason: %d\n", nss_ctx, ret);
- goto error;
- }
-
- nss_virt_if_msg_init(&nvim, handle->if_num, NSS_VIRT_IF_TX_CREATE_MSG,
- sizeof(struct nss_virt_if_create_msg), nss_virt_if_callback, handle);
-
- nvcm = &nvim.msg.if_create;
- nvcm->flags = 0;
- memcpy(nvcm->mac_addr, netdev->dev_addr, ETH_ALEN);
-
- ret = nss_virt_if_tx_msg_sync(handle, &nvim);
- if (ret != NSS_TX_SUCCESS) {
- nss_warning("%p: nss_virt_if_tx_msg_sync failed %u\n", nss_ctx, ret);
- goto error;
- }
-
- spin_lock_bh(&nss_top_main.lock);
- if (!nss_top_main.subsys_dp_register[handle->if_num].ndev) {
- nss_top_main.subsys_dp_register[handle->if_num].ndev = netdev;
- }
- spin_unlock_bh(&nss_top_main.lock);
-
- /*
- * Hold a reference to the net_device
- */
- dev_hold(netdev);
-
- /*
- * The context returned is the handle interface # which contains all the info related to
- * the interface if_num.
- */
-
- return handle;
-
-error:
- nss_virt_if_handle_destroy(handle);
- return NULL;
-}
-EXPORT_SYMBOL(nss_virt_if_create);
-
-/*
- * nss_virt_if_destroy()
- * Destroy the virt interface associated with the interface number.
- */
-nss_tx_status_t nss_virt_if_destroy(struct nss_virt_if_handle *handle)
-{
- nss_tx_status_t status;
- struct net_device *dev;
- int32_t if_num;
- struct nss_ctx_instance *nss_ctx;
-
- if (!handle) {
- nss_warning("nss_virt_if_destroy handle is NULL\n");
- return NSS_TX_FAILURE_BAD_PARAM;
- }
-
- if_num = handle->if_num;
- nss_ctx = handle->nss_ctx;
-
- if (unlikely(nss_ctx->state != NSS_CORE_STATE_INITIALIZED)) {
- nss_warning("%p: Interface could not be destroyed as core not ready\n", nss_ctx);
- return NSS_TX_FAILURE_NOT_READY;
- }
-
- spin_lock_bh(&nss_top_main.lock);
- if (!nss_top_main.subsys_dp_register[if_num].ndev) {
- spin_unlock_bh(&nss_top_main.lock);
- nss_warning("%p: Unregister virt interface %d: no context\n", nss_ctx, if_num);
- return NSS_TX_FAILURE_BAD_PARAM;
- }
-
- dev = nss_top_main.subsys_dp_register[if_num].ndev;
- nss_top_main.subsys_dp_register[if_num].ndev = NULL;
- spin_unlock_bh(&nss_top_main.lock);
- dev_put(dev);
-
- status = nss_virt_if_handle_destroy(handle);
- return status;
-}
-EXPORT_SYMBOL(nss_virt_if_destroy);
-/*
* nss_virt_if_tx_msg()
*/
nss_tx_status_t nss_virt_if_tx_msg(struct nss_ctx_instance *nss_ctx, struct nss_virt_if_msg *nvim)
@@ -505,7 +822,7 @@
/*
* Sanity check the message
*/
- if (((!NSS_IS_IF_TYPE(DYNAMIC, ncm->interface)) && (!NSS_IS_IF_TYPE(VIRTUAL, ncm->interface)))) {
+ if (!NSS_IS_IF_TYPE(DYNAMIC, ncm->interface)) {
nss_warning("%p: tx request for another interface: %d", nss_ctx, ncm->interface);
return NSS_TX_FAILURE;
}
@@ -560,7 +877,7 @@
int32_t if_num;
if (!handle) {
- nss_warning("nss_virt_if_register handle is NULL\n");
+ nss_warning("handle is NULL\n");
return;
}
@@ -581,7 +898,7 @@
int32_t if_num;
if (!handle) {
- nss_warning("nss_virt_if_unregister handle is NULL\n");
+ nss_warning("handle is NULL\n");
return;
}
@@ -609,20 +926,20 @@
struct nss_virt_if_handle *handle = NULL;
if (if_num < 0) {
- nss_warning("nss_virt_if_copy_stats invalid if_num\n");
- return bytes;
+ nss_warning("invalid if_num\n");
+ return 0;
}
- ifnum = NSS_VIRT_IF_INDEX_OFFSET(if_num);
+ ifnum = NSS_VIRT_IF_GET_INDEX(if_num);
- spin_lock_bh(&virt_if_lock);
- if (!virt_handle[ifnum]) {
- spin_unlock_bh(&virt_if_lock);
+ spin_lock_bh(&nss_virt_if_lock);
+ if (!nss_virt_if_handle_t[ifnum]) {
+ spin_unlock_bh(&nss_virt_if_lock);
goto end;
}
- handle = virt_handle[ifnum];
- spin_unlock_bh(&virt_if_lock);
+ handle = nss_virt_if_handle_t[ifnum];
+ spin_unlock_bh(&nss_virt_if_lock);
stats = &handle->stats;
@@ -671,10 +988,8 @@
* nss_virt_if_get_interface_num()
* Get interface number for a virtual interface
*/
-int32_t nss_virt_if_get_interface_num(void *ctx)
+int32_t nss_virt_if_get_interface_num(struct nss_virt_if_handle *handle)
{
- struct nss_virt_if_handle *handle = (struct nss_virt_if_handle *)ctx;
-
if (!handle) {
nss_warning("virt_if handle is NULL\n");
return -1;