spbx/roms/srcs/tools/switch_mirror/mirror_drv.c

649 lines
17 KiB
C

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/errno.h>
#include <linux/list.h>
#include <linux/io.h>
#include <linux/spinlock.h>
#include <linux/bitops.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/ctype.h>
#include <linux/fs.h>
#include <linux/spi/spi.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/kthread.h>
#include <asm/uaccess.h>
#include <linux/mm.h>
#include <linux/delay.h>
#include <linux/sched.h>
#include "mirror_drv.h"
#include "bcm_mirror.h"
#include "spbx_comm.h"
#include "spbx_log/spbx_log.h"
#include "./proc/debug_info.h"
#define DRV_INFO_MAJOR (233) ///< 驱动程序版本号
#define DEV_NAME ("mirror_port") ///< 驱动程序设备名
static BCM_PORT g_BCMPortPre[MAX_SWITCH_PORT];
extern int FlashBoardType(void);
extern const char* get_cmd_line_string(void);
void bcm_reset_init(void);
void bcm_reset_uninit(void);
static PMIRROR_HAL_DEV g_pMirrorDrv = NULL;
static struct spi_device* g_SPIDevice;
static BCM_PORT_NAME g_MirrorPortName = GE0_MSB_GE;
#define MIRROR_PORT (16)
PMIRROR_HAL_DEV DRV_GetDrvDetail(void)
{
return g_pMirrorDrv;
}
const char* GetBCMPortName(BCM_PORT_NAME bcmPort)
{
switch(bcmPort)
{
case FE0_BOARD_SLOT1:
return "FE0_BOARD_SLOT1";
case FE1_BOARD_SLOT2:
return "FE1_BOARD_SLOT2";
case FE2_BOARD_SLOT3:
return "FE2_BOARD_SLOT3";
case FE3_BOARD_SLOT4:
return "FE3_BOARD_SLOT4";
case FE4_BOARD_SLOT5:
return "FE4_BOARD_SLOT5";
case FE5_BOARD_FSLOT1:
return "FE5_BOARD_FSLOT1";
case FE6_MSB_ETH0:
return "FE6_MSB_ETH0";
case FE7_SG_ETH0:
return "FE7_SG_ETH0";
case FE8_MSB_FE1:
return "FE8_MSB_FE1";
case FE9_MSB_FE2:
return "FE9_MSB_FE2";
case FE10_MSB_FE3:
return "FE10_MSB_FE3";
case FE11_DM_TC:
return "FE11_DM_TC";
case GE0_MSB_GE:
return "GE0_MSB_GE";
case GE1_BOARD_FSLOT2:
return "GE1_BOARD_FSLOT2";
}
return "UNKNOWN";
}
static BCM_PORT g_BCMPort[MAX_SWITCH_PORT] =
{
{FE0_BOARD_SLOT1, GE0_MSB_GE, MIRROR_MASK_DISABLE},
{FE1_BOARD_SLOT2, GE0_MSB_GE, MIRROR_MASK_DISABLE},
{FE2_BOARD_SLOT3, GE0_MSB_GE, MIRROR_MASK_DISABLE},
{FE3_BOARD_SLOT4, GE0_MSB_GE, MIRROR_MASK_DISABLE},
{FE4_BOARD_SLOT5, GE0_MSB_GE, MIRROR_MASK_DISABLE},
{FE5_BOARD_FSLOT1, GE0_MSB_GE, MIRROR_MASK_DISABLE},
{FE6_MSB_ETH0, GE0_MSB_GE, MIRROR_MASK_DISABLE},
{FE7_SG_ETH0, GE0_MSB_GE, MIRROR_MASK_DISABLE},
{FE8_MSB_FE1, GE0_MSB_GE, MIRROR_MASK_DISABLE},
{FE9_MSB_FE2, GE0_MSB_GE, MIRROR_MASK_DISABLE},
{FE10_MSB_FE3, GE0_MSB_GE, MIRROR_MASK_DISABLE},
{FE11_DM_TC, GE0_MSB_GE, MIRROR_MASK_DISABLE},
{GE0_MSB_GE, GE0_MSB_GE, MIRROR_MASK_DISABLE},
{GE1_BOARD_FSLOT2, GE0_MSB_GE, MIRROR_MASK_DISABLE},
};
static void BCMMirrorUpdate(void)
{
int i;
for(i = 0; i < MAX_SWITCH_PORT; i++)
{
if(g_BCMPort[i].portName == g_MirrorPortName)
{
continue;
}
if(g_pMirrorDrv->bEnabled)
{
if(g_BCMPortPre[i].mirrorMask != g_BCMPort[i].mirrorMask)
{
if(g_BCMPortPre[i].mirrorMask & MIRROR_MASK_ENABLE)
{
if(g_BCMPortPre[i].mirrorMask & MIRROR_MASK_IN_ENABLE)
{
bcm_mir_in_on(g_BCMPortPre[i].portName, g_MirrorPortName);
}
else
{
bcm_mir_in_off(g_BCMPortPre[i].portName);
}
if(g_BCMPortPre[i].mirrorMask & MIRROR_MASK_OUT_ENABLE)
{
bcm_mir_out_on(g_BCMPortPre[i].portName, g_MirrorPortName);
}
else
{
bcm_mir_out_off(g_BCMPortPre[i].portName);
}
}
else
{
bcm_mir_in_off(g_BCMPortPre[i].portName);
bcm_mir_out_off(g_BCMPortPre[i].portName);
}
}
}
else
{
if(g_BCMPortPre[i].mirrorMask != g_BCMPort[i].mirrorMask)
{
bcm_mir_in_off(g_BCMPortPre[i].portName);
bcm_mir_out_off(g_BCMPortPre[i].portName);
}
}
}
memcpy(g_BCMPort, g_BCMPortPre, sizeof(g_BCMPort));
}
static int CheckBCMPort(int port, int bMirror)
{
if(bMirror)
{
if(port == FE8_MSB_FE1 ||
port == FE9_MSB_FE2 |
port == FE10_MSB_FE3 ||
port == g_MirrorPortName)
{
return 0;
}
}
else
{
if(port >= FE0_BOARD_SLOT1 && port <= FE11_DM_TC)
{
return 0;
}
else if(port == GE0_MSB_GE || port == GE1_BOARD_FSLOT2)
{
return 0;
}
}
return -1;
}
static struct spi_board_info g_SPIBoardInfo =
{
.modalias = "spidev",
.bus_num = 0x7000,
.chip_select = 0,
.max_speed_hz = 8000000,
};
static struct file_operations drv_hal_fops =
{
.owner = THIS_MODULE,
.llseek = no_llseek,
};
static void InitSwitchPort(void)
{
int i = 0;
for(i = 0; i < MAX_SWITCH_PORT; i++)
{
g_BCMPort[i].mirrorMask = MIRROR_MASK_DISABLE;
g_BCMPort[i].mirrorPort = g_MirrorPortName;
}
memcpy(g_BCMPortPre, g_BCMPort, sizeof(g_BCMPort));
}
int BCM_EnableMirrorPort(int bEnable)
{
int i = 0;
if(g_pMirrorDrv)
{
g_pMirrorDrv->bEnabled = bEnable;
}
return ERR_NO_ERROR;
}
static void DbgFsSeqPrintf(struct seq_file *seq, PBCM_PORT pBcmPort)
{
int i;
unsigned int uFlag = 0;
char strPortName[20], strPortEn[8], strPortIn[8], strPortOut[8];
seq_printf(seq, "%s%s\n",
"+-------------------------------------------------",
"--------------------------------------------------+");
seq_printf(seq, "|%20s|%9s|%20s|%15s|%15s|%15s|\n",
" Name ",
" Port Id ",
" Mirror Prot ",
" Mirror Switch ",
" Mirror Input ",
" Mirror Output ");
seq_printf(seq, "%s%s\n",
"+-------------------------------------------------",
"--------------------------------------------------+");
for(i = 0; i < MAX_SWITCH_PORT; i++)
{
if(pBcmPort[i].portName == g_MirrorPortName)
{
continue;
}
uFlag = g_BCMPort[i].mirrorMask ^ g_BCMPortPre[i].mirrorMask;
if(uFlag)
{
sprintf(strPortName, "*%s", GetBCMPortName(pBcmPort[i].portName));
}
else
{
strncpy(strPortName, GetBCMPortName(pBcmPort[i].portName), 19);
}
seq_printf(seq, "|%19s |%8d |%19s |%14s |%14s |%14s |\n",
strPortName,
pBcmPort[i].portName,
GetBCMPortName(pBcmPort[i].mirrorPort),
(pBcmPort[i].mirrorMask & MIRROR_MASK_ENABLE) ?
((uFlag & MIRROR_MASK_ENABLE) ? "*ON" : "ON") :
((uFlag & MIRROR_MASK_ENABLE) ? "*OFF" : "OFF"),
(pBcmPort[i].mirrorMask & MIRROR_MASK_IN_ENABLE) ?
((uFlag & MIRROR_MASK_IN_ENABLE) ? "*ON" : "ON") :
((uFlag & MIRROR_MASK_IN_ENABLE) ? "*OFF" : "OFF"),
(pBcmPort[i].mirrorMask & MIRROR_MASK_OUT_ENABLE) ?
((uFlag & MIRROR_MASK_OUT_ENABLE) ? "*ON" : "ON") :
((uFlag & MIRROR_MASK_OUT_ENABLE) ? "*OFF" : "OFF")
);
seq_printf(seq, "%s%s\n",
"+-------------------------------------------------",
"--------------------------------------------------+");
}
}
static int DbgFS_MirrorEnableShow(struct seq_file* seq, void* token);
static int DbgFS_MirrorleShow(struct seq_file* seq, void* token);
static int DbgFS_MirrorSetTableShow(struct seq_file* seq, void* token);
static int DbgFS_HelpShow(struct seq_file* seq, void* token);
static DBGFS_PRIV g_DbgFSConfig[] =
{
{
"info", NULL, NULL, DbgFS_MirrorleShow, ""
},
{
"enable", NULL, NULL, DbgFS_MirrorEnableShow, ""
},
{
"set", NULL, NULL, DbgFS_MirrorSetTableShow, ""
},
{
"help", NULL, NULL, DbgFS_HelpShow, ""
},
};
static int DbgFS_HelpShow(struct seq_file* seq, void* token)
{
printk("\n==============Options Helps=============\n");
printk("usage: echo \"<port(0..11,26)> <opeartion (in/out/both/switch)> <value (on/off)>\" > /proc/spbx_mirror/mirror_port\n");
printk("params:\n");
printk("\t[port ]: Switch port id, from 0 to 11 and 26, others is disabled.\n");
printk("\t[opeartion ]: Which property to do for this port, in port, out port and enable switch.\n");
printk("\t[value ]: Property value.\n");
return 0;
}
static int DbgFS_MirrorSetTableShow(struct seq_file* seq, void* token)
{
int i, iRet = 0;
char strProperty[16], strValue[16];
unsigned char pArgs[16];
int optMask = MIRROR_MASK_DISABLE;
int value = FALSE;
int findPort = FALSE;
strncpy(pArgs, g_DbgFSConfig[2].args, 16);
memset(g_DbgFSConfig[2].args, 0, MAX_PATH);
if(strlen(pArgs) <= 0 || strlen(pArgs) >= 16)
{
seq_printf(seq, "\nSPBX BCM Mirror Port Current Set Table Information:\n");
DbgFsSeqPrintf(seq, &g_BCMPortPre[0]);
return (0);
}
if(token == SEQ_START_TOKEN)
{
int port = GetIntParamValue(pArgs, 0);
for(i = 0; i < GET_ARRAY_SIZE(g_BCMPortPre); i++)
{
if(g_BCMPortPre[i].portName == port)
{
port = i;
findPort = TRUE;
break;
}
}
if(!findPort)
{
LOG_EX(LOG_Error, "Port Error: %d\n", port);
return (ERR_DBGFS_NO_ERROR | 0x1000);
}
if(GetStringParamValue(pArgs, 1, strProperty, 15) != ERR_DBGFS_NO_ERROR)
{
seq_printf(seq, "strProperty Error: %s\n", strProperty);
return (0);
}
if(GetStringParamValue(pArgs, 2, strValue, 15) != ERR_DBGFS_NO_ERROR)
{
seq_printf(seq, "strValue Error: [%s]\n", strValue);
return (0);
}
if(strcmp(strProperty, "in") == 0)
{
optMask = MIRROR_MASK_IN_ENABLE;
}
else if(strcmp(strProperty, "out") == 0)
{
optMask = MIRROR_MASK_OUT_ENABLE;
}
else if(strcmp(strProperty, "both") == 0)
{
optMask = MIRROR_MASK_IN_ENABLE | MIRROR_MASK_OUT_ENABLE;
}
else if(strcmp(strProperty, "switch") == 0)
{
optMask = MIRROR_MASK_ENABLE;
}
else
{
seq_printf(seq, "Unknown opeartion: %s\n", strProperty);
return (0);
}
if(strcmp(strValue, "on") == 0)
{
value = TRUE;
}
else if(strcmp(strValue, "off") == 0)
{
value = FALSE;
}
else
{
return (0);
}
if(value)
{
if(!(optMask & MIRROR_MASK_ENABLE))
{
if(optMask & MIRROR_MASK_IN_ENABLE)
{
g_BCMPortPre[port].mirrorMask |= MIRROR_MASK_IN_ENABLE;
}
if(optMask & MIRROR_MASK_OUT_ENABLE)
{
g_BCMPortPre[port].mirrorMask |= MIRROR_MASK_OUT_ENABLE;
}
}
g_BCMPortPre[port].mirrorMask |= MIRROR_MASK_ENABLE;
}
else
{
if(optMask & MIRROR_MASK_ENABLE)
{
g_BCMPortPre[port].mirrorMask &= ~MIRROR_MASK_ENABLE;
}
else
{
if(optMask & MIRROR_MASK_IN_ENABLE)
{
g_BCMPortPre[port].mirrorMask &= ~MIRROR_MASK_IN_ENABLE;
}
if(optMask & MIRROR_MASK_OUT_ENABLE)
{
g_BCMPortPre[port].mirrorMask &= ~MIRROR_MASK_OUT_ENABLE;
}
if((g_BCMPortPre[port].mirrorMask & MIRROR_MASK_IN_ENABLE) ||
(g_BCMPortPre[port].mirrorMask & MIRROR_MASK_OUT_ENABLE))
{
g_BCMPortPre[port].mirrorMask |= MIRROR_MASK_ENABLE;
}
else
{
g_BCMPortPre[port].mirrorMask &= ~MIRROR_MASK_ENABLE;
}
}
}
seq_printf(seq, "Configure %s Mirror Port Input [%s] Output [%s] to %s\n",
GetBCMPortName(g_BCMPortPre[port].portName),
(g_BCMPortPre[port].mirrorMask & MIRROR_MASK_IN_ENABLE) ? "ON" : "OFF",
(g_BCMPortPre[port].mirrorMask & MIRROR_MASK_OUT_ENABLE) ? "ON" : "OFF",
GetBCMPortName(g_MirrorPortName));
seq_printf(seq, "\nSPBX BCM Mirror Port Current Set Table Information:\n");
DbgFsSeqPrintf(seq, &g_BCMPortPre[0]);
}
BCMMirrorUpdate();
return (0);
}
static int DbgFS_MirrorEnableShow(struct seq_file* seq, void* token)
{
unsigned char* pArgs = g_DbgFSConfig[1].args;
if(token == SEQ_START_TOKEN)
{
int enable = GetIntParamValue(pArgs, 0);
BCM_EnableMirrorPort(enable ? TRUE : FALSE);
seq_printf(seq, "SPBX BCM Mirror Port Function [%s], Mirror Port is [%s]\n",
enable ? "ON" : "OFF", GetBCMPortName(g_MirrorPortName));
}
return (0);
}
static int DbgFS_MirrorleShow(struct seq_file* seq, void* token)
{
int i = 0;
if(token == SEQ_START_TOKEN && g_pMirrorDrv)
{
seq_printf(seq, "SPBX BCM Mirror Port Function [%s], Mirror Port is [%s]\n",
g_pMirrorDrv->bEnabled? "ON" : "OFF", GetBCMPortName(g_MirrorPortName));
seq_printf(seq, "\nSPBX BCM Mirror Port System Table Information:\n");
DbgFsSeqPrintf(seq, &g_BCMPort[0]);
}
return 0;
}
static int __init mirror_drv_init(void)
{
int i = 0;
PMIRROR_HAL_DEV pDev = NULL;
#ifdef PLATFORM_P1010
LOG_EX(LOG_Info, "Box Info Init PLATFORM P1010 Ver:%s Build:%s(%s)\n",
VERSION, __DATE__, __TIME__);
#else
LOG_EX(LOG_Info, "Box Info Init PLATFORM MPC8309 Ver:%s Build:%s(%s)\n",
VERSION, __DATE__, __TIME__);
#endif
if(FlashBoardType() != BOARD_MSB2U4)
{
LOG_EX(LOG_Error, "Not MSB Board, Don't need Running...........\n");
return -1;
}
pDev = (PMIRROR_HAL_DEV)kmalloc(sizeof(MIRROR_HAL_DEV), GFP_KERNEL);
if(pDev == NULL)
{
LOG_EX(LOG_Error, "%s(%d):Malloc Error\n", __FUNCTION__, __LINE__);
return ERR_MALLOC_MEMORY;
}
InitSwitchPort();
pDev->bEnabled = FALSE;
mpc_spi_init();
pDev->pSPIMaster = get_spi_master();
if(pDev->pSPIMaster == NULL)
{
kfree(pDev);
LOG_EX(LOG_Error, "%s(%d):Get SPI Device Error\n", __FUNCTION__, __LINE__);
return -1;
}
pDev->pSPIDevice = spi_new_device(pDev->pSPIMaster, &g_SPIBoardInfo);
mdelay(100);
if(IS_ERR(pDev->pSPIDevice))
{
kfree(pDev);
LOG_EX(LOG_Error, "%s(%d):Get SPI Device Driver Error\n", __FUNCTION__, __LINE__);
return -1;
}
// 注册设备
register_chrdev(DRV_INFO_MAJOR, DEV_NAME, &drv_hal_fops);
pDev->pDevClass = class_create(THIS_MODULE, "mirror_port");
device_create(pDev->pDevClass, NULL, MKDEV(DRV_INFO_MAJOR, 0), NULL,
"mirror_port/hal_dev");
g_pMirrorDrv = pDev;
InitDebugInfoProc("spbx_mirror");
for(i = 0; i < sizeof(g_DbgFSConfig) / sizeof(g_DbgFSConfig[0]); i++)
{
if(DebugFsRegister(&g_DbgFSConfig[i]) != ERR_NO_ERROR)
{
LOG_EX(LOG_Error, "%d Regisetr %s Error\n",
i, g_DbgFSConfig[i].name);
}
}
for(i = 0; i < MAX_SWITCH_PORT; i++)
{
bcm_mir_in_off(g_BCMPortPre[i].portName);
bcm_mir_out_off(g_BCMPortPre[i].portName);
}
return ERR_NO_ERROR;
}
static void __exit mirror_drv_exit(void)
{
int i = 0;
#ifdef PLATFORM_P1010
LOG_EX(LOG_Info, "Box Info Exit PLATFORM P1010 Build:%s(%s)\n",
__DATE__, __TIME__);
#else
LOG_EX(LOG_Info, "Box Info Exit PLATFORM MPC8309 Build:%s(%s)\n",
__DATE__, __TIME__);
#endif
for(i = 0; i < MAX_SWITCH_PORT; i++)
{
bcm_mir_in_off(g_BCMPortPre[i].portName);
bcm_mir_out_off(g_BCMPortPre[i].portName);
}
mpc_spi_exit();
for(i = 0; i < sizeof(g_DbgFSConfig) / sizeof(g_DbgFSConfig[0]); i++)
{
DebugFsUnRegister(&g_DbgFSConfig[i]);
}
DeInitDebugInfoProc();
// 删除驱动
if(g_pMirrorDrv != NULL)
{
device_destroy(g_pMirrorDrv->pDevClass, MKDEV(DRV_INFO_MAJOR, 0));
class_destroy(g_pMirrorDrv->pDevClass);
unregister_chrdev(DRV_INFO_MAJOR, DEV_NAME);
kfree(g_pMirrorDrv);
g_pMirrorDrv = NULL;
}
}
module_init(mirror_drv_init);
module_exit(mirror_drv_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Synway");
MODULE_DESCRIPTION("mirror port drv");
MODULE_VERSION("0.92");