[U-Boot] [PATCH 03/11 v2] drivers/net/vsc9953: Add default configuration for VSC9953 L2 Switch
Joe Hershberger
joe.hershberger at gmail.com
Thu Jun 25 21:25:17 CEST 2015
Hi Codrin,
On Tue, Jun 23, 2015 at 11:48 AM, Codrin Ciubotariu
<codrin.ciubotariu at freescale.com> wrote:
> 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 at freescale.com>
> Signed-off-by: Codrin Ciubotariu <codrin.ciubotariu at freescale.com>
> ---
> Changes for v2:
> - removed Change-id field;
>
> drivers/net/vsc9953.c | 266 +++++++++++++++++++++++++++++++++++++++++++++++++-
> include/vsc9953.h | 61 +++++++++++-
> 2 files changed, 325 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/net/vsc9953.c b/drivers/net/vsc9953.c
> index 720ae47..9dec683 100644
> --- a/drivers/net/vsc9953.c
> +++ b/drivers/net/vsc9953.c
> @@ -1,5 +1,5 @@
> /*
> - * Copyright 2014 Freescale Semiconductor, Inc.
> + * Copyright 2014-2015 Freescale Semiconductor, Inc.
> *
> * SPDX-License-Identifier: GPL-2.0+
> *
> @@ -176,6 +176,268 @@ static int vsc9953_port_init(int port_no)
> 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) &
> + CONFIG_VSC9953_VLAN_CMD_MASK) !=
> + CONFIG_VSC9953_VLAN_CMD_IDLE) && --timeout)
> + udelay(1);
> +
> + return !!timeout;
Maybe this:
+ return timeout ? 0 : -EBUSY;
> +}
> +
> +/* vlan table set/clear all membership of vid */
> +static void vsc9953_vlan_table_membership_all_set(int vid, int set)
> +{
> + struct vsc9953_analyzer *l2ana_reg;
> +
> + l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
> + VSC9953_ANA_OFFSET);
> +
> + if (!vsc9953_vlan_table_poll_idle()) {
If you accept the above, you need to change these to:
+ if (vsc9953_vlan_table_poll_idle() < 0) {
or
+ if (vsc9953_vlan_table_poll_idle() == -EBUSY) {
> + debug("VLAN table timeout\n");
> + return;
> + }
> +
> + /* read current vlan configuration */
> + clrsetbits_le32(&l2ana_reg->ana_tables.vlan_tidx,
> + CONFIG_VSC9953_ANA_TBL_VID_MASK,
> + field_set(vid, CONFIG_VSC9953_ANA_TBL_VID_MASK));
> +
> + clrsetbits_le32(&l2ana_reg->ana_tables.vlan_access,
> + CONFIG_VSC9953_VLAN_CMD_MASK,
> + field_set(CONFIG_VSC9953_VLAN_CMD_READ,
> + CONFIG_VSC9953_VLAN_CMD_MASK));
> +
> + if (!vsc9953_vlan_table_poll_idle()) {
Here too.
> + debug("VLAN table timeout\n");
> + return;
> + }
> +
> + clrsetbits_le32(&l2ana_reg->ana_tables.vlan_tidx,
> + CONFIG_VSC9953_ANA_TBL_VID_MASK,
> + field_set(vid, CONFIG_VSC9953_ANA_TBL_VID_MASK));
> +
> + if (!set)
> + clrsetbits_le32(&l2ana_reg->ana_tables.vlan_access,
> + CONFIG_VSC9953_VLAN_PORT_MASK |
> + CONFIG_VSC9953_VLAN_CMD_MASK,
> + field_set(CONFIG_VSC9953_VLAN_CMD_WRITE,
> + CONFIG_VSC9953_VLAN_CMD_MASK));
> + else
> + clrsetbits_le32(&l2ana_reg->ana_tables.vlan_access,
> + CONFIG_VSC9953_VLAN_PORT_MASK |
> + CONFIG_VSC9953_VLAN_CMD_MASK,
> + field_set(CONFIG_VSC9953_VLAN_CMD_WRITE,
> + CONFIG_VSC9953_VLAN_CMD_MASK) |
> + CONFIG_VSC9953_VLAN_PORT_MASK);
It seems this could if statement could all be simplified as:
+ clrsetbits_le32(&l2ana_reg->ana_tables.vlan_access,
+ CONFIG_VSC9953_VLAN_PORT_MASK |
+ CONFIG_VSC9953_VLAN_CMD_MASK,
+ field_set(CONFIG_VSC9953_VLAN_CMD_WRITE,
+ CONFIG_VSC9953_VLAN_CMD_MASK) |
+ (set ? CONFIG_VSC9953_VLAN_PORT_MASK : 0));
It may also help to rename the parameter from "set" to something like
"set_member".
> +}
> +
> +/* Set PVID for a VSC9953 port */
> +static void vsc9953_port_vlan_pvid_set(int port_no, int pvid)
> +{
> + struct vsc9953_analyzer *l2ana_reg;
> + struct vsc9953_rew_reg *l2rew_reg;
> +
> + /* Administrative down */
> + if ((!vsc9953_l2sw.port[port_no].enabled)) {
Why do you have double "((" and "))"?
> + 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 */
> + clrsetbits_le32(&l2ana_reg->port[port_no].vlan_cfg,
> + CONFIG_VSC9953_VLAN_CFG_VID_MASK,
> + field_set(pvid, CONFIG_VSC9953_VLAN_CFG_VID_MASK));
> +
> + /* Set PVID on egress */
> + clrsetbits_le32(&l2rew_reg->port[port_no].port_vlan_cfg,
> + CONFIG_VSC9953_PORT_VLAN_CFG_VID_MASK,
> + field_set(pvid, CONFIG_VSC9953_PORT_VLAN_CFG_VID_MASK));
> +}
> +
> +static void vsc9953_port_all_vlan_pvid_set(int pvid)
> +{
> + int i;
Use a single space.
> +
> + 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,
> + CONFIG_VSC9953_VLAN_CFG_AWARE_ENA);
> + else
> + clrbits_le32(&l2ana_reg->port[port_no].vlan_cfg,
> + CONFIG_VSC9953_VLAN_CFG_AWARE_ENA);
> +}
> +
> +/* Set all VSC9953 ports' vlan aware */
> +static void vsc9953_port_all_vlan_aware_set(int enabled)
> +{
> + int i;
Use a single space.
> +
> + 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)
> +{
> + struct vsc9953_analyzer *l2ana_reg;
Use a single space.
> +
> + /* 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);
> +
> + clrsetbits_le32(&l2ana_reg->port[port_no].vlan_cfg,
> + CONFIG_VSC9953_VLAN_CFG_POP_CNT_MASK,
> + field_set(popcnt,
> + CONFIG_VSC9953_VLAN_CFG_POP_CNT_MASK));
> +}
> +
> +/* Set all VSC9953 ports' pop count */
> +static void vsc9953_port_all_vlan_poncnt_set(int popcnt)
> +{
> + int i;
Use a single space.
> +
> + 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;
Use a single space.
> +
> + l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
> + VSC9953_ANA_OFFSET);
> +
> + if (enable)
> + setbits_le32(&l2ana_reg->ana.adv_learn,
> + CONFIG_VSC9953_VLAN_CHK);
> + else
> + clrbits_le32(&l2ana_reg->ana.adv_learn,
> + CONFIG_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;
Use a single space.
> +
> + /* 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,
> + CONFIG_VSC9953_TAG_CFG_MASK,
> + CONFIG_VSC9953_TAG_CFG_NONE);
> + break;
> + case EGRESS_UNTAG_PVID_AND_ZERO:
> + clrsetbits_le32(&l2rew_reg->port[port_no].port_tag_cfg,
> + CONFIG_VSC9953_TAG_CFG_MASK,
> + CONFIG_VSC9953_TAG_CFG_ALL_PVID_ZERO);
This seems like the naming is inverted. The enum value is called
"untag" pvid and zero, but the config is called "tag" all pvid and
zero. Is this a bug or just poorly named constants / enum values?
> + break;
> + case EGRESS_UNTAG_ZERO:
> + clrsetbits_le32(&l2rew_reg->port[port_no].port_tag_cfg,
> + CONFIG_VSC9953_TAG_CFG_MASK,
> + CONFIG_VSC9953_TAG_CFG_ALL_ZERO);
Also here.
> + break;
> + case EGRESS_UNTAG_NONE:
> + clrsetbits_le32(&l2rew_reg->port[port_no].port_tag_cfg,
> + CONFIG_VSC9953_TAG_CFG_MASK,
> + CONFIG_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;
Use a single space.
> +
> + 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)
> {
> u32 i, hdx_cfg = 0, phy_addr = 0;
> @@ -306,6 +568,8 @@ void vsc9953_init(bd_t *bis)
> }
> }
>
> + vsc9953_default_configuration();
> +
> printf("VSC9953 L2 switch initialized\n");
> return;
> }
> diff --git a/include/vsc9953.h b/include/vsc9953.h
> index 2b88c5c..bf81623 100644
> --- a/include/vsc9953.h
> +++ b/include/vsc9953.h
> @@ -7,7 +7,7 @@
> * terms of the GNU Public License, Version 2, incorporated
> * herein by reference.
> *
> - * Copyright 2013 Freescale Semiconductor, Inc.
> + * Copyright 2013, 2015 Freescale Semiconductor, Inc.
> *
> */
>
> @@ -19,9 +19,13 @@
> #include <asm/types.h>
> #include <malloc.h>
>
> +#define field_set(val, mask) ((val) * ((mask) & ~((mask) << 1)))
> +#define field_get(val, mask) ((val) / ((mask) & ~((mask) << 1)))
I don't follow why this is unique to this chip? Also, get is never
used. Is it just for completeness, I assume.
I think you should either be using the functions in include/bitfield.h
or you should be adding these there instead of here. If you decide to
add them there, then naturally do it as a separate patch and with good
comments and naming consistent with that file and as functions not
macros. This method is nice in that you use the mask to define the
shift instead of requiring it as a separate constant.
> +
> #define VSC9953_OFFSET (CONFIG_SYS_CCSRBAR_DEFAULT + 0x800000)
>
> #define VSC9953_SYS_OFFSET 0x010000
> +#define VSC9953_REW_OFFSET 0x030000
> #define VSC9953_DEV_GMII_OFFSET 0x100000
> #define VSC9953_QSYS_OFFSET 0x200000
> #define VSC9953_ANA_OFFSET 0x280000
> @@ -84,9 +88,38 @@
> #define CONFIG_VSC9953_VCAP_MV_CFG 0x0000ffff
> #define CONFIG_VSC9953_VCAP_UPDATE_CTRL 0x01000004
>
> +/* Macros for vsc9953_ana_port.vlan_cfg register */
> +#define CONFIG_VSC9953_VLAN_CFG_AWARE_ENA 0x00100000
> +#define CONFIG_VSC9953_VLAN_CFG_POP_CNT_MASK 0x000c0000
> +#define CONFIG_VSC9953_VLAN_CFG_VID_MASK 0x00000fff
> +
> +/* Macros for vsc9953_rew_port.port_vlan_cfg register */
> +#define CONFIG_VSC9953_PORT_VLAN_CFG_VID_MASK 0x00000fff
> +
> +/* Macros for vsc9953_ana_ana_tables.vlan_tidx register */
> +#define CONFIG_VSC9953_ANA_TBL_VID_MASK 0x00000fff
> +
> +/* Macros for vsc9953_ana_ana_tables.vlan_access register */
> +#define CONFIG_VSC9953_VLAN_PORT_MASK 0x00001ffc
> +#define CONFIG_VSC9953_VLAN_CMD_MASK 0x00000003
> +#define CONFIG_VSC9953_VLAN_CMD_IDLE 0x00000000
> +#define CONFIG_VSC9953_VLAN_CMD_READ 0x00000001
> +#define CONFIG_VSC9953_VLAN_CMD_WRITE 0x00000002
> +#define CONFIG_VSC9953_VLAN_CMD_INIT 0x00000003
> +
> /* Macros for vsc9953_qsys_sys.switch_port_mode register */
> #define CONFIG_VSC9953_PORT_ENA 0x00002000
>
> +/* Macros for vsc9953_ana_ana.adv_learn register */
> +#define CONFIG_VSC9953_VLAN_CHK 0x00000400
> +
> +/* Macros for vsc9953_rew_port.port_tag_cfg register */
> +#define CONFIG_VSC9953_TAG_CFG_MASK 0x00000180
> +#define CONFIG_VSC9953_TAG_CFG_NONE 0x00000000
> +#define CONFIG_VSC9953_TAG_CFG_ALL_PVID_ZERO 0x00000080
> +#define CONFIG_VSC9953_TAG_CFG_ALL_ZERO 0x00000100
> +#define CONFIG_VSC9953_TAG_CFG_ALL 0x00000180
> +
> #define VSC9953_MAX_PORTS 10
> #define VSC9953_PORT_CHECK(port) \
> (((port) < 0 || (port) >= VSC9953_MAX_PORTS) ? 0 : 1)
> @@ -95,6 +128,9 @@
> (port) < VSC9953_MAX_PORTS - 2 || (port) >= VSC9953_MAX_PORTS \
> ) ? 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"
>
> @@ -342,6 +378,29 @@ struct vsc9953_system_reg {
>
> /* END VSC9953 SYS structure for T1040 U-boot*/
>
> +/* VSC9953 REW structure for T1040 U-boot*/
> +
> +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];
Seems like you should drop the "port_" from all of these member names.
> + 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 for T1040 U-boot*/
These comments seem gratuitous and not particularly relevant (begin
and end). Perhaps either remove them throughout the file or at least
don't add more. At the very least, drop the " structure for T1040
U-boot" which isn't helpful or accurate.
>
> /* VSC9953 DEVCPU_GCB structure for T1040 U-boot*/
>
> --
> 1.9.3
>
> _______________________________________________
> U-Boot mailing list
> U-Boot at lists.denx.de
> http://lists.denx.de/mailman/listinfo/u-boot
More information about the U-Boot
mailing list