drivers/net/vsc9953: Add default configuration for VSC9953 L2 Switch
At startup, the default configuration should be: - enable HW learning on all ports (HW default); - all ports are VLAN aware; - all ports are members of VLAN 1; - all ports have Port-based VLAN 1; - on all ports, the switch is allowed to remove maximum one VLAN tag, - on egress, the switch should add a VLAN tag if the frame is classified to a different VLAN than the port's Port-based VLAN; Signed-off-by: Johnson Leung <johnson.leung@freescale.com> Signed-off-by: Codrin Ciubotariu <codrin.ciubotariu@freescale.com> Acked-by: Joe Hershberger <joe.hershberger@ni.com> Reviewed-by: York Sun <yorksun@freescale.com>
This commit is contained in:
parent
8756de2824
commit
9de059871f
|
@ -10,6 +10,7 @@
|
||||||
#include <asm/fsl_serdes.h>
|
#include <asm/fsl_serdes.h>
|
||||||
#include <fm_eth.h>
|
#include <fm_eth.h>
|
||||||
#include <fsl_memac.h>
|
#include <fsl_memac.h>
|
||||||
|
#include <bitfield.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#include <vsc9953.h>
|
#include <vsc9953.h>
|
||||||
|
@ -178,6 +179,256 @@ static int vsc9953_port_init(int port_no)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int vsc9953_vlan_table_poll_idle(void)
|
||||||
|
{
|
||||||
|
struct vsc9953_analyzer *l2ana_reg;
|
||||||
|
int timeout;
|
||||||
|
|
||||||
|
l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
|
||||||
|
VSC9953_ANA_OFFSET);
|
||||||
|
|
||||||
|
timeout = 50000;
|
||||||
|
while (((in_le32(&l2ana_reg->ana_tables.vlan_access) &
|
||||||
|
VSC9953_VLAN_CMD_MASK) != VSC9953_VLAN_CMD_IDLE) && --timeout)
|
||||||
|
udelay(1);
|
||||||
|
|
||||||
|
return timeout ? 0 : -EBUSY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* vlan table set/clear all membership of vid */
|
||||||
|
static void vsc9953_vlan_table_membership_all_set(int vid, int set_member)
|
||||||
|
{
|
||||||
|
uint val;
|
||||||
|
struct vsc9953_analyzer *l2ana_reg;
|
||||||
|
|
||||||
|
l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
|
||||||
|
VSC9953_ANA_OFFSET);
|
||||||
|
|
||||||
|
if (vsc9953_vlan_table_poll_idle() < 0) {
|
||||||
|
debug("VLAN table timeout\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* read current vlan configuration */
|
||||||
|
val = in_le32(&l2ana_reg->ana_tables.vlan_tidx);
|
||||||
|
out_le32(&l2ana_reg->ana_tables.vlan_tidx,
|
||||||
|
bitfield_replace_by_mask(val, VSC9953_ANA_TBL_VID_MASK, vid));
|
||||||
|
|
||||||
|
clrsetbits_le32(&l2ana_reg->ana_tables.vlan_access,
|
||||||
|
VSC9953_VLAN_CMD_MASK, VSC9953_VLAN_CMD_READ);
|
||||||
|
|
||||||
|
if (vsc9953_vlan_table_poll_idle() < 0) {
|
||||||
|
debug("VLAN table timeout\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
val = in_le32(&l2ana_reg->ana_tables.vlan_tidx);
|
||||||
|
out_le32(&l2ana_reg->ana_tables.vlan_tidx,
|
||||||
|
bitfield_replace_by_mask(val, VSC9953_ANA_TBL_VID_MASK, vid));
|
||||||
|
|
||||||
|
clrsetbits_le32(&l2ana_reg->ana_tables.vlan_access,
|
||||||
|
VSC9953_VLAN_PORT_MASK | VSC9953_VLAN_CMD_MASK,
|
||||||
|
VSC9953_VLAN_CMD_WRITE |
|
||||||
|
(set_member ? VSC9953_VLAN_PORT_MASK : 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set PVID for a VSC9953 port */
|
||||||
|
static void vsc9953_port_vlan_pvid_set(int port_no, int pvid)
|
||||||
|
{
|
||||||
|
uint val;
|
||||||
|
struct vsc9953_analyzer *l2ana_reg;
|
||||||
|
struct vsc9953_rew_reg *l2rew_reg;
|
||||||
|
|
||||||
|
/* Administrative down */
|
||||||
|
if (!vsc9953_l2sw.port[port_no].enabled) {
|
||||||
|
printf("Port %d is administrative down\n", port_no);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
|
||||||
|
VSC9953_ANA_OFFSET);
|
||||||
|
l2rew_reg = (struct vsc9953_rew_reg *)(VSC9953_OFFSET +
|
||||||
|
VSC9953_REW_OFFSET);
|
||||||
|
|
||||||
|
/* Set PVID on ingress */
|
||||||
|
val = in_le32(&l2ana_reg->port[port_no].vlan_cfg);
|
||||||
|
val = bitfield_replace_by_mask(val, VSC9953_VLAN_CFG_VID_MASK, pvid);
|
||||||
|
out_le32(&l2ana_reg->port[port_no].vlan_cfg, val);
|
||||||
|
|
||||||
|
/* Set PVID on egress */
|
||||||
|
val = in_le32(&l2rew_reg->port[port_no].port_vlan_cfg);
|
||||||
|
val = bitfield_replace_by_mask(val, VSC9953_PORT_VLAN_CFG_VID_MASK,
|
||||||
|
pvid);
|
||||||
|
out_le32(&l2rew_reg->port[port_no].port_vlan_cfg, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void vsc9953_port_all_vlan_pvid_set(int pvid)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < VSC9953_MAX_PORTS; i++)
|
||||||
|
vsc9953_port_vlan_pvid_set(i, pvid);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Enable/disable vlan aware of a VSC9953 port */
|
||||||
|
static void vsc9953_port_vlan_aware_set(int port_no, int enabled)
|
||||||
|
{
|
||||||
|
struct vsc9953_analyzer *l2ana_reg;
|
||||||
|
|
||||||
|
/* Administrative down */
|
||||||
|
if (!vsc9953_l2sw.port[port_no].enabled) {
|
||||||
|
printf("Port %d is administrative down\n", port_no);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
|
||||||
|
VSC9953_ANA_OFFSET);
|
||||||
|
|
||||||
|
if (enabled)
|
||||||
|
setbits_le32(&l2ana_reg->port[port_no].vlan_cfg,
|
||||||
|
VSC9953_VLAN_CFG_AWARE_ENA);
|
||||||
|
else
|
||||||
|
clrbits_le32(&l2ana_reg->port[port_no].vlan_cfg,
|
||||||
|
VSC9953_VLAN_CFG_AWARE_ENA);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set all VSC9953 ports' vlan aware */
|
||||||
|
static void vsc9953_port_all_vlan_aware_set(int enabled)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < VSC9953_MAX_PORTS; i++)
|
||||||
|
vsc9953_port_vlan_aware_set(i, enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Enable/disable vlan pop count of a VSC9953 port */
|
||||||
|
static void vsc9953_port_vlan_popcnt_set(int port_no, int popcnt)
|
||||||
|
{
|
||||||
|
uint val;
|
||||||
|
struct vsc9953_analyzer *l2ana_reg;
|
||||||
|
|
||||||
|
/* Administrative down */
|
||||||
|
if (!vsc9953_l2sw.port[port_no].enabled) {
|
||||||
|
printf("Port %d is administrative down\n", port_no);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (popcnt > 3 || popcnt < 0) {
|
||||||
|
printf("Invalid pop count value: %d\n", port_no);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
|
||||||
|
VSC9953_ANA_OFFSET);
|
||||||
|
|
||||||
|
val = in_le32(&l2ana_reg->port[port_no].vlan_cfg);
|
||||||
|
val = bitfield_replace_by_mask(val, VSC9953_VLAN_CFG_POP_CNT_MASK,
|
||||||
|
popcnt);
|
||||||
|
out_le32(&l2ana_reg->port[port_no].vlan_cfg, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set all VSC9953 ports' pop count */
|
||||||
|
static void vsc9953_port_all_vlan_poncnt_set(int popcnt)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < VSC9953_MAX_PORTS; i++)
|
||||||
|
vsc9953_port_vlan_popcnt_set(i, popcnt);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Enable/disable learning for frames dropped due to ingress filtering */
|
||||||
|
static void vsc9953_vlan_ingr_fltr_learn_drop(int enable)
|
||||||
|
{
|
||||||
|
struct vsc9953_analyzer *l2ana_reg;
|
||||||
|
|
||||||
|
l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
|
||||||
|
VSC9953_ANA_OFFSET);
|
||||||
|
|
||||||
|
if (enable)
|
||||||
|
setbits_le32(&l2ana_reg->ana.adv_learn, VSC9953_VLAN_CHK);
|
||||||
|
else
|
||||||
|
clrbits_le32(&l2ana_reg->ana.adv_learn, VSC9953_VLAN_CHK);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Egress untag modes of a VSC9953 port */
|
||||||
|
enum egress_untag_mode {
|
||||||
|
EGRESS_UNTAG_ALL = 0,
|
||||||
|
EGRESS_UNTAG_PVID_AND_ZERO,
|
||||||
|
EGRESS_UNTAG_ZERO,
|
||||||
|
EGRESS_UNTAG_NONE,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void vsc9953_port_vlan_egr_untag_set(int port_no,
|
||||||
|
enum egress_untag_mode mode)
|
||||||
|
{
|
||||||
|
struct vsc9953_rew_reg *l2rew_reg;
|
||||||
|
|
||||||
|
/* Administrative down */
|
||||||
|
if (!vsc9953_l2sw.port[port_no].enabled) {
|
||||||
|
printf("Port %d is administrative down\n", port_no);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
l2rew_reg = (struct vsc9953_rew_reg *)(VSC9953_OFFSET +
|
||||||
|
VSC9953_REW_OFFSET);
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case EGRESS_UNTAG_ALL:
|
||||||
|
clrsetbits_le32(&l2rew_reg->port[port_no].port_tag_cfg,
|
||||||
|
VSC9953_TAG_CFG_MASK, VSC9953_TAG_CFG_NONE);
|
||||||
|
break;
|
||||||
|
case EGRESS_UNTAG_PVID_AND_ZERO:
|
||||||
|
clrsetbits_le32(&l2rew_reg->port[port_no].port_tag_cfg,
|
||||||
|
VSC9953_TAG_CFG_MASK,
|
||||||
|
VSC9953_TAG_CFG_ALL_BUT_PVID_ZERO);
|
||||||
|
break;
|
||||||
|
case EGRESS_UNTAG_ZERO:
|
||||||
|
clrsetbits_le32(&l2rew_reg->port[port_no].port_tag_cfg,
|
||||||
|
VSC9953_TAG_CFG_MASK,
|
||||||
|
VSC9953_TAG_CFG_ALL_BUT_ZERO);
|
||||||
|
break;
|
||||||
|
case EGRESS_UNTAG_NONE:
|
||||||
|
clrsetbits_le32(&l2rew_reg->port[port_no].port_tag_cfg,
|
||||||
|
VSC9953_TAG_CFG_MASK, VSC9953_TAG_CFG_ALL);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("Unknown untag mode for port %d\n", port_no);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void vsc9953_port_all_vlan_egress_untagged_set(
|
||||||
|
enum egress_untag_mode mode)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < VSC9953_MAX_PORTS; i++)
|
||||||
|
vsc9953_port_vlan_egr_untag_set(i, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
At startup, the default configuration would be:
|
||||||
|
- HW learning enabled on all ports; (HW default)
|
||||||
|
- All ports are in VLAN 1;
|
||||||
|
- All ports are VLAN aware;
|
||||||
|
- All ports have POP_COUNT 1;
|
||||||
|
- All ports have PVID 1;
|
||||||
|
- All ports have TPID 0x8100; (HW default)
|
||||||
|
- All ports tag frames classified to all VLANs that are not PVID;
|
||||||
|
*****************************************************************************/
|
||||||
|
void vsc9953_default_configuration(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < VSC9953_MAX_VLAN; i++)
|
||||||
|
vsc9953_vlan_table_membership_all_set(i, 0);
|
||||||
|
vsc9953_port_all_vlan_aware_set(1);
|
||||||
|
vsc9953_port_all_vlan_pvid_set(1);
|
||||||
|
vsc9953_port_all_vlan_poncnt_set(1);
|
||||||
|
vsc9953_vlan_table_membership_all_set(1, 1);
|
||||||
|
vsc9953_vlan_ingr_fltr_learn_drop(1);
|
||||||
|
vsc9953_port_all_vlan_egress_untagged_set(EGRESS_UNTAG_PVID_AND_ZERO);
|
||||||
|
}
|
||||||
|
|
||||||
void vsc9953_init(bd_t *bis)
|
void vsc9953_init(bd_t *bis)
|
||||||
{
|
{
|
||||||
u32 i;
|
u32 i;
|
||||||
|
@ -310,6 +561,8 @@ void vsc9953_init(bd_t *bis)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vsc9953_default_configuration();
|
||||||
|
|
||||||
printf("VSC9953 L2 switch initialized\n");
|
printf("VSC9953 L2 switch initialized\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#define VSC9953_OFFSET (CONFIG_SYS_CCSRBAR_DEFAULT + 0x800000)
|
#define VSC9953_OFFSET (CONFIG_SYS_CCSRBAR_DEFAULT + 0x800000)
|
||||||
|
|
||||||
#define VSC9953_SYS_OFFSET 0x010000
|
#define VSC9953_SYS_OFFSET 0x010000
|
||||||
|
#define VSC9953_REW_OFFSET 0x030000
|
||||||
#define VSC9953_DEV_GMII_OFFSET 0x100000
|
#define VSC9953_DEV_GMII_OFFSET 0x100000
|
||||||
#define VSC9953_QSYS_OFFSET 0x200000
|
#define VSC9953_QSYS_OFFSET 0x200000
|
||||||
#define VSC9953_ANA_OFFSET 0x280000
|
#define VSC9953_ANA_OFFSET 0x280000
|
||||||
|
@ -80,9 +81,38 @@
|
||||||
#define VSC9953_VCAP_MV_CFG 0x0000ffff
|
#define VSC9953_VCAP_MV_CFG 0x0000ffff
|
||||||
#define VSC9953_VCAP_UPDATE_CTRL 0x01000004
|
#define VSC9953_VCAP_UPDATE_CTRL 0x01000004
|
||||||
|
|
||||||
|
/* Macros for vsc9953_ana_port.vlan_cfg register */
|
||||||
|
#define VSC9953_VLAN_CFG_AWARE_ENA 0x00100000
|
||||||
|
#define VSC9953_VLAN_CFG_POP_CNT_MASK 0x000c0000
|
||||||
|
#define VSC9953_VLAN_CFG_VID_MASK 0x00000fff
|
||||||
|
|
||||||
|
/* Macros for vsc9953_rew_port.port_vlan_cfg register */
|
||||||
|
#define VSC9953_PORT_VLAN_CFG_VID_MASK 0x00000fff
|
||||||
|
|
||||||
|
/* Macros for vsc9953_ana_ana_tables.vlan_tidx register */
|
||||||
|
#define VSC9953_ANA_TBL_VID_MASK 0x00000fff
|
||||||
|
|
||||||
|
/* Macros for vsc9953_ana_ana_tables.vlan_access register */
|
||||||
|
#define VSC9953_VLAN_PORT_MASK 0x00001ffc
|
||||||
|
#define VSC9953_VLAN_CMD_MASK 0x00000003
|
||||||
|
#define VSC9953_VLAN_CMD_IDLE 0x00000000
|
||||||
|
#define VSC9953_VLAN_CMD_READ 0x00000001
|
||||||
|
#define VSC9953_VLAN_CMD_WRITE 0x00000002
|
||||||
|
#define VSC9953_VLAN_CMD_INIT 0x00000003
|
||||||
|
|
||||||
/* Macros for vsc9953_qsys_sys.switch_port_mode register */
|
/* Macros for vsc9953_qsys_sys.switch_port_mode register */
|
||||||
#define VSC9953_PORT_ENA 0x00002000
|
#define VSC9953_PORT_ENA 0x00002000
|
||||||
|
|
||||||
|
/* Macros for vsc9953_ana_ana.adv_learn register */
|
||||||
|
#define VSC9953_VLAN_CHK 0x00000400
|
||||||
|
|
||||||
|
/* Macros for vsc9953_rew_port.port_tag_cfg register */
|
||||||
|
#define VSC9953_TAG_CFG_MASK 0x00000180
|
||||||
|
#define VSC9953_TAG_CFG_NONE 0x00000000
|
||||||
|
#define VSC9953_TAG_CFG_ALL_BUT_PVID_ZERO 0x00000080
|
||||||
|
#define VSC9953_TAG_CFG_ALL_BUT_ZERO 0x00000100
|
||||||
|
#define VSC9953_TAG_CFG_ALL 0x00000180
|
||||||
|
|
||||||
#define VSC9953_MAX_PORTS 10
|
#define VSC9953_MAX_PORTS 10
|
||||||
#define VSC9953_PORT_CHECK(port) \
|
#define VSC9953_PORT_CHECK(port) \
|
||||||
(((port) < 0 || (port) >= VSC9953_MAX_PORTS) ? 0 : 1)
|
(((port) < 0 || (port) >= VSC9953_MAX_PORTS) ? 0 : 1)
|
||||||
|
@ -91,6 +121,9 @@
|
||||||
(port) < VSC9953_MAX_PORTS - 2 || (port) >= VSC9953_MAX_PORTS \
|
(port) < VSC9953_MAX_PORTS - 2 || (port) >= VSC9953_MAX_PORTS \
|
||||||
) ? 0 : 1 \
|
) ? 0 : 1 \
|
||||||
)
|
)
|
||||||
|
#define VSC9953_MAX_VLAN 4096
|
||||||
|
#define VSC9953_VLAN_CHECK(vid) \
|
||||||
|
(((vid) < 0 || (vid) >= VSC9953_MAX_VLAN) ? 0 : 1)
|
||||||
|
|
||||||
#define DEFAULT_VSC9953_MDIO_NAME "VSC9953_MDIO0"
|
#define DEFAULT_VSC9953_MDIO_NAME "VSC9953_MDIO0"
|
||||||
|
|
||||||
|
@ -338,6 +371,29 @@ struct vsc9953_system_reg {
|
||||||
|
|
||||||
/* END VSC9953 SYS structure */
|
/* END VSC9953 SYS structure */
|
||||||
|
|
||||||
|
/* VSC9953 REW structure */
|
||||||
|
|
||||||
|
struct vsc9953_rew_port {
|
||||||
|
u32 port_vlan_cfg;
|
||||||
|
u32 port_tag_cfg;
|
||||||
|
u32 port_port_cfg;
|
||||||
|
u32 port_dscp_cfg;
|
||||||
|
u32 port_pcp_dei_qos_map_cfg[16];
|
||||||
|
u32 reserved[12];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct vsc9953_rew_common {
|
||||||
|
u32 reserve[4];
|
||||||
|
u32 dscp_remap_dp1_cfg[64];
|
||||||
|
u32 dscp_remap_cfg[64];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct vsc9953_rew_reg {
|
||||||
|
struct vsc9953_rew_port port[12];
|
||||||
|
struct vsc9953_rew_common common;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* END VSC9953 REW structure */
|
||||||
|
|
||||||
/* VSC9953 DEVCPU_GCB structure */
|
/* VSC9953 DEVCPU_GCB structure */
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue