Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'net-dsa-yt921x-add-dcb-qos-support'

David Yang says:

====================
net: dsa: yt921x: Add DCB/QoS support

This series add DCB/QoS support to the driver.

v5: https://lore.kernel.org/r/20260128215202.2244266-1-mmyangfl@gmail.com
v4: https://lore.kernel.org/r/20260127020847.1482724-1-mmyangfl@gmail.com
v3: https://lore.kernel.org/r/20260125001328.3784006-1-mmyangfl@gmail.com
v2: https://lore.kernel.org/r/20260122194233.2777550-1-mmyangfl@gmail.com
v1: https://lore.kernel.org/r/20260119185935.2072685-1-mmyangfl@gmail.com
====================

Link: https://patch.msgid.link/20260131021854.3405036-1-mmyangfl@gmail.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>

+393 -62
+1
drivers/net/dsa/Kconfig
··· 158 158 config NET_DSA_YT921X 159 159 tristate "Motorcomm YT9215 ethernet switch chip support" 160 160 select NET_DSA_TAG_YT921X 161 + select NET_IEEE8021Q_HELPERS if DCB 161 162 help 162 163 This enables support for the Motorcomm YT9215 ethernet switch 163 164 chip.
+289 -21
drivers/net/dsa/yt921x.c
··· 8 8 * Copyright (c) 2025 David Yang 9 9 */ 10 10 11 + #include <linux/dcbnl.h> 11 12 #include <linux/etherdevice.h> 12 13 #include <linux/if_bridge.h> 13 14 #include <linux/if_hsr.h> ··· 19 18 #include <linux/of.h> 20 19 #include <linux/of_mdio.h> 21 20 #include <linux/of_net.h> 21 + #include <linux/sort.h> 22 22 23 23 #include <net/dsa.h> 24 + #include <net/dscp.h> 25 + #include <net/ieee8021q.h> 24 26 25 27 #include "yt921x.h" 26 28 ··· 1774 1770 } 1775 1771 1776 1772 static int 1773 + yt921x_vlan_aware_set(struct yt921x_priv *priv, int port, bool vlan_aware) 1774 + { 1775 + u32 ctrl; 1776 + 1777 + /* Abuse SVLAN for PCP parsing without polluting the FDB - it just works 1778 + * despite YT921X_VLAN_CTRL_SVLAN_EN never being set 1779 + */ 1780 + if (!vlan_aware) 1781 + ctrl = YT921X_PORT_IGR_TPIDn_STAG(0); 1782 + else 1783 + ctrl = YT921X_PORT_IGR_TPIDn_CTAG(0); 1784 + return yt921x_reg_write(priv, YT921X_PORTn_IGR_TPID(port), ctrl); 1785 + } 1786 + 1787 + static int 1777 1788 yt921x_port_set_pvid(struct yt921x_priv *priv, int port, u16 vid) 1778 1789 { 1779 1790 u32 mask; ··· 1837 1818 if (res) 1838 1819 return res; 1839 1820 1840 - /* Turn on / off VLAN awareness */ 1841 - mask = YT921X_PORT_IGR_TPIDn_CTAG_M; 1842 - if (!vlan_filtering) 1843 - ctrl = 0; 1844 - else 1845 - ctrl = YT921X_PORT_IGR_TPIDn_CTAG(0); 1846 - res = yt921x_reg_update_bits(priv, YT921X_PORTn_IGR_TPID(port), 1847 - mask, ctrl); 1821 + res = yt921x_vlan_aware_set(priv, port, vlan_filtering); 1848 1822 if (res) 1849 1823 return res; 1850 1824 ··· 2034 2022 return res; 2035 2023 2036 2024 /* Turn off VLAN awareness */ 2037 - mask = YT921X_PORT_IGR_TPIDn_CTAG_M; 2038 - res = yt921x_reg_clear_bits(priv, YT921X_PORTn_IGR_TPID(port), mask); 2025 + res = yt921x_vlan_aware_set(priv, port, false); 2039 2026 if (res) 2040 2027 return res; 2041 2028 ··· 2403 2392 port, res); 2404 2393 } 2405 2394 2395 + static int __maybe_unused 2396 + yt921x_dsa_port_get_default_prio(struct dsa_switch *ds, int port) 2397 + { 2398 + struct yt921x_priv *priv = to_yt921x_priv(ds); 2399 + u32 val; 2400 + int res; 2401 + 2402 + mutex_lock(&priv->reg_lock); 2403 + res = yt921x_reg_read(priv, YT921X_PORTn_QOS(port), &val); 2404 + mutex_unlock(&priv->reg_lock); 2405 + 2406 + if (res) 2407 + return res; 2408 + 2409 + return FIELD_GET(YT921X_PORT_QOS_PRIO_M, val); 2410 + } 2411 + 2412 + static int __maybe_unused 2413 + yt921x_dsa_port_set_default_prio(struct dsa_switch *ds, int port, u8 prio) 2414 + { 2415 + struct yt921x_priv *priv = to_yt921x_priv(ds); 2416 + u32 mask; 2417 + u32 ctrl; 2418 + int res; 2419 + 2420 + if (prio >= YT921X_PRIO_NUM) 2421 + return -EINVAL; 2422 + 2423 + mutex_lock(&priv->reg_lock); 2424 + mask = YT921X_PORT_QOS_PRIO_M | YT921X_PORT_QOS_PRIO_EN; 2425 + ctrl = YT921X_PORT_QOS_PRIO(prio) | YT921X_PORT_QOS_PRIO_EN; 2426 + res = yt921x_reg_update_bits(priv, YT921X_PORTn_QOS(port), mask, ctrl); 2427 + mutex_unlock(&priv->reg_lock); 2428 + 2429 + return res; 2430 + } 2431 + 2432 + static int __maybe_unused appprios_cmp(const void *a, const void *b) 2433 + { 2434 + return ((const u8 *)b)[1] - ((const u8 *)a)[1]; 2435 + } 2436 + 2437 + static int __maybe_unused 2438 + yt921x_dsa_port_get_apptrust(struct dsa_switch *ds, int port, u8 *sel, 2439 + int *nselp) 2440 + { 2441 + struct yt921x_priv *priv = to_yt921x_priv(ds); 2442 + u8 appprios[2][2] = {}; 2443 + int nsel; 2444 + u32 val; 2445 + int res; 2446 + 2447 + mutex_lock(&priv->reg_lock); 2448 + res = yt921x_reg_read(priv, YT921X_PORTn_PRIO_ORD(port), &val); 2449 + mutex_unlock(&priv->reg_lock); 2450 + 2451 + if (res) 2452 + return res; 2453 + 2454 + appprios[0][0] = IEEE_8021QAZ_APP_SEL_DSCP; 2455 + appprios[0][1] = (val >> (3 * YT921X_APP_SEL_DSCP)) & 7; 2456 + appprios[1][0] = DCB_APP_SEL_PCP; 2457 + appprios[1][1] = (val >> (3 * YT921X_APP_SEL_CVLAN_PCP)) & 7; 2458 + sort(appprios, ARRAY_SIZE(appprios), sizeof(appprios[0]), appprios_cmp, 2459 + NULL); 2460 + 2461 + nsel = 0; 2462 + for (int i = 0; i < ARRAY_SIZE(appprios) && appprios[i][1]; i++) { 2463 + sel[nsel] = appprios[i][0]; 2464 + nsel++; 2465 + } 2466 + *nselp = nsel; 2467 + 2468 + return 0; 2469 + } 2470 + 2471 + static int __maybe_unused 2472 + yt921x_dsa_port_set_apptrust(struct dsa_switch *ds, int port, const u8 *sel, 2473 + int nsel) 2474 + { 2475 + struct yt921x_priv *priv = to_yt921x_priv(ds); 2476 + struct device *dev = to_device(priv); 2477 + u32 ctrl; 2478 + int res; 2479 + 2480 + if (nsel > YT921X_APP_SEL_NUM) 2481 + return -EINVAL; 2482 + 2483 + ctrl = 0; 2484 + for (int i = 0; i < nsel; i++) { 2485 + switch (sel[i]) { 2486 + case IEEE_8021QAZ_APP_SEL_DSCP: 2487 + ctrl |= YT921X_PORT_PRIO_ORD_APPm(YT921X_APP_SEL_DSCP, 2488 + 7 - i); 2489 + break; 2490 + case DCB_APP_SEL_PCP: 2491 + ctrl |= YT921X_PORT_PRIO_ORD_APPm(YT921X_APP_SEL_CVLAN_PCP, 2492 + 7 - i); 2493 + ctrl |= YT921X_PORT_PRIO_ORD_APPm(YT921X_APP_SEL_SVLAN_PCP, 2494 + 7 - i); 2495 + break; 2496 + default: 2497 + dev_err(dev, 2498 + "Invalid apptrust selector (at %d-th). Supported: dscp, pcp\n", 2499 + i + 1); 2500 + return -EOPNOTSUPP; 2501 + } 2502 + } 2503 + 2504 + mutex_lock(&priv->reg_lock); 2505 + res = yt921x_reg_write(priv, YT921X_PORTn_PRIO_ORD(port), ctrl); 2506 + mutex_unlock(&priv->reg_lock); 2507 + 2508 + return res; 2509 + } 2510 + 2406 2511 static int yt921x_port_down(struct yt921x_priv *priv, int port) 2407 2512 { 2408 2513 u32 mask; ··· 2843 2716 if (res) 2844 2717 return res; 2845 2718 2719 + /* Clear prio order (even if DCB is not enabled) to avoid unsolicited 2720 + * priorities 2721 + */ 2722 + res = yt921x_reg_write(priv, YT921X_PORTn_PRIO_ORD(port), 0); 2723 + if (res) 2724 + return res; 2725 + 2846 2726 if (dsa_is_cpu_port(ds, port)) { 2847 2727 /* Egress of CPU port is supposed to be completely controlled 2848 2728 * via tagging, so set to oneway isolated (drop all packets ··· 2888 2754 2889 2755 mutex_lock(&priv->reg_lock); 2890 2756 res = yt921x_port_setup(priv, port); 2757 + mutex_unlock(&priv->reg_lock); 2758 + 2759 + return res; 2760 + } 2761 + 2762 + /* Not "port" - DSCP mapping is global */ 2763 + static int __maybe_unused 2764 + yt921x_dsa_port_get_dscp_prio(struct dsa_switch *ds, int port, u8 dscp) 2765 + { 2766 + struct yt921x_priv *priv = to_yt921x_priv(ds); 2767 + u32 val; 2768 + int res; 2769 + 2770 + mutex_lock(&priv->reg_lock); 2771 + res = yt921x_reg_read(priv, YT921X_IPM_DSCPn(dscp), &val); 2772 + mutex_unlock(&priv->reg_lock); 2773 + 2774 + if (res) 2775 + return res; 2776 + 2777 + return FIELD_GET(YT921X_IPM_PRIO_M, val); 2778 + } 2779 + 2780 + static int __maybe_unused 2781 + yt921x_dsa_port_del_dscp_prio(struct dsa_switch *ds, int port, u8 dscp, u8 prio) 2782 + { 2783 + struct yt921x_priv *priv = to_yt921x_priv(ds); 2784 + u32 val; 2785 + int res; 2786 + 2787 + mutex_lock(&priv->reg_lock); 2788 + /* During a "dcb app replace" command, the new app table entry will be 2789 + * added first, then the old one will be deleted. But the hardware only 2790 + * supports one QoS class per DSCP value (duh), so if we blindly delete 2791 + * the app table entry for this DSCP value, we end up deleting the 2792 + * entry with the new priority. Avoid that by checking whether user 2793 + * space wants to delete the priority which is currently configured, or 2794 + * something else which is no longer current. 2795 + */ 2796 + res = yt921x_reg_read(priv, YT921X_IPM_DSCPn(dscp), &val); 2797 + if (!res && FIELD_GET(YT921X_IPM_PRIO_M, val) == prio) 2798 + res = yt921x_reg_write(priv, YT921X_IPM_DSCPn(dscp), 2799 + YT921X_IPM_PRIO(IEEE8021Q_TT_BK)); 2800 + mutex_unlock(&priv->reg_lock); 2801 + 2802 + return res; 2803 + } 2804 + 2805 + static int __maybe_unused 2806 + yt921x_dsa_port_add_dscp_prio(struct dsa_switch *ds, int port, u8 dscp, u8 prio) 2807 + { 2808 + struct yt921x_priv *priv = to_yt921x_priv(ds); 2809 + int res; 2810 + 2811 + if (prio >= YT921X_PRIO_NUM) 2812 + return -EINVAL; 2813 + 2814 + mutex_lock(&priv->reg_lock); 2815 + res = yt921x_reg_write(priv, YT921X_IPM_DSCPn(dscp), 2816 + YT921X_IPM_PRIO(prio)); 2891 2817 mutex_unlock(&priv->reg_lock); 2892 2818 2893 2819 return res; ··· 3092 2898 return 0; 3093 2899 } 3094 2900 3095 - static int yt921x_chip_setup(struct yt921x_priv *priv) 2901 + static int yt921x_chip_setup_dsa(struct yt921x_priv *priv) 3096 2902 { 3097 2903 struct dsa_switch *ds = &priv->ds; 3098 2904 unsigned long cpu_ports_mask; ··· 3107 2913 ctrl = YT921X_EXT_CPU_PORT_TAG_EN | YT921X_EXT_CPU_PORT_PORT_EN | 3108 2914 YT921X_EXT_CPU_PORT_PORT(__ffs(priv->cpu_ports_mask)); 3109 2915 res = yt921x_reg_write(priv, YT921X_EXT_CPU_PORT, ctrl); 3110 - if (res) 3111 - return res; 3112 - 3113 - /* Enable and clear MIB */ 3114 - res = yt921x_reg_set_bits(priv, YT921X_FUNC, YT921X_FUNC_MIB); 3115 - if (res) 3116 - return res; 3117 - 3118 - ctrl = YT921X_MIB_CTRL_CLEAN | YT921X_MIB_CTRL_ALL_PORT; 3119 - res = yt921x_reg_write(priv, YT921X_MIB_CTRL, ctrl); 3120 2916 if (res) 3121 2917 return res; 3122 2918 ··· 3159 2975 */ 3160 2976 ctrl64 = YT921X_VLAN_CTRL_LEARN_DIS | YT921X_VLAN_CTRL_PORTS_M; 3161 2977 res = yt921x_reg64_write(priv, YT921X_VLANn_CTRL(0), ctrl64); 2978 + if (res) 2979 + return res; 2980 + 2981 + return 0; 2982 + } 2983 + 2984 + static int __maybe_unused yt921x_chip_setup_qos(struct yt921x_priv *priv) 2985 + { 2986 + u32 ctrl; 2987 + int res; 2988 + 2989 + /* DSCP to internal priorities */ 2990 + for (u8 dscp = 0; dscp < DSCP_MAX; dscp++) { 2991 + int prio = ietf_dscp_to_ieee8021q_tt(dscp); 2992 + 2993 + if (prio < 0) 2994 + return prio; 2995 + 2996 + res = yt921x_reg_write(priv, YT921X_IPM_DSCPn(dscp), 2997 + YT921X_IPM_PRIO(prio)); 2998 + if (res) 2999 + return res; 3000 + } 3001 + 3002 + /* 802.1Q QoS to internal priorities */ 3003 + for (u8 pcp = 0; pcp < 8; pcp++) 3004 + for (u8 dei = 0; dei < 2; dei++) { 3005 + ctrl = YT921X_IPM_PRIO(pcp); 3006 + if (dei) 3007 + /* "Red" almost means drop, so it's not that 3008 + * useful. Note that tc police does not support 3009 + * Three-Color very well 3010 + */ 3011 + ctrl |= YT921X_IPM_COLOR_YELLOW; 3012 + 3013 + for (u8 svlan = 0; svlan < 2; svlan++) { 3014 + u32 reg = YT921X_IPM_PCPn(svlan, dei, pcp); 3015 + 3016 + res = yt921x_reg_write(priv, reg, ctrl); 3017 + if (res) 3018 + return res; 3019 + } 3020 + } 3021 + 3022 + return 0; 3023 + } 3024 + 3025 + static int yt921x_chip_setup(struct yt921x_priv *priv) 3026 + { 3027 + u32 ctrl; 3028 + int res; 3029 + 3030 + ctrl = YT921X_FUNC_MIB; 3031 + res = yt921x_reg_set_bits(priv, YT921X_FUNC, ctrl); 3032 + if (res) 3033 + return res; 3034 + 3035 + res = yt921x_chip_setup_dsa(priv); 3036 + if (res) 3037 + return res; 3038 + 3039 + #if IS_ENABLED(CONFIG_DCB) 3040 + res = yt921x_chip_setup_qos(priv); 3041 + if (res) 3042 + return res; 3043 + #endif 3044 + 3045 + /* Clear MIB */ 3046 + ctrl = YT921X_MIB_CTRL_CLEAN | YT921X_MIB_CTRL_ALL_PORT; 3047 + res = yt921x_reg_write(priv, YT921X_MIB_CTRL, ctrl); 3162 3048 if (res) 3163 3049 return res; 3164 3050 ··· 3341 3087 .port_mst_state_set = yt921x_dsa_port_mst_state_set, 3342 3088 .vlan_msti_set = yt921x_dsa_vlan_msti_set, 3343 3089 .port_stp_state_set = yt921x_dsa_port_stp_state_set, 3090 + #if IS_ENABLED(CONFIG_DCB) 3091 + /* dcb */ 3092 + .port_get_default_prio = yt921x_dsa_port_get_default_prio, 3093 + .port_set_default_prio = yt921x_dsa_port_set_default_prio, 3094 + .port_get_apptrust = yt921x_dsa_port_get_apptrust, 3095 + .port_set_apptrust = yt921x_dsa_port_set_apptrust, 3096 + #endif 3344 3097 /* port */ 3345 3098 .get_tag_protocol = yt921x_dsa_get_tag_protocol, 3346 3099 .phylink_get_caps = yt921x_dsa_phylink_get_caps, 3347 3100 .port_setup = yt921x_dsa_port_setup, 3101 + #if IS_ENABLED(CONFIG_DCB) 3102 + /* dscp */ 3103 + .port_get_dscp_prio = yt921x_dsa_port_get_dscp_prio, 3104 + .port_del_dscp_prio = yt921x_dsa_port_del_dscp_prio, 3105 + .port_add_dscp_prio = yt921x_dsa_port_add_dscp_prio, 3106 + #endif 3348 3107 /* chip */ 3349 3108 .setup = yt921x_dsa_setup, 3350 3109 }; ··· 3424 3157 ds = &priv->ds; 3425 3158 ds->dev = dev; 3426 3159 ds->assisted_learning_on_cpu_port = true; 3160 + ds->dscp_prio_mapping_is_global = true; 3427 3161 ds->priv = priv; 3428 3162 ds->ops = &yt921x_dsa_switch_ops; 3429 3163 ds->ageing_time_min = 1 * 5000;
+45 -10
drivers/net/dsa/yt921x.h
··· 269 269 #define YT921X_TPID_EGRn(x) (0x100300 + 4 * (x)) /* [0, 3] */ 270 270 #define YT921X_TPID_EGR_TPID_M GENMASK(15, 0) 271 271 272 + #define YT921X_IPM_DSCPn(n) (0x180000 + 4 * (n)) /* Internal Priority Map */ 273 + #define YT921X_IPM_PCPn(map, dei, pcp) (0x180100 + 4 * (16 * (map) + 8 * (dei) + (pcp))) 274 + #define YT921X_IPM_PRIO_M GENMASK(4, 2) 275 + #define YT921X_IPM_PRIO(x) FIELD_PREP(YT921X_IPM_PRIO_M, (x)) 276 + #define YT921X_IPM_COLOR_M GENMASK(1, 0) 277 + #define YT921X_IPM_COLOR(x) FIELD_PREP(YT921X_IPM_COLOR_M, (x)) 278 + #define YT921X_IPM_COLOR_GREEN YT921X_IPM_COLOR(0) 279 + #define YT921X_IPM_COLOR_YELLOW YT921X_IPM_COLOR(1) 280 + #define YT921X_IPM_COLOR_RED YT921X_IPM_COLOR(2) 281 + #define YT921X_PORTn_QOS(port) (0x180180 + 4 * (port)) 282 + #define YT921X_PORT_QOS_CVLAN_PRIO_MAP_ID BIT(5) 283 + #define YT921X_PORT_QOS_SVLAN_PRIO_MAP_ID BIT(4) 284 + #define YT921X_PORT_QOS_PRIO_M GENMASK(3, 1) 285 + #define YT921X_PORT_QOS_PRIO(x) FIELD_PREP(YT921X_PORT_QOS_PRIO_M, (x)) 286 + #define YT921X_PORT_QOS_PRIO_EN BIT(0) 287 + #define YT921X_PORTn_PRIO_ORD(port) (0x180200 + 4 * (port)) 288 + #define YT921X_PORT_PRIO_ORD_APPm_M(m) GENMASK(3 * (m) + 2, 3 * (m)) 289 + #define YT921X_PORT_PRIO_ORD_APPm(m, x) ((x) << (3 * (m))) /* 0: disabled, except PORT_QOS_PRIO */ 290 + 291 + enum yt921x_app_selector { 292 + YT921X_APP_SEL_MAC_SA, 293 + YT921X_APP_SEL_MAC_DA, 294 + YT921X_APP_SEL_VID, 295 + YT921X_APP_SEL_ACL, 296 + YT921X_APP_SEL_DSCP, 297 + YT921X_APP_SEL_CVLAN_PCP, 298 + YT921X_APP_SEL_SVLAN_PCP, 299 + /* The physical port, i.e. YT921X_PORT_QOS_PRIO */ 300 + YT921X_APP_SEL_PORT, 301 + YT921X_APP_SEL_NUM 302 + }; 303 + 272 304 #define YT921X_VLAN_IGR_FILTER 0x180280 273 305 #define YT921X_VLAN_IGR_FILTER_PORTn_BYPASS_IGMP(port) BIT((port) + 11) 274 306 #define YT921X_VLAN_IGR_FILTER_PORTn(port) BIT(port) ··· 369 337 #define YT921X_FDB_OUT0 0x1804b0 370 338 #define YT921X_FDB_IO0_ADDR_HI4_M GENMASK(31, 0) 371 339 #define YT921X_FDB_OUT1 0x1804b4 372 - #define YT921X_FDB_IO1_EGR_INT_PRI_EN BIT(31) 340 + #define YT921X_FDB_IO1_EGR_PRIO_EN BIT(31) 373 341 #define YT921X_FDB_IO1_STATUS_M GENMASK(30, 28) 374 342 #define YT921X_FDB_IO1_STATUS(x) FIELD_PREP(YT921X_FDB_IO1_STATUS_M, (x)) 375 343 #define YT921X_FDB_IO1_STATUS_INVALID YT921X_FDB_IO1_STATUS(0) ··· 388 356 #define YT921X_FDB_IO2_EGR_PORTS(x) FIELD_PREP(YT921X_FDB_IO2_EGR_PORTS_M, (x)) 389 357 #define YT921X_FDB_IO2_EGR_DROP BIT(17) 390 358 #define YT921X_FDB_IO2_COPY_TO_CPU BIT(16) 391 - #define YT921X_FDB_IO2_IGR_INT_PRI_EN BIT(15) 392 - #define YT921X_FDB_IO2_INT_PRI_M GENMASK(14, 12) 393 - #define YT921X_FDB_IO2_INT_PRI(x) FIELD_PREP(YT921X_FDB_IO2_INT_PRI_M, (x)) 359 + #define YT921X_FDB_IO2_IGR_PRIO_EN BIT(15) 360 + #define YT921X_FDB_IO2_PRIO_M GENMASK(14, 12) 361 + #define YT921X_FDB_IO2_PRIO(x) FIELD_PREP(YT921X_FDB_IO2_PRIO_M, (x)) 394 362 #define YT921X_FDB_IO2_NEW_VID_M GENMASK(11, 0) 395 363 #define YT921X_FDB_IO2_NEW_VID(x) FIELD_PREP(YT921X_FDB_IO2_NEW_VID_M, (x)) 396 364 #define YT921X_FILTER_UNK_UCAST 0x180508 ··· 438 406 #define YT921X_VLAN_CTRL_FID_M GENMASK_ULL(34, 23) 439 407 #define YT921X_VLAN_CTRL_FID(x) FIELD_PREP(YT921X_VLAN_CTRL_FID_M, (x)) 440 408 #define YT921X_VLAN_CTRL_LEARN_DIS BIT_ULL(22) 441 - #define YT921X_VLAN_CTRL_INT_PRI_EN BIT_ULL(21) 442 - #define YT921X_VLAN_CTRL_INT_PRI_M GENMASK_ULL(20, 18) 409 + #define YT921X_VLAN_CTRL_PRIO_EN BIT_ULL(21) 410 + #define YT921X_VLAN_CTRL_PRIO_M GENMASK_ULL(20, 18) 411 + #define YT921X_VLAN_CTRL_PRIO(x) FIELD_PREP(YT921X_VLAN_CTRL_PRIO_M, (x)) 443 412 #define YT921X_VLAN_CTRL_PORTS_M GENMASK_ULL(17, 7) 444 413 #define YT921X_VLAN_CTRL_PORTS(x) FIELD_PREP(YT921X_VLAN_CTRL_PORTS_M, (x)) 445 414 #define YT921X_VLAN_CTRL_PORTn(port) BIT_ULL((port) + 7) ··· 466 433 #define YT921X_LAG_HASH_SRC_PORT BIT(0) 467 434 468 435 #define YT921X_PORTn_VLAN_CTRL(port) (0x230010 + 4 * (port)) 469 - #define YT921X_PORT_VLAN_CTRL_SVLAN_PRI_EN BIT(31) 470 - #define YT921X_PORT_VLAN_CTRL_CVLAN_PRI_EN BIT(30) 436 + #define YT921X_PORT_VLAN_CTRL_SVLAN_PRIO_EN BIT(31) 437 + #define YT921X_PORT_VLAN_CTRL_CVLAN_PRIO_EN BIT(30) 471 438 #define YT921X_PORT_VLAN_CTRL_SVID_M GENMASK(29, 18) 472 439 #define YT921X_PORT_VLAN_CTRL_SVID(x) FIELD_PREP(YT921X_PORT_VLAN_CTRL_SVID_M, (x)) 473 440 #define YT921X_PORT_VLAN_CTRL_CVID_M GENMASK(17, 6) 474 441 #define YT921X_PORT_VLAN_CTRL_CVID(x) FIELD_PREP(YT921X_PORT_VLAN_CTRL_CVID_M, (x)) 475 - #define YT921X_PORT_VLAN_CTRL_SVLAN_PRI_M GENMASK(5, 3) 476 - #define YT921X_PORT_VLAN_CTRL_CVLAN_PRI_M GENMASK(2, 0) 442 + #define YT921X_PORT_VLAN_CTRL_SVLAN_PRIO_M GENMASK(5, 3) 443 + #define YT921X_PORT_VLAN_CTRL_CVLAN_PRIO_M GENMASK(2, 0) 477 444 #define YT921X_PORTn_VLAN_CTRL1(port) (0x230080 + 4 * (port)) 478 445 #define YT921X_PORT_VLAN_CTRL1_VLAN_RANGE_EN BIT(8) 479 446 #define YT921X_PORT_VLAN_CTRL1_VLAN_RANGE_PROFILE_ID_M GENMASK(7, 4) ··· 510 477 511 478 #define YT921X_LAG_NUM 2 512 479 #define YT921X_LAG_PORT_NUM 4 480 + 481 + #define YT921X_PRIO_NUM 8 513 482 514 483 #define YT9215_MAJOR 0x9002 515 484 #define YT9218_MAJOR 0x9001
+58 -31
net/dsa/tag_yt921x.c
··· 14 14 * are conflicts somewhere and/or you want to change it for some reason. 15 15 * Tag: 16 16 * 2: VLAN Tag 17 - * 2: Rx Port 17 + * 2: 18 18 * 15b: Rx Port Valid 19 19 * 14b-11b: Rx Port 20 - * 10b-0b: Cmd? 21 - * 2: Tx Port(s) 20 + * 10b-8b: Tx/Rx Priority 21 + * 7b: Tx/Rx Code Valid 22 + * 6b-1b: Tx/Rx Code 23 + * 0b: ? (unset) 24 + * 2: 22 25 * 15b: Tx Port(s) Valid 23 26 * 10b-0b: Tx Port(s) Mask 24 27 */ ··· 36 33 37 34 #define YT921X_TAG_PORT_EN BIT(15) 38 35 #define YT921X_TAG_RX_PORT_M GENMASK(14, 11) 39 - #define YT921X_TAG_RX_CMD_M GENMASK(10, 0) 40 - #define YT921X_TAG_RX_CMD(x) FIELD_PREP(YT921X_TAG_RX_CMD_M, (x)) 41 - #define YT921X_TAG_RX_CMD_FORWARDED 0x80 42 - #define YT921X_TAG_RX_CMD_UNK_UCAST 0xb2 43 - #define YT921X_TAG_RX_CMD_UNK_MCAST 0xb4 44 - #define YT921X_TAG_TX_PORTS GENMASK(10, 0) 36 + #define YT921X_TAG_PRIO_M GENMASK(10, 8) 37 + #define YT921X_TAG_PRIO(x) FIELD_PREP(YT921X_TAG_PRIO_M, (x)) 38 + #define YT921X_TAG_CODE_EN BIT(7) 39 + #define YT921X_TAG_CODE_M GENMASK(6, 1) 40 + #define YT921X_TAG_CODE(x) FIELD_PREP(YT921X_TAG_CODE_M, (x)) 41 + #define YT921X_TAG_TX_PORTS_M GENMASK(10, 0) 42 + #define YT921X_TAG_TX_PORTS(x) FIELD_PREP(YT921X_TAG_TX_PORTS_M, (x)) 43 + 44 + /* Incomplete. Some are configurable via RMA_CTRL_CPU_CODE, the meaning of 45 + * others remains unknown. 46 + */ 47 + enum yt921x_tag_code { 48 + YT921X_TAG_CODE_FORWARD = 0, 49 + YT921X_TAG_CODE_UNK_UCAST = 0x19, 50 + YT921X_TAG_CODE_UNK_MCAST = 0x1a, 51 + YT921X_TAG_CODE_PORT_COPY = 0x1b, 52 + YT921X_TAG_CODE_FDB_COPY = 0x1c, 53 + }; 45 54 46 55 static struct sk_buff * 47 56 yt921x_tag_xmit(struct sk_buff *skb, struct net_device *netdev) 48 57 { 49 58 __be16 *tag; 50 - u16 tx; 59 + u16 ctrl; 51 60 52 61 skb_push(skb, YT921X_TAG_LEN); 53 62 dsa_alloc_etype_header(skb, YT921X_TAG_LEN); ··· 69 54 tag[0] = htons(ETH_P_YT921X); 70 55 /* VLAN tag unrelated when TX */ 71 56 tag[1] = 0; 72 - tag[2] = 0; 73 - tx = FIELD_PREP(YT921X_TAG_TX_PORTS, dsa_xmit_port_mask(skb, netdev)) | 74 - YT921X_TAG_PORT_EN; 75 - tag[3] = htons(tx); 57 + ctrl = YT921X_TAG_CODE(YT921X_TAG_CODE_FORWARD) | YT921X_TAG_CODE_EN | 58 + YT921X_TAG_PRIO(skb->priority); 59 + tag[2] = htons(ctrl); 60 + ctrl = YT921X_TAG_TX_PORTS(dsa_xmit_port_mask(skb, netdev)) | 61 + YT921X_TAG_PORT_EN; 62 + tag[3] = htons(ctrl); 76 63 77 64 return skb; 78 65 } ··· 84 67 { 85 68 unsigned int port; 86 69 __be16 *tag; 87 - u16 cmd; 88 70 u16 rx; 89 71 90 72 if (unlikely(!pskb_may_pull(skb, YT921X_TAG_LEN))) ··· 114 98 return NULL; 115 99 } 116 100 117 - cmd = FIELD_GET(YT921X_TAG_RX_CMD_M, rx); 118 - switch (cmd) { 119 - case YT921X_TAG_RX_CMD_FORWARDED: 120 - /* Already forwarded by hardware */ 121 - dsa_default_offload_fwd_mark(skb); 122 - break; 123 - case YT921X_TAG_RX_CMD_UNK_UCAST: 124 - case YT921X_TAG_RX_CMD_UNK_MCAST: 125 - /* NOTE: hardware doesn't distinguish between TRAP (copy to CPU 126 - * only) and COPY (forward and copy to CPU). In order to perform 127 - * a soft switch, NEVER use COPY action in the switch driver. 128 - */ 129 - break; 130 - default: 101 + skb->priority = FIELD_GET(YT921X_TAG_PRIO_M, rx); 102 + 103 + if (!(rx & YT921X_TAG_CODE_EN)) { 131 104 dev_warn_ratelimited(&netdev->dev, 132 - "Unexpected rx cmd 0x%02x\n", cmd); 133 - break; 105 + "Tag code not enabled in rx packet\n"); 106 + } else { 107 + u16 code = FIELD_GET(YT921X_TAG_CODE_M, rx); 108 + 109 + switch (code) { 110 + case YT921X_TAG_CODE_FORWARD: 111 + case YT921X_TAG_CODE_PORT_COPY: 112 + case YT921X_TAG_CODE_FDB_COPY: 113 + /* Already forwarded by hardware */ 114 + dsa_default_offload_fwd_mark(skb); 115 + break; 116 + case YT921X_TAG_CODE_UNK_UCAST: 117 + case YT921X_TAG_CODE_UNK_MCAST: 118 + /* NOTE: hardware doesn't distinguish between TRAP (copy 119 + * to CPU only) and COPY (forward and copy to CPU). In 120 + * order to perform a soft switch, NEVER use COPY action 121 + * in the switch driver. 122 + */ 123 + break; 124 + default: 125 + dev_warn_ratelimited(&netdev->dev, 126 + "Unknown code 0x%02x\n", code); 127 + break; 128 + } 134 129 } 135 130 136 131 /* Remove YT921x tag and update checksum */