Merge "qca-wifi: Multi-Link Repeater Enhancements"

This commit is contained in:
Linux Build Service Account
2020-10-27 03:07:42 -07:00
committed by Gerrit - the friendly Code Review server
3 changed files with 355 additions and 163 deletions

View File

@@ -21,6 +21,7 @@
#include <qdf_module.h> #include <qdf_module.h>
#include <qdf_list.h> #include <qdf_list.h>
#include <qdf_util.h> #include <qdf_util.h>
#include <qdf_lock.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include <linux/version.h> #include <linux/version.h>
@@ -34,8 +35,7 @@
#include "if_upperproto.h" #include "if_upperproto.h"
#define QCA_MULTI_LINK_FAST_LANE_LIST_SIZE 6 #define QCA_MULTI_LINK_RADIO_LIST_SIZE 6
#define QCA_MULTI_LINK_NO_BACKHAUL_LIST_SIZE 32
/** /**
* qca_multi_link_needs_enq - rptr return status * qca_multi_link_needs_enq - rptr return status
@@ -61,15 +61,55 @@ typedef enum qca_multi_link_status {
} qca_multi_link_status_t; } qca_multi_link_status_t;
/** /**
* struct qca_multi_link_list_node - rptr list node * struct qca_multi_link_statistics - rptr drop statistics
* @list: linked list node
* @wiphy: wiphy pointer
*/ */
struct qca_multi_link_list_node { typedef struct qca_multi_link_statistics {
uint32_t ap_rx_sec_sta_null;
uint32_t sta_rx_sec_sta_mcast_no_fdb;
uint32_t sta_rx_sec_sta_mcast_dup_pkts;
uint32_t sta_rx_sec_sta_mcast_drop_sec;
uint32_t sta_rx_sec_sta_mcast_drop;
uint32_t sta_rx_sec_sta_ucast_src_eth;
uint32_t sta_rx_sec_sta_ucast_src_dif_band;
uint32_t sta_rx_sec_sta_ucast_no_ap;
uint32_t sta_rx_pri_sta_mcast_no_fdb;
uint32_t sta_rx_pri_sta_mcast_drop;
uint32_t sta_tx_sec_sta_alwys_prim;
uint32_t sta_tx_sec_sta_mcast_no_fdb;
uint32_t sta_tx_sec_sta_src_eth;
uint32_t sta_tx_sec_sta_mcast_drop_sec;
uint32_t sta_tx_sec_sta_drop_dif_band;
uint32_t sta_tx_pri_sta_drop_no_fdb;
uint32_t sta_tx_pri_sta_drop_dif_band;
} qca_ml_global_stats_t;
/**
* struct qca_multi_link_radio_list_node - rptr list node
* @node: linked list node
* @wiphy: wiphy pointer
* @no_backhaul: is no_backhaul radio
* @is_fast_lane: is fast_lane radio
* @sta_dev: radio's station net device
*/
typedef struct qca_multi_link_radio_list_node {
qdf_list_node_t node; qdf_list_node_t node;
struct wiphy *wiphy; struct wiphy *wiphy;
}; bool no_backhaul;
bool is_fast_lane;
struct net_device *sta_dev;
} qca_multi_link_radio_node_t;
/**
* struct qca_multi_link_parameters - rptr list node
* @rptr_processing_enable: repeater is enabled
* @loop_detected: is loop detected
* @always_primary: is always primary flag enabled
* @force_client_mcast_traffic: is force client mcast flag enabled
* @drop_secondary_mcast: is drop secondary mcast flag enabled
* @primary_wiphy: primary radio pointer
* @total_stavaps_up: total number of backhauls
* @radio_list: list of radio participating in repeater
*/
typedef struct qca_multi_link_parameters { typedef struct qca_multi_link_parameters {
bool rptr_processing_enable; bool rptr_processing_enable;
bool loop_detected; bool loop_detected;
@@ -78,12 +118,13 @@ typedef struct qca_multi_link_parameters {
bool drop_secondary_mcast; bool drop_secondary_mcast;
struct wiphy *primary_wiphy; struct wiphy *primary_wiphy;
uint8_t total_stavaps_up; uint8_t total_stavaps_up;
qdf_list_t no_backhaul_list; qdf_list_t radio_list;
qdf_list_t fast_lane_list; qdf_spinlock_t radio_lock;
qca_ml_global_stats_t qca_ml_stats;
} qca_multi_link_parameters_t; } qca_multi_link_parameters_t;
void qca_multi_link_init_module(void);
void qca_multi_link_deinit_module(void); void qca_multi_link_deinit_module(void);
void qca_multi_link_init_module(void);
uint8_t qca_multi_link_get_num_sta(void); uint8_t qca_multi_link_get_num_sta(void);
void qca_multi_link_append_num_sta(bool inc_or_dec); void qca_multi_link_append_num_sta(bool inc_or_dec);
bool qca_multi_link_is_dbdc_processing_reqd(struct net_device *net_dev); bool qca_multi_link_is_dbdc_processing_reqd(struct net_device *net_dev);
@@ -93,10 +134,15 @@ void qca_multi_link_set_always_primary(bool val);
void qca_multi_link_set_dbdc_enable(bool val); void qca_multi_link_set_dbdc_enable(bool val);
struct wiphy *qca_multi_link_get_primary_radio(void); struct wiphy *qca_multi_link_get_primary_radio(void);
void qca_multi_link_set_primary_radio(struct wiphy *primary_wiphy); void qca_multi_link_set_primary_radio(struct wiphy *primary_wiphy);
bool qca_multi_link_add_fastlane_radio(struct wiphy *fl_wiphy); bool qca_multi_link_remove_radio(struct wiphy *wiphy);
bool qca_multi_link_add_radio(struct wiphy *wiphy);
bool qca_multi_link_remove_fastlane_radio(struct wiphy *fl_wiphy); bool qca_multi_link_remove_fastlane_radio(struct wiphy *fl_wiphy);
bool qca_multi_link_add_no_backhaul_radio(struct wiphy *no_bl_wiphy); bool qca_multi_link_add_fastlane_radio(struct wiphy *fl_wiphy);
bool qca_multi_link_remove_no_backhaul_radio(struct wiphy *no_bl_wiphy); bool qca_multi_link_remove_no_backhaul_radio(struct wiphy *no_bl_wiphy);
bool qca_multi_link_add_no_backhaul_radio(struct wiphy *no_bl_wiphy);
bool qca_multi_link_remove_station_vap(struct wiphy *wiphy);
bool qca_multi_link_add_station_vap(struct wiphy *wiphy,
struct net_device *sta_dev);
bool qca_multi_link_ap_rx(struct net_device *net_dev, qdf_nbuf_t nbuf); bool qca_multi_link_ap_rx(struct net_device *net_dev, qdf_nbuf_t nbuf);
bool qca_multi_link_sta_rx(struct net_device *net_dev, qdf_nbuf_t nbuf); bool qca_multi_link_sta_rx(struct net_device *net_dev, qdf_nbuf_t nbuf);
bool qca_multi_link_sta_tx(struct net_device *net_dev, qdf_nbuf_t nbuf); bool qca_multi_link_sta_tx(struct net_device *net_dev, qdf_nbuf_t nbuf);

View File

@@ -19,66 +19,69 @@
static bool is_initialized; static bool is_initialized;
qca_multi_link_parameters_t qca_multi_link_cfg; qca_multi_link_parameters_t qca_multi_link_cfg;
static inline bool is_fast_lane_radio(struct wiphy *fl_wiphy) static inline qca_multi_link_radio_node_t *
qca_multi_link_find_radio_node(struct wiphy *wiphy)
{ {
qdf_list_node_t *node = NULL, *next_node = NULL; qdf_list_node_t *node = NULL, *next_node = NULL;
if (!fl_wiphy) { if (!wiphy) {
return false; QDF_TRACE(QDF_MODULE_ID_RPTR, QDF_TRACE_LEVEL_WARN,
FL(" Radio wiphy pointer is NULL\n"));
return NULL;
} }
if (qdf_list_empty(&qca_multi_link_cfg.fast_lane_list)) { if (qdf_list_empty(&qca_multi_link_cfg.radio_list)) {
return false; QDF_TRACE(QDF_MODULE_ID_RPTR, QDF_TRACE_LEVEL_DEBUG,
FL(" Radio list is empty\n"));
return NULL;
} }
qdf_list_peek_front(&qca_multi_link_cfg.fast_lane_list, qdf_list_peek_front(&qca_multi_link_cfg.radio_list,
(qdf_list_node_t **)&next_node); (qdf_list_node_t **)&next_node);
while (next_node) { while (next_node) {
struct qca_multi_link_list_node *fast_lane_node qca_multi_link_radio_node_t *radio_node
= (struct qca_multi_link_list_node *)next_node; = (qca_multi_link_radio_node_t *)next_node;
if (fast_lane_node->wiphy == fl_wiphy) { if (radio_node->wiphy == wiphy) {
return true; return radio_node;
} else { } else {
node = next_node; node = next_node;
next_node = NULL; next_node = NULL;
if ((qdf_list_peek_next(&qca_multi_link_cfg.fast_lane_list, node, &next_node)) if ((qdf_list_peek_next(&qca_multi_link_cfg.radio_list,
node, (qdf_list_node_t **)&next_node))
!= QDF_STATUS_SUCCESS) { != QDF_STATUS_SUCCESS) {
return NULL;
}
}
}
return NULL;
}
static inline bool is_fast_lane_radio(struct wiphy *fl_wiphy)
{
qca_multi_link_radio_node_t *radio_node = NULL;
qdf_spin_lock(&qca_multi_link_cfg.radio_lock);
radio_node = qca_multi_link_find_radio_node(fl_wiphy);
qdf_spin_unlock(&qca_multi_link_cfg.radio_lock);
if (!radio_node) {
return false; return false;
} }
}
} return radio_node->is_fast_lane;
return false;
} }
static inline bool is_no_backhaul_radio(struct wiphy *no_bl_wiphy) static inline bool is_no_backhaul_radio(struct wiphy *no_bl_wiphy)
{ {
qdf_list_node_t *node = NULL, *next_node = NULL; qca_multi_link_radio_node_t *radio_node = NULL;
if (!no_bl_wiphy) { qdf_spin_lock(&qca_multi_link_cfg.radio_lock);
radio_node = qca_multi_link_find_radio_node(no_bl_wiphy);
qdf_spin_unlock(&qca_multi_link_cfg.radio_lock);
if (!radio_node) {
return false; return false;
} }
if (qdf_list_empty(&qca_multi_link_cfg.no_backhaul_list)) { return radio_node->no_backhaul;
return false;
}
qdf_list_peek_front(&qca_multi_link_cfg.no_backhaul_list,
(qdf_list_node_t **)&next_node);
while (next_node) {
struct qca_multi_link_list_node *no_bl_node
= (struct qca_multi_link_list_node *)next_node;
if (no_bl_node->wiphy == no_bl_wiphy) {
return true;
} else {
node = next_node;
next_node = NULL;
if ((qdf_list_peek_next(&qca_multi_link_cfg.no_backhaul_list, node, &next_node))
!= QDF_STATUS_SUCCESS) {
return false;
}
}
}
return false;
} }
static inline bool is_other_fast_lane_radio_primary(struct wiphy *fl_wiphy) static inline bool is_other_fast_lane_radio_primary(struct wiphy *fl_wiphy)
@@ -89,20 +92,24 @@ static inline bool is_other_fast_lane_radio_primary(struct wiphy *fl_wiphy)
return false; return false;
} }
if (qdf_list_empty(&qca_multi_link_cfg.fast_lane_list)) { if (qdf_list_empty(&qca_multi_link_cfg.radio_list)) {
return false; return false;
} }
qdf_list_peek_front(&qca_multi_link_cfg.fast_lane_list, qdf_spin_lock(&qca_multi_link_cfg.radio_lock);
qdf_list_peek_front(&qca_multi_link_cfg.radio_list,
(qdf_list_node_t **)&next_node); (qdf_list_node_t **)&next_node);
while (next_node) { while (next_node) {
struct qca_multi_link_list_node *fast_lane_node qca_multi_link_radio_node_t *radio_node
= (struct qca_multi_link_list_node *)next_node; = (qca_multi_link_radio_node_t *)next_node;
if ((fast_lane_node->wiphy != fl_wiphy) if ((radio_node->wiphy != fl_wiphy) &&
&& (fast_lane_node->wiphy == qca_multi_link_cfg.primary_wiphy)) { (radio_node->is_fast_lane) &&
(radio_node->wiphy == qca_multi_link_cfg.primary_wiphy)) {
qdf_spin_unlock(&qca_multi_link_cfg.radio_lock);
return true; return true;
} }
} }
qdf_spin_unlock(&qca_multi_link_cfg.radio_lock);
return false; return false;
} }
@@ -202,6 +209,26 @@ static inline bool qca_multi_link_drop_always_primary(bool is_primary, qdf_nbuf_
return false; return false;
} }
/**
* qca_multi_link_get_station_vap() - get the radio station vap pointer for a radio
* @primary_wiphy: wiphy pointer of radio device
*
* Return: station vap netdevice pointer
*/
static struct net_device *qca_multi_link_get_station_vap(struct wiphy *wiphy)
{
qca_multi_link_radio_node_t *radio_node = NULL;
qdf_spin_lock(&qca_multi_link_cfg.radio_lock);
radio_node = qca_multi_link_find_radio_node(wiphy);
qdf_spin_unlock(&qca_multi_link_cfg.radio_lock);
if (!radio_node || !radio_node->sta_dev) {
return NULL;
}
return radio_node->sta_dev;
}
/** /**
* qca_multi_link_deinit_module() - De-initialize the repeater base structute * qca_multi_link_deinit_module() - De-initialize the repeater base structute
* Return: void * Return: void
@@ -214,9 +241,9 @@ void qca_multi_link_deinit_module(void)
qca_multi_link_cfg.total_stavaps_up = 0; qca_multi_link_cfg.total_stavaps_up = 0;
qca_multi_link_cfg.loop_detected = 0; qca_multi_link_cfg.loop_detected = 0;
qca_multi_link_cfg.primary_wiphy = NULL; qca_multi_link_cfg.primary_wiphy = NULL;
qdf_list_destroy(&qca_multi_link_cfg.fast_lane_list); qdf_list_destroy(&qca_multi_link_cfg.radio_list);
qdf_list_destroy(&qca_multi_link_cfg.no_backhaul_list);
is_initialized = false; is_initialized = false;
qdf_spinlock_destroy(&qca_multi_link_cfg.radio_lock);
QDF_TRACE(QDF_MODULE_ID_RPTR, QDF_TRACE_LEVEL_INFO, QDF_TRACE(QDF_MODULE_ID_RPTR, QDF_TRACE_LEVEL_INFO,
FL("\n******QCA RPtr De-Init Done***********\n")); FL("\n******QCA RPtr De-Init Done***********\n"));
@@ -238,9 +265,10 @@ void qca_multi_link_init_module(void)
qca_multi_link_cfg.total_stavaps_up = 0; qca_multi_link_cfg.total_stavaps_up = 0;
qca_multi_link_cfg.loop_detected = 0; qca_multi_link_cfg.loop_detected = 0;
qca_multi_link_cfg.primary_wiphy = NULL; qca_multi_link_cfg.primary_wiphy = NULL;
qdf_list_create(&qca_multi_link_cfg.fast_lane_list, QCA_MULTI_LINK_FAST_LANE_LIST_SIZE); qdf_list_create(&qca_multi_link_cfg.radio_list, QCA_MULTI_LINK_RADIO_LIST_SIZE);
qdf_list_create(&qca_multi_link_cfg.no_backhaul_list, QCA_MULTI_LINK_NO_BACKHAUL_LIST_SIZE); qdf_spinlock_create(&qca_multi_link_cfg.radio_lock);
memset(&qca_multi_link_cfg.qca_ml_stats, 0x0, sizeof(qca_multi_link_radio_node_t));
QDF_TRACE(QDF_MODULE_ID_RPTR, QDF_TRACE_LEVEL_INFO, QDF_TRACE(QDF_MODULE_ID_RPTR, QDF_TRACE_LEVEL_INFO,
FL("\n******QCA Repeater Initialization Done***********\n")); FL("\n******QCA Repeater Initialization Done***********\n"));
} }
@@ -299,7 +327,8 @@ qdf_export_symbol(qca_multi_link_append_num_sta);
bool qca_multi_link_is_dbdc_processing_reqd(struct net_device *net_dev) bool qca_multi_link_is_dbdc_processing_reqd(struct net_device *net_dev)
{ {
if (qca_multi_link_cfg.total_stavaps_up > 2) if (qca_multi_link_cfg.total_stavaps_up > 2)
return (qca_multi_link_cfg.loop_detected && qca_multi_link_cfg.rptr_processing_enable); return (qca_multi_link_cfg.loop_detected &&
qca_multi_link_cfg.rptr_processing_enable);
else else
return false; return false;
} }
@@ -382,11 +411,89 @@ void qca_multi_link_set_primary_radio(struct wiphy *primary_wiphy)
} }
qca_multi_link_cfg.primary_wiphy = primary_wiphy; qca_multi_link_cfg.primary_wiphy = primary_wiphy;
QDF_TRACE(QDF_MODULE_ID_RPTR, QDF_TRACE_LEVEL_INFO, QDF_TRACE(QDF_MODULE_ID_RPTR, QDF_TRACE_LEVEL_INFO,
FL("\nSetting primary radio for wiphy%p\n"), primary_wiphy); FL("\n******Setting primary radio for wiphy****%p\n"), primary_wiphy);
} }
qdf_export_symbol(qca_multi_link_set_primary_radio); qdf_export_symbol(qca_multi_link_set_primary_radio);
/**
* qca_multi_link_remove_radio() - remove the radio pointer from repeater list
* @primary_wiphy: wiphy pointer of radio device
*
* Return: false: addition not successful
* true: addition is successful
*/
bool qca_multi_link_remove_radio(struct wiphy *wiphy)
{
qca_multi_link_radio_node_t *radio_node = NULL;
qdf_spin_lock(&qca_multi_link_cfg.radio_lock);
radio_node = qca_multi_link_find_radio_node(wiphy);
if (!radio_node) {
qdf_spin_unlock(&qca_multi_link_cfg.radio_lock);
return false;
}
qdf_list_remove_node(&qca_multi_link_cfg.radio_list, &radio_node->node);
qdf_spin_unlock(&qca_multi_link_cfg.radio_lock);
qdf_mem_free(radio_node);
return true;
}
qdf_export_symbol(qca_multi_link_remove_radio);
/**
* qca_multi_link_add_radio() - add the radio pointer to repeater list
* @primary_wiphy: wiphy pointer of radio device
*
* Return: false: addition not successful
* true: addition is successful
*/
bool qca_multi_link_add_radio(struct wiphy *wiphy)
{
qca_multi_link_radio_node_t *radio_node = NULL;
if (!wiphy) {
QDF_TRACE(QDF_MODULE_ID_RPTR, QDF_TRACE_LEVEL_WARN,
FL(" Radio could not be set - wiphy is NULL\n"));
return false;
}
/*
* Check if Radio is already present in reppeater list.
*/
qdf_spin_lock(&qca_multi_link_cfg.radio_lock);
radio_node = qca_multi_link_find_radio_node(wiphy);
qdf_spin_unlock(&qca_multi_link_cfg.radio_lock);
if (radio_node) {
QDF_TRACE(QDF_MODULE_ID_RPTR, QDF_TRACE_LEVEL_WARN,
FL(" Radio node already present\n"));
return false;
}
radio_node = qdf_mem_malloc(sizeof(qca_multi_link_radio_node_t));
if (!radio_node) {
QDF_TRACE(QDF_MODULE_ID_RPTR, QDF_TRACE_LEVEL_DEBUG,
FL("Could not allocate node for wiphy%p\n"), wiphy);
return false;
}
qdf_spin_lock(&qca_multi_link_cfg.radio_lock);
radio_node->wiphy = wiphy;
if (qdf_list_insert_front(&qca_multi_link_cfg.radio_list, &radio_node->node)
== QDF_STATUS_SUCCESS) {
qdf_spin_unlock(&qca_multi_link_cfg.radio_lock);
QDF_TRACE(QDF_MODULE_ID_RPTR, QDF_TRACE_LEVEL_DEBUG,
FL("Adding radio node for wiphy%p\n"), wiphy);
return true;
}
qdf_spin_unlock(&qca_multi_link_cfg.radio_lock);
qdf_mem_free(radio_node);
return false;
}
qdf_export_symbol(qca_multi_link_add_radio);
/** /**
* qca_multi_link_add_fastlane_radio() - add the fast lane radio pointer to list * qca_multi_link_add_fastlane_radio() - add the fast lane radio pointer to list
* @primary_wiphy: wiphy pointer of fast-lane radio device * @primary_wiphy: wiphy pointer of fast-lane radio device
@@ -396,28 +503,19 @@ qdf_export_symbol(qca_multi_link_set_primary_radio);
*/ */
bool qca_multi_link_add_fastlane_radio(struct wiphy *fl_wiphy) bool qca_multi_link_add_fastlane_radio(struct wiphy *fl_wiphy)
{ {
struct qca_multi_link_list_node *fast_lane_node; qca_multi_link_radio_node_t *radio_node = NULL;
if (!fl_wiphy) { qdf_spin_lock(&qca_multi_link_cfg.radio_lock);
QDF_TRACE(QDF_MODULE_ID_RPTR, QDF_TRACE_LEVEL_WARN, radio_node = qca_multi_link_find_radio_node(fl_wiphy);
FL(" Fast lane radio could not be set - wiphy is NULL\n")); if (!radio_node) {
qdf_spin_unlock(&qca_multi_link_cfg.radio_lock);
return false; return false;
} }
fast_lane_node = qdf_mem_malloc(sizeof(struct qca_multi_link_list_node)); radio_node->is_fast_lane = true;
if (!fast_lane_node) { qdf_spin_unlock(&qca_multi_link_cfg.radio_lock);
QDF_TRACE(QDF_MODULE_ID_RPTR, QDF_TRACE_LEVEL_DEBUG,
FL("Could not allocate fast-lane node for wiphy%p\n"), fl_wiphy);
return false;
}
fast_lane_node->wiphy = fl_wiphy;
if (qdf_list_insert_front(&qca_multi_link_cfg.fast_lane_list, &fast_lane_node->node)
== QDF_STATUS_SUCCESS) {
return true; return true;
} }
return false;
}
qdf_export_symbol(qca_multi_link_add_fastlane_radio); qdf_export_symbol(qca_multi_link_add_fastlane_radio);
@@ -430,33 +528,18 @@ qdf_export_symbol(qca_multi_link_add_fastlane_radio);
*/ */
bool qca_multi_link_remove_fastlane_radio(struct wiphy *fl_wiphy) bool qca_multi_link_remove_fastlane_radio(struct wiphy *fl_wiphy)
{ {
qdf_list_node_t *node = NULL, *next_node = NULL; qca_multi_link_radio_node_t *radio_node = NULL;
if (!fl_wiphy) { qdf_spin_lock(&qca_multi_link_cfg.radio_lock);
QDF_TRACE(QDF_MODULE_ID_RPTR, QDF_TRACE_LEVEL_WARN, radio_node = qca_multi_link_find_radio_node(fl_wiphy);
FL(" Fast lane radio could not be removed - wiphy is NULL\n")); if (!radio_node) {
qdf_spin_unlock(&qca_multi_link_cfg.radio_lock);
return false; return false;
} }
qdf_list_peek_front(&qca_multi_link_cfg.fast_lane_list, radio_node->is_fast_lane = false;
(qdf_list_node_t **)&next_node); qdf_spin_unlock(&qca_multi_link_cfg.radio_lock);
while (next_node) {
struct qca_multi_link_list_node *fast_lane_node
= (struct qca_multi_link_list_node *)next_node;
if (fast_lane_node->wiphy == fl_wiphy) {
qdf_list_remove_node(&qca_multi_link_cfg.fast_lane_list, next_node);
qdf_mem_free(fast_lane_node);
return true; return true;
} else {
node = next_node;
next_node = NULL;
if ((qdf_list_peek_next(&qca_multi_link_cfg.fast_lane_list, node,
(qdf_list_node_t **)&next_node)) != QDF_STATUS_SUCCESS) {
return false;
}
}
}
return false;
} }
qdf_export_symbol(qca_multi_link_remove_fastlane_radio); qdf_export_symbol(qca_multi_link_remove_fastlane_radio);
@@ -470,28 +553,19 @@ qdf_export_symbol(qca_multi_link_remove_fastlane_radio);
*/ */
bool qca_multi_link_add_no_backhaul_radio(struct wiphy *no_bl_wiphy) bool qca_multi_link_add_no_backhaul_radio(struct wiphy *no_bl_wiphy)
{ {
struct qca_multi_link_list_node *no_bl_node; qca_multi_link_radio_node_t *radio_node = NULL;
if (!no_bl_wiphy) { qdf_spin_lock(&qca_multi_link_cfg.radio_lock);
QDF_TRACE(QDF_MODULE_ID_RPTR, QDF_TRACE_LEVEL_WARN, radio_node = qca_multi_link_find_radio_node(no_bl_wiphy);
FL(" No backhaul radio could not be set - wiphy is NULL\n")); if (!radio_node) {
qdf_spin_unlock(&qca_multi_link_cfg.radio_lock);
return false; return false;
} }
no_bl_node = qdf_mem_malloc(sizeof(struct qca_multi_link_list_node)); radio_node->no_backhaul = true;
if (!no_bl_node) { qdf_spin_unlock(&qca_multi_link_cfg.radio_lock);
QDF_TRACE(QDF_MODULE_ID_RPTR, QDF_TRACE_LEVEL_DEBUG,
FL("Could not allocate back-haul node for wiphy%p\n"), no_bl_node);
return false;
}
no_bl_node->wiphy = no_bl_wiphy;
if (qdf_list_insert_front(&qca_multi_link_cfg.no_backhaul_list, &no_bl_node->node)
== QDF_STATUS_SUCCESS) {
return true; return true;
} }
return false;
}
qdf_export_symbol(qca_multi_link_add_no_backhaul_radio); qdf_export_symbol(qca_multi_link_add_no_backhaul_radio);
@@ -504,37 +578,81 @@ qdf_export_symbol(qca_multi_link_add_no_backhaul_radio);
*/ */
bool qca_multi_link_remove_no_backhaul_radio(struct wiphy *no_bl_wiphy) bool qca_multi_link_remove_no_backhaul_radio(struct wiphy *no_bl_wiphy)
{ {
qdf_list_node_t *node = NULL, *next_node = NULL; qca_multi_link_radio_node_t *radio_node = NULL;
if (!no_bl_wiphy) { qdf_spin_lock(&qca_multi_link_cfg.radio_lock);
QDF_TRACE(QDF_MODULE_ID_RPTR, QDF_TRACE_LEVEL_WARN, radio_node = qca_multi_link_find_radio_node(no_bl_wiphy);
FL(" No backhaul radio could not be removed - wiphy is NULL\n")); if (!radio_node) {
qdf_spin_unlock(&qca_multi_link_cfg.radio_lock);
return false; return false;
} }
qdf_list_peek_front(&qca_multi_link_cfg.no_backhaul_list, radio_node->no_backhaul = false;
(qdf_list_node_t **)&next_node); qdf_spin_unlock(&qca_multi_link_cfg.radio_lock);
while (next_node) {
struct qca_multi_link_list_node *no_bl_node
= (struct qca_multi_link_list_node *)next_node;
if (no_bl_node->wiphy == no_bl_wiphy) {
qdf_list_remove_node(&qca_multi_link_cfg.no_backhaul_list, next_node);
qdf_mem_free(no_bl_node);
return true; return true;
} else {
node = next_node;
next_node = NULL;
if ((qdf_list_peek_next(&qca_multi_link_cfg.no_backhaul_list, node, &next_node))
!= QDF_STATUS_SUCCESS) {
return false;
}
}
}
return false;
} }
qdf_export_symbol(qca_multi_link_remove_no_backhaul_radio); qdf_export_symbol(qca_multi_link_remove_no_backhaul_radio);
/**
* qca_multi_link_remove_station_vap() - remove the radio station vap pointer for a radio
* @primary_wiphy: wiphy pointer of radio device
*
* Return: false: addition not successful
* true: addition is successful
*/
bool qca_multi_link_remove_station_vap(struct wiphy *wiphy)
{
qca_multi_link_radio_node_t *radio_node = NULL;
qdf_spin_lock(&qca_multi_link_cfg.radio_lock);
radio_node = qca_multi_link_find_radio_node(wiphy);
if (!radio_node) {
qdf_spin_unlock(&qca_multi_link_cfg.radio_lock);
return false;
}
radio_node->sta_dev = NULL;
qdf_spin_unlock(&qca_multi_link_cfg.radio_lock);
return true;
}
qdf_export_symbol(qca_multi_link_remove_station_vap);
/**
* qca_multi_link_add_station_vap() - add the station vap pointer for a radio
* @primary_wiphy: wiphy pointer of radio device
*
* Return: false: addition not successful
* true: addition is successful
*/
bool qca_multi_link_add_station_vap(struct wiphy *wiphy, struct net_device *sta_dev)
{
qca_multi_link_radio_node_t *radio_node = NULL;
qdf_spin_lock(&qca_multi_link_cfg.radio_lock);
radio_node = qca_multi_link_find_radio_node(wiphy);
if (!radio_node) {
qdf_spin_unlock(&qca_multi_link_cfg.radio_lock);
return false;
}
if (radio_node->sta_dev) {
QDF_TRACE(QDF_MODULE_ID_RPTR, QDF_TRACE_LEVEL_WARN,
FL("STA Device already mapped for wiphy%p\n"), wiphy);
qdf_spin_unlock(&qca_multi_link_cfg.radio_lock);
return false;
}
radio_node->sta_dev = sta_dev;
qdf_spin_unlock(&qca_multi_link_cfg.radio_lock);
QDF_TRACE(QDF_MODULE_ID_RPTR, QDF_TRACE_LEVEL_DEBUG,
FL("STA Device mapped for wiphy%p\n"), wiphy);
return true;
}
qdf_export_symbol(qca_multi_link_add_station_vap);
/** /**
* qca_multi_link_secondary_ap_rx() - Processing for frames recieved on Secondary AP VAP * qca_multi_link_secondary_ap_rx() - Processing for frames recieved on Secondary AP VAP
* @net_device: net device handle * @net_device: net device handle
@@ -599,13 +717,16 @@ static qca_multi_link_status_t qca_multi_link_secondary_ap_rx(struct net_device
/* /*
* Find the station vap corresponding to the AP vap. * Find the station vap corresponding to the AP vap.
*/ */
sta_dev = qca_multi_link_tbl_find_sta_or_ap(ap_dev, 1); sta_dev = qca_multi_link_get_station_vap(ap_wiphy);
if (!sta_dev) { if (!sta_dev) {
QDF_TRACE(QDF_MODULE_ID_RPTR, QDF_TRACE_LEVEL_DEBUG, QDF_TRACE(QDF_MODULE_ID_RPTR, QDF_TRACE_LEVEL_DEBUG,
FL("Null STA device found %pM - Give to bridge\n"), eh->ether_shost); FL("Null STA device found %pM - Give to bridge\n"), eh->ether_shost);
qca_multi_link_cfg.qca_ml_stats.ap_rx_sec_sta_null++;
return QCA_MULTI_LINK_PKT_DROP; return QCA_MULTI_LINK_PKT_DROP;
} }
qca_multi_link_tbl_add_or_refresh_entry(ap_dev, eh->ether_shost,
QCA_MULTI_LINK_ENTRY_USER_ADDED);
dev_hold(sta_dev); dev_hold(sta_dev);
QDF_TRACE(QDF_MODULE_ID_RPTR, QDF_TRACE_LEVEL_DEBUG, QDF_TRACE(QDF_MODULE_ID_RPTR, QDF_TRACE_LEVEL_DEBUG,
FL("shost %pM dhost %pM \n"), eh->ether_shost, eh->ether_dhost); FL("shost %pM dhost %pM \n"), eh->ether_shost, eh->ether_dhost);
@@ -728,6 +849,7 @@ static qca_multi_link_status_t qca_multi_link_secondary_sta_rx(struct net_device
* Always drop mcast packets on secondary radio when loop has been detected. * Always drop mcast packets on secondary radio when loop has been detected.
*/ */
if (qca_multi_link_cfg.loop_detected) { if (qca_multi_link_cfg.loop_detected) {
qca_multi_link_cfg.qca_ml_stats.sta_rx_sec_sta_mcast_drop++;
return QCA_MULTI_LINK_PKT_DROP; return QCA_MULTI_LINK_PKT_DROP;
} }
@@ -746,6 +868,7 @@ static qca_multi_link_status_t qca_multi_link_secondary_sta_rx(struct net_device
*/ */
return QCA_MULTI_LINK_PKT_ALLOW; return QCA_MULTI_LINK_PKT_ALLOW;
} else { } else {
qca_multi_link_cfg.qca_ml_stats.sta_rx_sec_sta_mcast_no_fdb++;
return QCA_MULTI_LINK_PKT_DROP; return QCA_MULTI_LINK_PKT_DROP;
} }
} }
@@ -769,10 +892,12 @@ static qca_multi_link_status_t qca_multi_link_secondary_sta_rx(struct net_device
QDF_TRACE(QDF_MODULE_ID_RPTR, QDF_TRACE_LEVEL_INFO, FL("\n****Wifi Rptr Loop Detected****\n")); QDF_TRACE(QDF_MODULE_ID_RPTR, QDF_TRACE_LEVEL_INFO, FL("\n****Wifi Rptr Loop Detected****\n"));
} }
} }
qca_multi_link_cfg.qca_ml_stats.sta_rx_sec_sta_mcast_dup_pkts++;
return QCA_MULTI_LINK_PKT_DROP; return QCA_MULTI_LINK_PKT_DROP;
} }
if (qca_multi_link_drop_secondary_mcast(nbuf)) { if (qca_multi_link_drop_secondary_mcast(nbuf)) {
qca_multi_link_cfg.qca_ml_stats.sta_rx_sec_sta_mcast_drop_sec++;
return QCA_MULTI_LINK_PKT_DROP; return QCA_MULTI_LINK_PKT_DROP;
} }
@@ -787,6 +912,7 @@ static qca_multi_link_status_t qca_multi_link_secondary_sta_rx(struct net_device
return QCA_MULTI_LINK_PKT_ALLOW; return QCA_MULTI_LINK_PKT_ALLOW;
} }
qca_multi_link_cfg.qca_ml_stats.sta_rx_sec_sta_mcast_drop++;
return QCA_MULTI_LINK_PKT_DROP; return QCA_MULTI_LINK_PKT_DROP;
} }
@@ -807,6 +933,7 @@ static qca_multi_link_status_t qca_multi_link_secondary_sta_rx(struct net_device
* on secondary stations. * on secondary stations.
*/ */
if (!qca_ml_entry.qal_fdb_ieee80211_ptr) { if (!qca_ml_entry.qal_fdb_ieee80211_ptr) {
qca_multi_link_cfg.qca_ml_stats.sta_rx_sec_sta_ucast_src_eth++;
return QCA_MULTI_LINK_PKT_DROP; return QCA_MULTI_LINK_PKT_DROP;
} }
@@ -828,6 +955,7 @@ static qca_multi_link_status_t qca_multi_link_secondary_sta_rx(struct net_device
return QCA_MULTI_LINK_PKT_CONSUMED; return QCA_MULTI_LINK_PKT_CONSUMED;
} }
qca_multi_link_cfg.qca_ml_stats.sta_rx_sec_sta_ucast_src_dif_band++;
return QCA_MULTI_LINK_PKT_DROP; return QCA_MULTI_LINK_PKT_DROP;
} else { } else {
@@ -843,7 +971,8 @@ static qca_multi_link_status_t qca_multi_link_secondary_sta_rx(struct net_device
ap_dev = qca_multi_link_tbl_find_sta_or_ap(sta_dev, 0); ap_dev = qca_multi_link_tbl_find_sta_or_ap(sta_dev, 0);
if (!ap_dev) { if (!ap_dev) {
QDF_TRACE(QDF_MODULE_ID_RPTR, QDF_TRACE_LEVEL_DEBUG, QDF_TRACE(QDF_MODULE_ID_RPTR, QDF_TRACE_LEVEL_DEBUG,
FL("Null AP device found %pM - Give to bridge\n"), eh->ether_shost); FL("Null AP device found %pM - Drop\n"), eh->ether_shost);
qca_multi_link_cfg.qca_ml_stats.sta_rx_sec_sta_ucast_no_ap++;
return QCA_MULTI_LINK_PKT_DROP; return QCA_MULTI_LINK_PKT_DROP;
} }
@@ -913,6 +1042,7 @@ static qca_multi_link_status_t qca_multi_link_primary_sta_rx(struct net_device *
*/ */
return QCA_MULTI_LINK_PKT_ALLOW; return QCA_MULTI_LINK_PKT_ALLOW;
} }
qca_multi_link_cfg.qca_ml_stats.sta_rx_pri_sta_mcast_no_fdb++;
return QCA_MULTI_LINK_PKT_DROP; return QCA_MULTI_LINK_PKT_DROP;
} }
@@ -931,13 +1061,15 @@ static qca_multi_link_status_t qca_multi_link_primary_sta_rx(struct net_device *
* Drop the loopback mcast packets from ethernet devices behind the repeater. * Drop the loopback mcast packets from ethernet devices behind the repeater.
*/ */
if (!qca_ml_entry.qal_fdb_ieee80211_ptr) { if (!qca_ml_entry.qal_fdb_ieee80211_ptr) {
qca_multi_link_cfg.qca_ml_stats.sta_rx_pri_sta_mcast_drop++;
return QCA_MULTI_LINK_PKT_DROP; return QCA_MULTI_LINK_PKT_DROP;
} }
if (qca_ml_entry.qal_fdb_ieee80211_ptr->wiphy != sta_wiphy) { if (qca_ml_entry.qal_fdb_ieee80211_ptr->wiphy != sta_wiphy) {
if (qca_ml_entry.qal_fdb_is_local &&
(qca_ml_entry.qal_fdb_ieee80211_ptr->iftype
== NL80211_IFTYPE_STATION)) {
if (!qca_multi_link_cfg.loop_detected) { if (!qca_multi_link_cfg.loop_detected) {
if (qca_ml_entry.qal_fdb_is_local
&& (qca_ml_entry.qal_fdb_ieee80211_ptr->iftype == NL80211_IFTYPE_STATION)) {
qca_multi_link_cfg.loop_detected = true; qca_multi_link_cfg.loop_detected = true;
QDF_TRACE(QDF_MODULE_ID_RPTR, QDF_TRACE_LEVEL_INFO, QDF_TRACE(QDF_MODULE_ID_RPTR, QDF_TRACE_LEVEL_INFO,
FL("\n****Wifi Rptr Loop Detected****\n")); FL("\n****Wifi Rptr Loop Detected****\n"));
@@ -954,6 +1086,7 @@ static qca_multi_link_status_t qca_multi_link_primary_sta_rx(struct net_device *
return QCA_MULTI_LINK_PKT_ALLOW; return QCA_MULTI_LINK_PKT_ALLOW;
} }
} }
qca_multi_link_cfg.qca_ml_stats.sta_rx_pri_sta_mcast_drop++;
return QCA_MULTI_LINK_PKT_DROP; return QCA_MULTI_LINK_PKT_DROP;
} }
@@ -966,6 +1099,7 @@ static qca_multi_link_status_t qca_multi_link_primary_sta_rx(struct net_device *
return QCA_MULTI_LINK_PKT_ALLOW; return QCA_MULTI_LINK_PKT_ALLOW;
} }
qca_multi_link_cfg.qca_ml_stats.sta_rx_pri_sta_mcast_drop++;
return QCA_MULTI_LINK_PKT_DROP; return QCA_MULTI_LINK_PKT_DROP;
} }
@@ -1052,6 +1186,7 @@ static qca_multi_link_status_t qca_multi_link_secondary_sta_tx(struct net_device
qdf_ether_header_t *eh = (qdf_ether_header_t *) qdf_nbuf_data(nbuf); qdf_ether_header_t *eh = (qdf_ether_header_t *) qdf_nbuf_data(nbuf);
if (qca_multi_link_drop_always_primary(false, nbuf)) { if (qca_multi_link_drop_always_primary(false, nbuf)) {
qca_multi_link_cfg.qca_ml_stats.sta_tx_sec_sta_alwys_prim++;
return QCA_MULTI_LINK_PKT_DROP; return QCA_MULTI_LINK_PKT_DROP;
} }
@@ -1075,6 +1210,7 @@ static qca_multi_link_status_t qca_multi_link_secondary_sta_tx(struct net_device
if (!is_mcast) { if (!is_mcast) {
return QCA_MULTI_LINK_PKT_ALLOW; return QCA_MULTI_LINK_PKT_ALLOW;
} }
qca_multi_link_cfg.qca_ml_stats.sta_tx_sec_sta_mcast_no_fdb++;
return QCA_MULTI_LINK_PKT_DROP; return QCA_MULTI_LINK_PKT_DROP;
} }
@@ -1083,6 +1219,7 @@ static qca_multi_link_status_t qca_multi_link_secondary_sta_tx(struct net_device
* ieee80211_ptr pointer will be NULL for ethernet devices. * ieee80211_ptr pointer will be NULL for ethernet devices.
* Packets from ethernet devices or bridge are allowed only on Primary radio. * Packets from ethernet devices or bridge are allowed only on Primary radio.
*/ */
qca_multi_link_cfg.qca_ml_stats.sta_tx_sec_sta_src_eth++;
return QCA_MULTI_LINK_PKT_DROP; return QCA_MULTI_LINK_PKT_DROP;
} }
@@ -1095,6 +1232,7 @@ static qca_multi_link_status_t qca_multi_link_secondary_sta_tx(struct net_device
} }
if (qca_multi_link_drop_secondary_mcast(nbuf)) { if (qca_multi_link_drop_secondary_mcast(nbuf)) {
qca_multi_link_cfg.qca_ml_stats.sta_tx_sec_sta_mcast_drop_sec++;
return QCA_MULTI_LINK_PKT_DROP; return QCA_MULTI_LINK_PKT_DROP;
} }
@@ -1105,6 +1243,7 @@ static qca_multi_link_status_t qca_multi_link_secondary_sta_tx(struct net_device
if (qca_ml_entry.qal_fdb_ieee80211_ptr->wiphy != sta_dev->ieee80211_ptr->wiphy) { if (qca_ml_entry.qal_fdb_ieee80211_ptr->wiphy != sta_dev->ieee80211_ptr->wiphy) {
QDF_TRACE(QDF_MODULE_ID_RPTR, QDF_TRACE_LEVEL_DEBUG, FL("STA TX: Diff Band Primary drop\ QDF_TRACE(QDF_MODULE_ID_RPTR, QDF_TRACE_LEVEL_DEBUG, FL("STA TX: Diff Band Primary drop\
shost %pM dhost %pM \n"), eh->ether_shost, eh->ether_dhost); shost %pM dhost %pM \n"), eh->ether_shost, eh->ether_dhost);
qca_multi_link_cfg.qca_ml_stats.sta_tx_sec_sta_drop_dif_band++;
return QCA_MULTI_LINK_PKT_DROP; return QCA_MULTI_LINK_PKT_DROP;
} }
@@ -1152,6 +1291,7 @@ static qca_multi_link_status_t qca_multi_link_primary_sta_tx(struct net_device *
* as they will be received from bridge only. * as they will be received from bridge only.
*/ */
if (qal_status != QDF_STATUS_SUCCESS) { if (qal_status != QDF_STATUS_SUCCESS) {
qca_multi_link_cfg.qca_ml_stats.sta_tx_pri_sta_drop_no_fdb++;
return QCA_MULTI_LINK_PKT_DROP; return QCA_MULTI_LINK_PKT_DROP;
} }
@@ -1186,6 +1326,7 @@ static qca_multi_link_status_t qca_multi_link_primary_sta_tx(struct net_device *
if (qca_ml_entry.qal_fdb_ieee80211_ptr->wiphy != sta_dev->ieee80211_ptr->wiphy) { if (qca_ml_entry.qal_fdb_ieee80211_ptr->wiphy != sta_dev->ieee80211_ptr->wiphy) {
QDF_TRACE(QDF_MODULE_ID_RPTR, QDF_TRACE_LEVEL_DEBUG, FL("STA TX: Diff Band Primary drop\ QDF_TRACE(QDF_MODULE_ID_RPTR, QDF_TRACE_LEVEL_DEBUG, FL("STA TX: Diff Band Primary drop\
shost %pM dhost %pM \n"), eh->ether_shost, eh->ether_dhost); shost %pM dhost %pM \n"), eh->ether_shost, eh->ether_dhost);
qca_multi_link_cfg.qca_ml_stats.sta_tx_pri_sta_drop_dif_band++;
return QCA_MULTI_LINK_PKT_DROP; return QCA_MULTI_LINK_PKT_DROP;
} }

View File

@@ -15,6 +15,7 @@
*/ */
#include "qca_multi_link_tbl.h" #include "qca_multi_link_tbl.h"
#include "qca_multi_link.h"
#include "qdf_module.h" #include "qdf_module.h"
#include "qdf_trace.h" #include "qdf_trace.h"
@@ -179,6 +180,10 @@ QDF_STATUS qca_multi_link_tbl_delete_entry(struct net_device *net_dev, uint8_t *
return QDF_STATUS_SUCCESS; return QDF_STATUS_SUCCESS;
} }
if (!qca_multi_link_is_dbdc_processing_reqd(net_dev)) {
return QDF_STATUS_SUCCESS;
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 24) #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 24)
fdb_port = br_port_get_rcu(net_dev); fdb_port = br_port_get_rcu(net_dev);
if (!fdb_port) { if (!fdb_port) {