blob: 97733e956bf7b3d4c99d3a15109bf668b8171c1f [file] [log] [blame]
/************************************************************************
* Copyright (C) 2010, Marvell Technology Group Ltd.
* All Rights Reserved.
*
* This is UNPUBLISHED PROPRIETARY SOURCE CODE of Marvell Technology Group;
* the contents of this file may not be disclosed to third parties, copied
* or duplicated in any form, in whole or in part, without the prior
* written permission of Marvell Technology Group.
*
*********************************************************************************
* Marvell GPL License Option
*
* If you received this File from Marvell, you may opt to use, redistribute and/or
* modify this File in accordance with the terms and conditions of the General
* Public License Version 2, June 1991 (the "GPL License"), a copy of which is
* available along with the File in the license.txt file or by writing to the Free
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
* on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
*
* THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
* WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
* DISCLAIMED. The GPL License provides additional details about this warranty
* disclaimer.
*
*********************************************************************************
* mv_cust_flow_map.c
*
* DESCRIPTION:
* Victor - initial version created. 12/Dec/2011
*
*******************************************************************************/
#include <mvCommon.h>
#include <linux/kernel.h>
#include <linux/version.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/if_vlan.h>
#include <net/ip.h>
#include <net/ipv6.h>
#include <mvOs.h>
#include <ctrlEnv/mvCtrlEnvLib.h>
#include "mv_cust_dev.h"
#include "mv_cust_netdev.h"
#include "mv_cust_flow_map.h"
#include "mv_cust_mng_if.h"
/******************************************************************************
* Global Data Definitions
******************************************************************************/
static mv_cust_vid_index_t gs_vid_index_table[MV_CUST_FLOW_DIR_NUM];
static mv_cust_pbits_map_t gs_pbits_map_table[MV_CUST_FLOW_DIR_NUM][MV_CUST_MAX_PBITS_MAP_TABLE_SIZE];
static mv_cust_dscp_pbits_t gs_dscp_map_table;
static uint32_t gs_mv_cust_trace_flag = 0;
/* Defined to support T-CONT state */
static bool gs_tcont_state[CPH_MAX_TCONT_NUM];
/******************************************************************************
* External Declarations
******************************************************************************/
/******************************************************************************
* Function Definitions
******************************************************************************/
/*******************************************************************************
**
** mv_cust_set_trace_flag
** ___________________________________________________________________________
**
** DESCRIPTION: The function sets mv_cust trace flag.
**
** INPUTS:
** enTrace - Enable or disable mv_cust trace.
**
** OUTPUTS:
** None.
**
** RETURNS:
** On success, the function returns (MV_CUST_OK). On error different types are
** returned according to the case.
**
*******************************************************************************/
int mv_cust_set_trace_flag(uint32_t enTrace)
{
gs_mv_cust_trace_flag = enTrace;
return MV_CUST_OK;
}
/*******************************************************************************
**
** mv_cust_valid_pbits_table_get
** ___________________________________________________________________________
**
** DESCRIPTION: The function gets available P-bits mapping table.
**
** INPUTS:
** None.
**
** OUTPUTS:
** None.
**
** RETURNS:
** Available P-bits mapping table index.
**
*******************************************************************************/
uint32_t mv_cust_valid_pbits_table_get(mv_cust_flow_dir_e dir)
{
uint32_t table_idx = 0;
/* Table index MV_CUST_MAX_PBITS_MAP_TABLE_SIZE is reserved for tagged default packets */
for (table_idx=0; table_idx<MV_CUST_MAX_PBITS_MAP_TABLE_SIZE-1; table_idx++) {
if (gs_pbits_map_table[dir][table_idx].in_use == 0)
return table_idx;
}
return MV_CUST_INVALID_PBITS_TABLE_INDEX;
}
/*******************************************************************************
**
** mv_cust_pbits_table_status_get
** ___________________________________________________________________________
**
** DESCRIPTION: The function gets P-bits mapping table status.
**
** INPUTS:
** pbits_map - P-bits mapping table.
**
** OUTPUTS:
** None.
**
** RETURNS:
** 0:No P-bits mapping rule exist in current table, 1: still exists P-bits mapping rule.
**
*******************************************************************************/
uint32_t mv_cust_pbits_table_status_get(mv_cust_pbits_map_t *pbits_map)
{
uint32_t pbits_idx = 0;
for (pbits_idx=0; pbits_idx<MV_CUST_PBITS_MAP_MAX_ENTRY_NUM; pbits_idx++) {
if (pbits_map->pkt_fwd[pbits_idx].in_use != 0)
return MV_CUST_OK;
}
return MV_CUST_FAIL;
}
/*******************************************************************************
**
** mv_cust_map_rule_set
** ___________________________________________________________________________
**
** DESCRIPTION: The function sets GPON flow mapping rules
**
** INPUTS:
** cust_flow - VLAN ID, 802.1p value, pkt_fwd information.
**
** OUTPUTS:
** None.
**
** RETURNS:
** On success, the function returns (MV_CUST_OK). On error different types are
** returned according to the case.
**
*******************************************************************************/
int mv_cust_map_rule_set(mv_cust_ioctl_flow_map_t *cust_flow)
{
uint8_t *pVidEntry = NULL;
mv_cust_pbits_map_t *pPbitsMap = NULL;
uint32_t pbitsIndex = 0;
uint32_t index = 0;
uint32_t vid = 0;
uint32_t pbits = 0;
uint32_t mod_vid = 0;
uint32_t mod_pbits = 0;
mv_cust_flow_dir_e dir = MV_CUST_FLOW_DIR_US;
mv_cust_pkt_frwd_t *pkt_fwd = NULL;
/* Get input information: VID, P-bits... */
if (cust_flow == NULL) {
MVCUST_ERR_PRINT(KERN_ERR "cust_flow is NULL \n\r");
return MV_CUST_FAIL;
}
vid = cust_flow->vid;
pbits = cust_flow->pbits;
mod_vid = cust_flow->mod_vid;
mod_pbits = cust_flow->mod_pbits;
pkt_fwd = &cust_flow->pkt_frwd;
dir = cust_flow->dir;
if (gs_mv_cust_trace_flag) {
MVCUST_TRACE_PRINT(KERN_INFO,
"==ENTER==%s: vid[%d], pbits[%d], mod_vid[%d], mod_pbits[%d], T-CONT[%d], SWF queue[%d], HWF queue[%d], GEM port[%d], dir[%d]\n\r",
__FUNCTION__, vid, pbits, mod_vid, mod_pbits,
((pkt_fwd!= NULL)? pkt_fwd->trg_port:0),
((pkt_fwd!= NULL)? pkt_fwd->trg_queue:0),
((pkt_fwd!= NULL)? pkt_fwd->trg_hwf_queue:0),
((pkt_fwd!= NULL)? pkt_fwd->gem_port:0),
cust_flow->dir);
}
/* Check VID */
if (vid > (MV_CUST_VID_INDEX_TABLE_MAX_SIZE - 1)) {
MVCUST_ERR_PRINT(KERN_ERR "vid[%d] exceeds maximum value[%d] \n\r", vid, (MV_CUST_VID_INDEX_TABLE_MAX_SIZE - 1));
return MV_CUST_FAIL;
}
/* Check P-bits */
if (pbits > MV_CUST_PBITS_NOT_CARE_VALUE) {
MVCUST_ERR_PRINT(KERN_ERR "P-bits[%d] exceeds maximum value[%d] \n\r", pbits, MV_CUST_PBITS_NOT_CARE_VALUE);
return MV_CUST_FAIL;
}
/* Check mod VID */
if (mod_vid > (MV_CUST_VID_INDEX_TABLE_MAX_SIZE - 1)) {
MVCUST_ERR_PRINT(KERN_ERR "mod_vid[%d] exceeds maximum value[%d] \n\r", mod_vid, (MV_CUST_VID_INDEX_TABLE_MAX_SIZE - 1));
return MV_CUST_FAIL;
}
/* Check mod P-bits */
if (mod_pbits > MV_CUST_PBITS_NOT_CARE_VALUE) {
MVCUST_ERR_PRINT(KERN_ERR "mod_pbits[%d] exceeds maximum value[%d] \n\r", mod_pbits, MV_CUST_PBITS_NOT_CARE_VALUE);
return MV_CUST_FAIL;
}
/* Check dir */
if (dir >= MV_CUST_FLOW_DIR_NUM) {
MVCUST_ERR_PRINT(KERN_ERR "dir[%d] exceeds maximum value[%d] \n\r", dir, MV_CUST_FLOW_DIR_NUM-1);
return MV_CUST_FAIL;
}
/* Check target port/queue/GEM port */
if (pkt_fwd->trg_port > MV_CUST_MAX_TRG_PORT_VALUE) {
MVCUST_ERR_PRINT(KERN_ERR "trg_port[%d] exceeds maximum value[%d] \n\r", pkt_fwd->trg_port, MV_CUST_MAX_TRG_PORT_VALUE);
return MV_CUST_FAIL;
}
if (pkt_fwd->trg_queue > MV_CUST_MAX_TRG_QUEUE_VALUE) {
MVCUST_ERR_PRINT(KERN_ERR "SWF trg_queue[%d] exceeds maximum value[%d] \n\r", pkt_fwd->trg_queue, MV_CUST_MAX_TRG_QUEUE_VALUE);
return MV_CUST_FAIL;
}
if (pkt_fwd->trg_hwf_queue > MV_CUST_MAX_TRG_QUEUE_VALUE) {
MVCUST_ERR_PRINT(KERN_ERR "HWF trg_queue[%d] exceeds maximum value[%d] \n\r", pkt_fwd->trg_queue, MV_CUST_MAX_TRG_QUEUE_VALUE);
return MV_CUST_FAIL;
}
if (pkt_fwd->gem_port > MV_CUST_MAX_GEM_PORT_VALUE) {
MVCUST_ERR_PRINT(KERN_ERR "trg_queue[%d] exceeds maximum value[%d] \n\r", pkt_fwd->gem_port, MV_CUST_MAX_GEM_PORT_VALUE);
return MV_CUST_FAIL;
}
/* Find VID index entry by VID */
pVidEntry = &gs_vid_index_table[dir].pbits_map_index[vid];
/* Get P-bits mapping table */
/* If this VID index entry does not point to any P-bits mapping table,
need to search for an available P-bits mapping table */
if (*pVidEntry >= MV_CUST_MAX_PBITS_MAP_TABLE_SIZE) {
/* Reserved for default tagged rule */
if (vid == MV_CUST_DEFAULT_SINGLE_TAG_RULE)
pbitsIndex = MV_CUST_MAX_PBITS_MAP_TABLE_SIZE - 1;
else
pbitsIndex = mv_cust_valid_pbits_table_get(dir);
if (pbitsIndex >= MV_CUST_MAX_PBITS_MAP_TABLE_SIZE) {
MVCUST_ERR_PRINT(KERN_ERR " %d P-bits mapping table has used out\n\r", MV_CUST_INVALID_PBITS_TABLE_INDEX);
return MV_CUST_FAIL;
}
}
/* In case that the VID index already points to a P-bits mapping table,
Need to replace the forwarding information of this P-bit mapping table */
else {
pbitsIndex = *pVidEntry;
}
pPbitsMap = &gs_pbits_map_table[dir][pbitsIndex];
/* If legal P-bits is configured */
if (pbits < MV_CUST_PBITS_NOT_CARE_VALUE) {
/* In case to enable packet forwarding */
if (pkt_fwd->in_use != 0) {
/* Save forwarding information */
pPbitsMap->pkt_fwd[pbits].trg_port = pkt_fwd->trg_port;
pPbitsMap->pkt_fwd[pbits].trg_queue = pkt_fwd->trg_queue;
pPbitsMap->pkt_fwd[pbits].trg_hwf_queue = pkt_fwd->trg_hwf_queue;
pPbitsMap->pkt_fwd[pbits].gem_port = pkt_fwd->gem_port;
/* Save mod_vid mod_pbits */
pPbitsMap->mod_vid[pbits] = mod_vid;
pPbitsMap->mod_pbits[pbits] = mod_pbits;
/* Enable in_use flag */
pPbitsMap->pkt_fwd[pbits].in_use = 1;
pPbitsMap->in_use = 1;
/* Save P-bit mapping table index in VID index table */
*pVidEntry = pbitsIndex;
}
/* In case to disable packet forwarding */
else {
/* Clear forwarding information */
pPbitsMap->pkt_fwd[pbits].trg_port = 0;
pPbitsMap->pkt_fwd[pbits].trg_queue = 0;
pPbitsMap->pkt_fwd[pbits].trg_hwf_queue = 0;
pPbitsMap->pkt_fwd[pbits].gem_port = 0;
/* Clear mod_vid mod_pbits */
pPbitsMap->mod_vid[pbits] = 0;
pPbitsMap->mod_pbits[pbits] = 0;
/* Disable in_use flag */
pPbitsMap->pkt_fwd[pbits].in_use = 0;
if (mv_cust_pbits_table_status_get(pPbitsMap) != MV_CUST_OK) {
pPbitsMap->in_use = 0;
*pVidEntry = MV_CUST_INVALID_PBITS_TABLE_INDEX;
}
else {
pPbitsMap->in_use = 1;
*pVidEntry = pbitsIndex;
}
}
}
/* If does not care for P-bits, each P-bits mapping entry should be set */
else if (pbits == MV_CUST_PBITS_NOT_CARE_VALUE) {
index = MV_CUST_PBITS_NOT_CARE_VALUE;
/* In case to enable packet forwarding */
if (pkt_fwd->in_use != 0) {
/* Save forwarding information */
pPbitsMap->pkt_fwd[index].trg_port = pkt_fwd->trg_port;
pPbitsMap->pkt_fwd[index].trg_queue = pkt_fwd->trg_queue;
pPbitsMap->pkt_fwd[pbits].trg_hwf_queue = pkt_fwd->trg_hwf_queue;
pPbitsMap->pkt_fwd[index].gem_port = pkt_fwd->gem_port;
pPbitsMap->pkt_fwd[index].in_use = 1;
/* Save mod_vid mod_pbits */
pPbitsMap->mod_vid[index] = mod_vid;
pPbitsMap->mod_pbits[index] = mod_pbits;
/* Enable in_use flag */
pPbitsMap->in_use = 1;
/* Save P-bit mapping table index in VID index table */
*pVidEntry = pbitsIndex;
}
/* In case to disable packet forwarding */
else {
/* Clear forwarding information */
pPbitsMap->pkt_fwd[index].trg_port = 0;
pPbitsMap->pkt_fwd[index].trg_queue = 0;
pPbitsMap->pkt_fwd[pbits].trg_hwf_queue = 0;
pPbitsMap->pkt_fwd[index].gem_port = 0;
pPbitsMap->pkt_fwd[index].in_use = 0;
/* clear mod_vid mod_pbits */
pPbitsMap->mod_vid[index] = 0;
pPbitsMap->mod_pbits[index] = 0;
/* Disable in_use flag */
if (mv_cust_pbits_table_status_get(pPbitsMap) != MV_CUST_OK) {
pPbitsMap->in_use = 0;
*pVidEntry = MV_CUST_INVALID_PBITS_TABLE_INDEX;
}
else {
pPbitsMap->in_use = 1;
*pVidEntry = pbitsIndex;
}
}
}
if (gs_mv_cust_trace_flag) {
MVCUST_TRACE_PRINT(KERN_INFO,
"==EXIT== %s:\n\r",__FUNCTION__);
}
return MV_CUST_OK;
}
/*******************************************************************************
**
** mv_cust_dscp_map_set
** ___________________________________________________________________________
**
** DESCRIPTION: The function sets GPON DSCP to P-bits mapping rules
**
** INPUTS:
** dscp_map - DSCP to P-bits mapping rules.
**
** OUTPUTS:
** None.
**
** RETURNS:
** On success, the function returns (MV_CUST_OK). On error different types are
** returned according to the case.
**
*******************************************************************************/
int mv_cust_dscp_map_set(mv_cust_dscp_pbits_t *dscp_map)
{
if (gs_mv_cust_trace_flag) {
MVCUST_TRACE_PRINT(KERN_INFO,
"==ENTER==%s: in_use[%d]\n\r", __FUNCTION__,
((dscp_map!= NULL)? dscp_map->in_use:0));
}
if (dscp_map == NULL) {
MVCUST_ERR_PRINT(KERN_ERR "Input dscp_map is NULL\n\r");
return MV_CUST_FAIL;
}
/* Case 1: to enable DSCP to P-bits mapping */
if (dscp_map->in_use != 0) {
memcpy(&gs_dscp_map_table.pbits[0], &dscp_map->pbits[0], sizeof(gs_dscp_map_table.pbits));
gs_dscp_map_table.in_use = 1;
}
/* Case 2: to disable DSCP to P-bits mapping */
else {
memset((uint8_t *)&gs_dscp_map_table, 0, sizeof(gs_dscp_map_table));
gs_dscp_map_table.in_use = 0;
}
if (gs_mv_cust_trace_flag) {
MVCUST_TRACE_PRINT(KERN_INFO,
"==EXIT== %s:\n\r",__FUNCTION__);
}
return MV_CUST_OK;
}
/*******************************************************************************
**
** mv_cust_map_rule_del
** ___________________________________________________________________________
**
** DESCRIPTION: The function deletes GPON flow mapping rules
**
** INPUTS:
** vid - VLAN ID.
** pbits - 802.1p value.
**
** OUTPUTS:
** None
**
** RETURNS:
** On success, the function returns (MV_CUST_OK). On error different types are
** returned according to the case.
**
*******************************************************************************/
int mv_cust_map_rule_del(uint16_t vid, uint8_t pbits, mv_cust_flow_dir_e dir)
{
uint8_t *pVidEntry = NULL;
mv_cust_pbits_map_t *pPbitsMap = NULL;
if (gs_mv_cust_trace_flag) {
MVCUST_TRACE_PRINT(KERN_INFO,
"==ENTER==: vid[%d],pbits[%d]\n\r", vid, pbits);
}
/* Check VID */
if (vid > (MV_CUST_VID_INDEX_TABLE_MAX_SIZE - 1)) {
MVCUST_ERR_PRINT(KERN_ERR "vid[%d] exceeds maximum value[%d] \n\r", vid, (MV_CUST_VID_INDEX_TABLE_MAX_SIZE - 1));
return MV_CUST_FAIL;
}
/* Check P-bits */
if (pbits > MV_CUST_PBITS_NOT_CARE_VALUE) {
MVCUST_ERR_PRINT(KERN_ERR "P-bits[%d] exceeds maximum value[%d] \n\r", pbits, MV_CUST_PBITS_NOT_CARE_VALUE);
return MV_CUST_FAIL;
}
/* Check dir */
if (dir >= MV_CUST_FLOW_DIR_NUM) {
MVCUST_ERR_PRINT(KERN_ERR "dir[%d] exceeds maximum value[%d] \n\r", dir, MV_CUST_FLOW_DIR_NUM-1);
return MV_CUST_FAIL;
}
/* Find VID index entry by VID */
pVidEntry = &gs_vid_index_table[dir].pbits_map_index[vid];
if (*pVidEntry >= MV_CUST_MAX_PBITS_MAP_TABLE_SIZE) {
MVCUST_TRACE_PRINT(KERN_INFO,"%s, pVidEntry[%d], does not need to delete \n\r",__FUNCTION__, *pVidEntry);
return MV_CUST_OK;
}
/* Find P-bits mapping table */
pPbitsMap = &gs_pbits_map_table[dir][*pVidEntry];
/* Delete P-bits mapping rule */
pPbitsMap->pkt_fwd[pbits].trg_port = 0;
pPbitsMap->pkt_fwd[pbits].trg_queue = 0;
pPbitsMap->pkt_fwd[pbits].gem_port = 0;
pPbitsMap->pkt_fwd[pbits].in_use = 0;
pPbitsMap->mod_vid[pbits] = 0;
pPbitsMap->mod_pbits[pbits] = 0;
/* Disable in_use flag */
if (mv_cust_pbits_table_status_get(pPbitsMap)!= MV_CUST_OK) {
pPbitsMap->in_use = 0;
*pVidEntry = MV_CUST_INVALID_PBITS_TABLE_INDEX;
}
if (gs_mv_cust_trace_flag) {
MVCUST_TRACE_PRINT(KERN_INFO,
"==EXIT==:\n\r");
}
return MV_CUST_OK;
}
/*******************************************************************************
**
** mv_cust_dscp_map_del
** ___________________________________________________________________________
**
** DESCRIPTION: The function deletes DSCP to P-bits mapping rules
**
** INPUTS:
** None.
**
** OUTPUTS:
** None.
**
** RETURNS:
** On success, the function returns (MV_CUST_OK). On error different types are
** returned according to the case.
**
*******************************************************************************/
int mv_cust_dscp_map_del(void)
{
if (gs_mv_cust_trace_flag) {
MVCUST_TRACE_PRINT(KERN_INFO,
"==ENTER==\n\r");
}
/* Clear DSCP to P-bits mapping */
else {
memset((uint8_t *)&gs_dscp_map_table, 0, sizeof(gs_dscp_map_table));
gs_dscp_map_table.in_use = 0;
}
if (gs_mv_cust_trace_flag) {
MVCUST_TRACE_PRINT(KERN_INFO,
"==EXIT==\n\r");
}
return MV_CUST_OK;
}
/*******************************************************************************
**
** mv_cust_map_rule_clear
** ___________________________________________________________________________
**
** DESCRIPTION: The function clears all GPON flow mapping rules
**
** INPUTS:
** None.
**
** OUTPUTS:
** None.
**
** RETURNS:
** On success, the function returns (MV_CUST_OK). On error different types are
** returned according to the case.
**
*******************************************************************************/
int mv_cust_map_rule_clear(void)
{
uint32_t pbits_index = 0;
if (gs_mv_cust_trace_flag) {
MVCUST_TRACE_PRINT(KERN_INFO,
"==ENTER==\n\r");
}
/* Clear VID index table */
memset((uint8_t *)&gs_vid_index_table, MV_CUST_INVALID_PBITS_TABLE_INDEX, sizeof(gs_vid_index_table));
/* Clear P-bits mapping tables */
for (pbits_index=0; pbits_index<MV_CUST_MAX_PBITS_MAP_TABLE_SIZE; pbits_index++) {
memset((uint8_t *)&gs_pbits_map_table[MV_CUST_FLOW_DIR_US][pbits_index], 0, sizeof(mv_cust_pbits_map_t));
gs_pbits_map_table[MV_CUST_FLOW_DIR_US][pbits_index].in_use = 0;
memset((uint8_t *)&gs_pbits_map_table[MV_CUST_FLOW_DIR_DS][pbits_index], 0, sizeof(mv_cust_pbits_map_t));
gs_pbits_map_table[MV_CUST_FLOW_DIR_DS][pbits_index].in_use = 0;
}
if (gs_mv_cust_trace_flag) {
MVCUST_TRACE_PRINT(KERN_INFO,
"==EXIT==\n\r");
}
return MV_CUST_OK;
}
/*******************************************************************************
**
** mv_cust_tag_map_rule_get
** ___________________________________________________________________________
**
** DESCRIPTION: The function gets GPON flow mapping rule for tagged frames.
**
** INPUTS:
** cust_flow - parsing vid, pbits, dir
**
** OUTPUTS:
** cust_flow - out packet forwarding information, including GEM port, T-CONT, queue.
** and packet modification for VID, P-bits
**
** RETURNS:
** On success, the function returns (MV_CUST_OK). On error different types are
** returned according to the case.
**
*******************************************************************************/
int mv_cust_tag_map_rule_get(mv_cust_ioctl_flow_map_t *cust_flow)
{
uint8_t *pVidEntry = NULL;
mv_cust_pbits_map_t *pPbitsMap = NULL;
mv_cust_pkt_frwd_t *pPktFrwd = NULL;
uint32_t vid = 0;
uint32_t pbits = 0;
mv_cust_flow_dir_e dir = MV_CUST_FLOW_DIR_US;
mv_cust_pkt_frwd_t *pkt_fwd = NULL;
uint32_t index = 0;
/* Get input parameters */
vid = cust_flow->vid;
pbits = cust_flow->pbits;
dir = cust_flow->dir;
pkt_fwd = &cust_flow->pkt_frwd;
if (gs_mv_cust_trace_flag) {
MVCUST_TRACE_PRINT(KERN_INFO,
"==ENTER==: vid[%d], pbits[%d], dir[%d]\n\r", vid, pbits, dir);
}
/* Check VID */
if (vid > (MV_CUST_VID_INDEX_TABLE_MAX_SIZE - 1)) {
MVCUST_ERR_PRINT(KERN_ERR "vid[%d] exceeds maximum value[%d] \n\r", vid, (MV_CUST_VID_INDEX_TABLE_MAX_SIZE - 1));
return MV_CUST_FAIL;
}
/* Check P-bits */
if (pbits > MV_CUST_PBITS_NOT_CARE_VALUE) {
MVCUST_ERR_PRINT(KERN_ERR "P-bits[%d] exceeds maximum value[%d] \n\r", pbits, MV_CUST_PBITS_NOT_CARE_VALUE);
return MV_CUST_FAIL;
}
/* Check dir */
if (dir >= MV_CUST_FLOW_DIR_NUM) {
MVCUST_ERR_PRINT(KERN_ERR "dir[%d] exceeds maximum value[%d] \n\r", dir, MV_CUST_FLOW_DIR_NUM-1);
return MV_CUST_FAIL;
}
/* Set default values */
cust_flow->mod_vid = MV_CUST_VID_NOT_CARE_VALUE;
cust_flow->mod_pbits = MV_CUST_PBITS_NOT_CARE_VALUE;
/* Find VID index entry by VID */
pVidEntry = &gs_vid_index_table[dir].pbits_map_index[vid];
if (*pVidEntry >= MV_CUST_MAX_PBITS_MAP_TABLE_SIZE) {
//MVCUST_ERR_PRINT(KERN_ERR "%s, pVidEntry[%d], No matched P-bits mapping table \n\r",__FUNCTION__, *pVidEntry);
pkt_fwd->in_use = 0;
if (gs_mv_cust_trace_flag) {
MVCUST_TRACE_PRINT(KERN_INFO,
"==EXIT==\n\r");
}
return MV_CUST_FAIL;
}
/* Find P-bits mapping table */
pPbitsMap = &gs_pbits_map_table[dir][*pVidEntry];
/* Get packet forwarding information */
index = pbits;
pPktFrwd = &pPbitsMap->pkt_fwd[index];
/* If specific flow mapping rule exists */
if (pPktFrwd->in_use != 0) {
pkt_fwd->trg_port = pPktFrwd->trg_port;
if (false == mv_cust_get_tcont_state(pPktFrwd->trg_port))
pkt_fwd->trg_queue = CPH_INVALID_TRGT_QUEUE;
else
pkt_fwd->trg_queue = pPktFrwd->trg_queue;
pkt_fwd->trg_hwf_queue = pPktFrwd->trg_hwf_queue;
pkt_fwd->gem_port = pPktFrwd->gem_port;
cust_flow->mod_vid = pPbitsMap->mod_vid[index];
cust_flow->mod_pbits = pPbitsMap->mod_pbits[index];
pkt_fwd->in_use = 1;
if (gs_mv_cust_trace_flag) {
MVCUST_TRACE_PRINT(KERN_INFO,
"trg_port(%d), trg_queue(%d) trg_hwf_queue(%d) gem_port(%d), mod_vid(%d), mod_pbits(%d)\n\r",
cust_flow->pkt_frwd.trg_port, cust_flow->pkt_frwd.trg_queue, cust_flow->pkt_frwd.trg_hwf_queue,
cust_flow->pkt_frwd.gem_port, cust_flow->mod_vid, cust_flow->mod_pbits);
}
}
/* If specific flow mapping rule does not exist, look for default rule */
else {
index = MV_CUST_PBITS_NOT_CARE_VALUE;
pPktFrwd = &pPbitsMap->pkt_fwd[index];
/* If default flow mapping rule exists */
if (pPktFrwd->in_use != 0) {
pkt_fwd->trg_port = pPktFrwd->trg_port;
if (false == mv_cust_get_tcont_state(pPktFrwd->trg_port))
pkt_fwd->trg_queue = CPH_INVALID_TRGT_QUEUE;
else
pkt_fwd->trg_queue = pPktFrwd->trg_queue;
pkt_fwd->trg_hwf_queue = pPktFrwd->trg_hwf_queue;
pkt_fwd->gem_port = pPktFrwd->gem_port;
cust_flow->mod_vid = pPbitsMap->mod_vid[index];
cust_flow->mod_pbits = pPbitsMap->mod_pbits[index];
pkt_fwd->in_use = 1;
if (gs_mv_cust_trace_flag) {
MVCUST_TRACE_PRINT(KERN_INFO,
"trg_port(%d), trg_queue(%d) trg_hwf_queue(%d) gem_port(%d), mod_vid(%d), mod_pbits(%d)\n\r",
cust_flow->pkt_frwd.trg_port, cust_flow->pkt_frwd.trg_queue, cust_flow->pkt_frwd.trg_hwf_queue,
cust_flow->pkt_frwd.gem_port, cust_flow->mod_vid, cust_flow->mod_pbits);
}
}
else {
pkt_fwd->in_use = 0;
if (gs_mv_cust_trace_flag) {
MVCUST_TRACE_PRINT(KERN_INFO,
"==EXIT==\n\r");
}
return MV_CUST_FAIL;
}
}
if (gs_mv_cust_trace_flag) {
MVCUST_TRACE_PRINT(KERN_INFO,
"==EXIT==\n\r");
}
return MV_CUST_OK;
}
/*******************************************************************************
**
** mv_cust_untag_map_rule_get
** ___________________________________________________________________________
**
** DESCRIPTION: The function gets GPON flow mapping rule for untagged frames.
**
** INPUTS:
** dscp - DSCP value.
**
** OUTPUTS:
** cust_flow - packet forwarding information, including GEM port, T-CONT, queue.
**
** RETURNS:
** On success, the function returns (MV_CUST_OK). On error different types are
** returned according to the case.
**
*******************************************************************************/
int mv_cust_untag_map_rule_get(mv_cust_ioctl_flow_map_t *cust_flow)
{
uint8_t *pVidEntry = NULL;
mv_cust_pbits_map_t *pPbitsMap = NULL;
mv_cust_pkt_frwd_t *pPktFrwd = NULL;
uint32_t pbitsIndex = MV_CUST_PBITS_NOT_CARE_VALUE;
mv_cust_flow_dir_e dir = MV_CUST_FLOW_DIR_US;
uint32_t dscp = 0;
if (gs_mv_cust_trace_flag) {
MVCUST_TRACE_PRINT(KERN_INFO,
"==ENTER==: dscp[%d] \n\r", dscp);
}
/* Check target port/queue/GEM port */
if (cust_flow == NULL) {
MVCUST_ERR_PRINT(KERN_ERR "cust_flow is NULL \n\r");
return MV_CUST_FAIL;
}
/* Set forwarding flag to false at first */
cust_flow->pkt_frwd.in_use = 0;
cust_flow->mod_vid = MV_CUST_VID_NOT_CARE_VALUE;
cust_flow->mod_pbits = MV_CUST_PBITS_NOT_CARE_VALUE;
dir = cust_flow->dir;
dscp = cust_flow->dscp;
/* Check DSCP */
if (dscp < MV_CUST_DSCP_PBITS_TABLE_MAX_SIZE) {
if (gs_dscp_map_table.in_use != 0) {
pbitsIndex = gs_dscp_map_table.pbits[dscp];
}
}
if(pbitsIndex > MV_CUST_PBITS_NOT_CARE_VALUE){
//MVCUST_ERR_PRINT(KERN_ERR "pbitsIndex[%d] is illegal \n\r", pbitsIndex);
return MV_CUST_FAIL;
}
/* Find P-bits mapping table */
pVidEntry = &gs_vid_index_table[dir].pbits_map_index[MV_CUST_DEFAULT_UNTAG_RULE];
if (*pVidEntry >= MV_CUST_MAX_PBITS_MAP_TABLE_SIZE) {
//MVCUST_TRACE_PRINT(KERN_INFO,"%s, pVidEntry[%d], does not exist \n\r",__FUNCTION__, *pVidEntry);
}
else {
pPbitsMap = &gs_pbits_map_table[dir][*pVidEntry];
if (pPbitsMap->in_use != 0) {
pPktFrwd = &pPbitsMap->pkt_fwd[pbitsIndex];
if (pPktFrwd->in_use != 0) {
cust_flow->pkt_frwd.trg_port = pPktFrwd->trg_port;
if (false == mv_cust_get_tcont_state(pPktFrwd->trg_port))
cust_flow->pkt_frwd.trg_queue = CPH_INVALID_TRGT_QUEUE;
else
cust_flow->pkt_frwd.trg_queue = pPktFrwd->trg_queue;
cust_flow->pkt_frwd.trg_hwf_queue = pPktFrwd->trg_hwf_queue;
cust_flow->pkt_frwd.gem_port = pPktFrwd->gem_port;
cust_flow->mod_vid = pPbitsMap->mod_vid[pbitsIndex];
cust_flow->mod_pbits = pPbitsMap->mod_pbits[pbitsIndex];
cust_flow->pkt_frwd.in_use = 1;
if (gs_mv_cust_trace_flag) {
MVCUST_TRACE_PRINT(KERN_INFO,
"trg_port(%d), trg_queue(%d), trg_hwf_queue(%d), gem_port(%d), mod_vid(%d), mod_pbits(%d)\n\r",
cust_flow->pkt_frwd.trg_port, cust_flow->pkt_frwd.trg_queue, cust_flow->pkt_frwd.trg_hwf_queue,
cust_flow->pkt_frwd.gem_port, cust_flow->mod_vid, cust_flow->mod_pbits);
MVCUST_TRACE_PRINT(KERN_INFO,
"==EXIT==:\n\r");
}
return MV_CUST_OK;
}
}
}
if (gs_mv_cust_trace_flag) {
MVCUST_TRACE_PRINT(KERN_INFO,
"==EXIT==:\n\r");
}
return MV_CUST_FAIL;
}
/*******************************************************************************
**
** mv_cust_map_table_print
** ___________________________________________________________________________
**
** DESCRIPTION: The function displays valid GPON flow mapping tables and DSCP
** to P-bits mapping tablefor untagged frames.
**
** INPUTS:
** None.
**
** OUTPUTS:
** None.
**
** RETURNS:
** On success, the function returns (MV_CUST_OK). On error different types are
** returned according to the case.
**
*******************************************************************************/
int mv_cust_map_table_print(void)
{
uint32_t index = 0;
uint32_t table_index = 0;
//MVCUST_TRACE_PRINT(KERN_INFO,"==ENTER==\n\r");
/* Print Valid VID index entries */
printk(KERN_INFO "In Upstream Direction \n----------------------------------\n");
printk(KERN_INFO "MV_CUST VLAN ID Index Table\n----------------------------------\n");
printk(KERN_INFO "VID P-bits_table_index\n");
for (index=0; index<MV_CUST_VID_INDEX_TABLE_MAX_SIZE; index++) {
if(gs_vid_index_table[MV_CUST_FLOW_DIR_US].pbits_map_index[index] < MV_CUST_MAX_PBITS_MAP_TABLE_SIZE)
printk(KERN_INFO "%4.4d %d\n", index, gs_vid_index_table[MV_CUST_FLOW_DIR_US].pbits_map_index[index]);
}
printk(KERN_INFO "\n\n");
/* Print P-bits mapping tables */
printk(KERN_INFO "MV_CUST P-bits Flow Mapping Tables\n----------------------------------\n\n");
for (table_index=0; table_index<MV_CUST_MAX_PBITS_MAP_TABLE_SIZE; table_index++) {
if(gs_pbits_map_table[MV_CUST_FLOW_DIR_US][table_index].in_use != 0) {
printk(KERN_INFO "P-bits Flow Mapping Table %d\n----------------------------\n", table_index);
printk(KERN_INFO "P-bits in_use mod_vid mod_pbits trg_port trg_queue trg_hwf_queue gem_port\n");
for (index=0; index<MV_CUST_PBITS_MAP_MAX_ENTRY_NUM; index++)
printk(KERN_INFO "%1.1d %3.3s %4.4d %1.1d %2.2d %2.2d %2.2d %4.4d\n",
index,
(gs_pbits_map_table[MV_CUST_FLOW_DIR_US][table_index].pkt_fwd[index].in_use!=0)? "YES":"",
gs_pbits_map_table[MV_CUST_FLOW_DIR_US][table_index].mod_vid[index],
gs_pbits_map_table[MV_CUST_FLOW_DIR_US][table_index].mod_pbits[index],
gs_pbits_map_table[MV_CUST_FLOW_DIR_US][table_index].pkt_fwd[index].trg_port,
gs_pbits_map_table[MV_CUST_FLOW_DIR_US][table_index].pkt_fwd[index].trg_queue,
gs_pbits_map_table[MV_CUST_FLOW_DIR_US][table_index].pkt_fwd[index].trg_hwf_queue,
gs_pbits_map_table[MV_CUST_FLOW_DIR_US][table_index].pkt_fwd[index].gem_port);
}
}
printk(KERN_INFO "\n\n");
printk(KERN_INFO "In Downstream Direction \n----------------------------------\n");
printk(KERN_INFO "MV_CUST VLAN ID Index Table\n----------------------------------\n");
printk(KERN_INFO "VID P-bits_table_index\n");
for (index=0; index<MV_CUST_VID_INDEX_TABLE_MAX_SIZE; index++) {
if(gs_vid_index_table[MV_CUST_FLOW_DIR_DS].pbits_map_index[index] < MV_CUST_MAX_PBITS_MAP_TABLE_SIZE)
printk(KERN_INFO "%4.4d %d\n", index, gs_vid_index_table[MV_CUST_FLOW_DIR_DS].pbits_map_index[index]);
}
printk(KERN_INFO "\n\n");
/* Print P-bits mapping tables */
printk(KERN_INFO "MV_CUST P-bits Flow Mapping Tables\n----------------------------------\n\n");
for (table_index=0; table_index<MV_CUST_MAX_PBITS_MAP_TABLE_SIZE; table_index++) {
if(gs_pbits_map_table[MV_CUST_FLOW_DIR_DS][table_index].in_use != 0) {
printk(KERN_INFO "P-bits Flow Mapping Table %d\n----------------------------\n", table_index);
printk(KERN_INFO "P-bits in_use mod_vid mod_pbits trg_queue trg_hwf_queue \n");
for (index=0; index<MV_CUST_PBITS_MAP_MAX_ENTRY_NUM; index++)
printk(KERN_INFO "%1.1d %3.3s %4.4d %1.1d %2.2d %2.2d \n",
index,
(gs_pbits_map_table[MV_CUST_FLOW_DIR_DS][table_index].pkt_fwd[index].in_use!=0)? "YES":"",
gs_pbits_map_table[MV_CUST_FLOW_DIR_DS][table_index].mod_vid[index],
gs_pbits_map_table[MV_CUST_FLOW_DIR_DS][table_index].mod_pbits[index],
gs_pbits_map_table[MV_CUST_FLOW_DIR_DS][table_index].pkt_fwd[index].trg_queue,
gs_pbits_map_table[MV_CUST_FLOW_DIR_DS][table_index].pkt_fwd[index].trg_hwf_queue);
}
}
printk(KERN_INFO "\n\n");
/* Print DSCP to P-bits mapping table */
printk(KERN_INFO "MV_CUST DSCP to P-bits Mapping Table\n----------------------------------\n");
if (gs_dscp_map_table.in_use == 0) {
printk(KERN_INFO "No DSCP to P-bits mapping\n");
}
else {
printk(KERN_INFO "DSCP Pbits\n");
for (index=0; index<MV_CUST_PBITS_MAP_MAX_ENTRY_NUM; index++)
printk(KERN_INFO "%2.2d %1.1d\n",
index, gs_dscp_map_table.pbits[index]);
}
printk(KERN_INFO "\n\n");
//MVCUST_TRACE_PRINT(KERN_INFO,"==EXIT==\n\r");
return MV_CUST_OK;
}
/*******************************************************************************
**
** mv_cust_flow_map_init
** ___________________________________________________________________________
**
** DESCRIPTION: The function initializes mv_cust flow mapping data structure.
**
** INPUTS:
** None.
**
** OUTPUTS:
** None.
**
** RETURNS:
** On success, the function returns (MV_CUST_OK). On error different types are
** returned according to the case.
**
*******************************************************************************/
int mv_cust_flow_map_init(void)
{
uint32_t index = 0;
/* Initializes VID index table */
memset((uint8_t *)&gs_vid_index_table, MV_CUST_INVALID_PBITS_TABLE_INDEX, sizeof(gs_vid_index_table));
/* Initializes P-bits mapping tables */
for (index = 0; index < MV_CUST_MAX_PBITS_MAP_TABLE_SIZE; index++) {
memset((uint8_t *)&gs_pbits_map_table[MV_CUST_FLOW_DIR_US][index], 0, sizeof(mv_cust_pbits_map_t));
gs_pbits_map_table[MV_CUST_FLOW_DIR_US][index].in_use = 0;
memset((uint8_t *)&gs_pbits_map_table[MV_CUST_FLOW_DIR_DS][index], 0, sizeof(mv_cust_pbits_map_t));
gs_pbits_map_table[MV_CUST_FLOW_DIR_DS][index].in_use = 0;
}
/* Initializes DSCP to P-bits mapping table */
memset((uint8_t *)&gs_dscp_map_table, 0, sizeof(mv_cust_dscp_pbits_t));
gs_dscp_map_table.in_use = 0;
/* Initializes T-CONT state, default value is false */
for (index = 0; index < CPH_MAX_TCONT_NUM; index++)
gs_tcont_state[index] = false;
return MV_CUST_OK;
}
/*******************************************************************************
**
** mv_cust_get_tcont_state
** ___________________________________________________________________________
**
** DESCRIPTION: The function get T-CONT state
**
** INPUTS:
** tcont - T-CONT
**
** OUTPUTS:
** None.
**
** RETURNS:
** state - State of T-CONT, enabled or disabled.
**
*******************************************************************************/
bool mv_cust_get_tcont_state(uint32_t tcont)
{
/* Check tcont */
if (tcont >= CPH_MAX_TCONT_NUM)
{
MVCUST_TRACE_PRINT(KERN_ERR,"tcont[%d] is illegal, should be less than [%d]\n", tcont, CPH_MAX_TCONT_NUM);
return false;
}
return gs_tcont_state[tcont];
}
/*******************************************************************************
**
** mv_cust_set_tcont_state
** ___________________________________________________________________________
**
** DESCRIPTION: The function sets T-CONT state in mv_cust
**
** INPUTS:
** tcont - T-CONT
** state - State of T-CONT, enabled or disabled.
**
** OUTPUTS:
** None.
**
** RETURNS:
** On success, the function returns (MV_OK). On error different types are
** returned according to the case.
**
*******************************************************************************/
MV_STATUS mv_cust_set_tcont_state(uint32_t tcont, bool state)
{
/* Check tcont */
if (tcont >= CPH_MAX_TCONT_NUM)
{
MVCUST_TRACE_PRINT(KERN_ERR,"tcont[%d] is illegal, should be less than [%d]\n", tcont, CPH_MAX_TCONT_NUM);
return MV_FAIL;
}
/* Apply t-cont state to mv_cust */
gs_tcont_state[tcont] = state;
return MV_OK;
}
EXPORT_SYMBOL(mv_cust_set_tcont_state);