器件型号: TDA4VH-Q1
默认情况下、CPSW 不按原样传递 VID 0(有优先级标记)帧。 Linux 驱动程序在入口 和出口处剥离或替换 VID 0、因此对于需要在 线路上设置优先级位的 VID 0 的用例而言、不可能。
This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
器件型号: TDA4VH-Q1
默认情况下、CPSW 不按原样传递 VID 0(有优先级标记)帧。 Linux 驱动程序在入口 和出口处剥离或替换 VID 0、因此对于需要在 线路上设置优先级位的 VID 0 的用例而言、不可能。
以下是 CPSW 阻止 VID 0 直通的原因。
入口 — PVID 替代: CPSW 控制寄存器具有每个端口的 PASS_PRI_Tagged 位(位 3-11,每个端口一个)。 如果 未设置这些参数、一个优先级标记的帧、VID 0 到达任何端口、其 VID 0 将替换为该端口的 已配置 PVID。 另外、ALE 具有 VID 0 模式 (ALE_NO_PORT_VLAN)、控制 VID 0 入口数据包是作为 VID 0 处理、还是重新映射到端口的 VLAN。 两者都默认为 PVID 替代。
出口 — 标签剥离:在驱动程序初始化时,使用强制未标记数据包出站 = 0x7f (所有端口)创建默认 ALE VLAN 0 条目。 这会在每个出口端口上剥离 VID 0 标记、因此有优先级标记的帧永远不会出现在线路上。
泛洪 — VID 0 无 ALE 进入/学习: ALE MAC 学习是按 VLAN 进行的。 Linux 内核保留 VID 0 并拒绝任何 在网桥或网络接口上配置它的尝试(网桥 VLAN 添加 vid 0 会返回错误)。 因此、不会 为 VID 0 创建 ALE 条目、ALE 在 VID 0 下没有单播条目、所有 VID 0 单播通信将 通过 VID 0 成员掩码中的每个端口泛洪。
修复:
CPSW Linux 驱动程序 (am65-cpsw-nuss.c) 中需要以下 chages 才能按原样传递 VLAN 0 数据包。
——
更改 1 — 设置 CPSW 控制寄存器中的 PASS_PRI_Tagged 位
添加每端口 pass_pri_tagged 定义并与现有的 VLAN_Aware 和 P0_R0_ENABLE 位一起设置它们。 该命令指示 CPSW 硬件转发有优先级标记的帧、而不使用端口 PVID 替换 VID 0。
--- a/drivers/net/ethernet/ti/am65-cpsw-nuss.c +++ b/drivers/net/ethernet/ti/am65-cpsw-nuss.c @@ -87,6 +87,15 @@ #define AM65_CPSW_CTL_VLAN_AWARE BIT(1) #define AM65_CPSW_CTL_P0_ENABLE BIT(2) +#define AM65_CPSW_CTL_P0_PASS_PRI_TAGGED BIT(3) +#define AM65_CPSW_CTL_P1_PASS_PRI_TAGGED BIT(4) +#define AM65_CPSW_CTL_P2_PASS_PRI_TAGGED BIT(5) +#define AM65_CPSW_CTL_P3_PASS_PRI_TAGGED BIT(6) +#define AM65_CPSW_CTL_P4_PASS_PRI_TAGGED BIT(7) +#define AM65_CPSW_CTL_P5_PASS_PRI_TAGGED BIT(8) +#define AM65_CPSW_CTL_P6_PASS_PRI_TAGGED BIT(9) +#define AM65_CPSW_CTL_P7_PASS_PRI_TAGGED BIT(10) +#define AM65_CPSW_CTL_P8_PASS_PRI_TAGGED BIT(11) #define AM65_CPSW_CTL_P0_TX_CRC_REMOVE BIT(13) #define AM65_CPSW_CTL_P0_RX_PAD BIT(14) @@ -739,7 +748,16 @@ static int am65_cpsw_nuss_common_open(struct am65_cpsw_common *common) /* Control register */ writel(AM65_CPSW_CTL_P0_ENABLE | AM65_CPSW_CTL_P0_TX_CRC_REMOVE | - AM65_CPSW_CTL_P0_RX_PAD, + AM65_CPSW_CTL_VLAN_AWARE | AM65_CPSW_CTL_P0_RX_PAD | + AM65_CPSW_CTL_P0_PASS_PRI_TAGGED | + AM65_CPSW_CTL_P1_PASS_PRI_TAGGED | + AM65_CPSW_CTL_P2_PASS_PRI_TAGGED | + AM65_CPSW_CTL_P3_PASS_PRI_TAGGED | + AM65_CPSW_CTL_P4_PASS_PRI_TAGGED | + AM65_CPSW_CTL_P5_PASS_PRI_TAGGED | + AM65_CPSW_CTL_P6_PASS_PRI_TAGGED | + AM65_CPSW_CTL_P7_PASS_PRI_TAGGED | + AM65_CPSW_CTL_P8_PASS_PRI_TAGGED, common->cpsw_base + AM65_CPSW_REG_CTL);
设置 CPSW ALE 控制寄存器中的 ALE_NO_PORT_VLAN、以便 ALE 将 VID 0 入口数据包视为 VID 0、而不会重新映射到端口的 VLAN。
--- a/drivers/net/ethernet/ti/am65-cpsw-nuss.c +++ b/drivers/net/ethernet/ti/am65-cpsw-nuss.c @@ -2987,6 +2987,10 @@ static void am65_cpsw_init_host_port_switch(struct am65_cpsw_common *common) cpsw_ale_control_set(common->ale, HOST_PORT_NUM, ALE_P0_UNI_FLOOD, 1); dev_dbg(common->dev, "Set P0_UNI_FLOOD\n"); + + cpsw_ale_control_set(common->ale, HOST_PORT_NUM, ALE_NO_PORT_VLAN, 1); + dev_dbg(common->dev, "Set VLAN 0 Mode\n"); + cpsw_ale_control_set(common->ale, HOST_PORT_NUM, ALE_PORT_NOLEARN, 0);
——
更改 3 — 清除 ALE VID 0 条目上的强制未标记出口掩码
默认的 ALE VID 0 条目是使用 untag = ALE_ALL_PORTS (0x7f) 创建的、它在每个出口 端口上条目 VID 0 标签。 相反、传递 untag = 0、这样 VID 0 数据包离开时其 VLAN 标记完好无损。
@@ -782,7 +800,7 @@ static int am65_cpsw_nuss_common_open(struct am65_cpsw_common *common) ~common->disabled_ports_mask; cpsw_ale_add_vlan(common->ale, 0, port_mask, - port_mask, port_mask, + 0, port_mask, port_mask & ~ALE_PORT_HOST);
——
更改 4-为每个外部端口的 VID 0 添加静态主机端口 ALE 条目
在 VID 0 下为每个外部端口添加主机 MAC 的单播和多播 ALE 条目。 如果没有这些、ALE 将不会 对 VID 0 通信进行单播匹配、并将其泛洪到所有成员端口上。
--- a/drivers/net/ethernet/ti/am65-cpsw-nuss.c +++ b/drivers/net/ethernet/ti/am65-cpsw-nuss.c @@ -3059,12 +3059,20 @@ static void am65_cpsw_init_port_switch_ale(struct am65_cpsw_port *port) HOST_PORT_NUM, ALE_SECURE | ALE_BLOCKED | ALE_VLAN, slave->port_vlan); + cpsw_ale_add_ucast(cpsw->ale, port->ndev->dev_addr, + HOST_PORT_NUM, ALE_SECURE | ALE_BLOCKED | ALE_VLAN, + 0); + port_mask = BIT(port->port_id) | ALE_PORT_HOST; cpsw_ale_add_mcast(cpsw->ale, port->ndev->broadcast, port_mask, ALE_VLAN, slave->port_vlan, ALE_MCAST_FWD_2); + cpsw_ale_add_mcast(cpsw->ale, port->ndev->broadcast, + port_mask, ALE_VLAN, 0, + ALE_MCAST_FWD_2); + writel(slave->port_vlan, port->port_base + AM65_CPSW_PORT_VLAN_REG_OFFSET); cpsw_ale_control_set(cpsw->ale, port->port_id,