|
23 | 23 | #include <linux/jhash.h>
|
24 | 24 | #include <linux/bitfield.h>
|
25 | 25 | #include <net/dsa.h>
|
| 26 | +#include <net/dst_metadata.h> |
26 | 27 |
|
27 | 28 | #include "mtk_eth_soc.h"
|
28 | 29 | #include "mtk_wed.h"
|
@@ -1939,13 +1940,19 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
|
1939 | 1940 | __vlan_hwaccel_put_tag(skb, htons(RX_DMA_VPID(trxd.rxd3)),
|
1940 | 1941 | RX_DMA_VID(trxd.rxd3));
|
1941 | 1942 | }
|
| 1943 | + } |
| 1944 | + |
| 1945 | + /* When using VLAN untagging in combination with DSA, the |
| 1946 | + * hardware treats the MTK special tag as a VLAN and untags it. |
| 1947 | + */ |
| 1948 | + if (skb_vlan_tag_present(skb) && netdev_uses_dsa(netdev)) { |
| 1949 | + unsigned int port = ntohs(skb->vlan_proto) & GENMASK(2, 0); |
1942 | 1950 |
|
1943 |
| - /* If the device is attached to a dsa switch, the special |
1944 |
| - * tag inserted in VLAN field by hw switch can * be offloaded |
1945 |
| - * by RX HW VLAN offload. Clear vlan info. |
1946 |
| - */ |
1947 |
| - if (netdev_uses_dsa(netdev)) |
1948 |
| - __vlan_hwaccel_clear_tag(skb); |
| 1951 | + if (port < ARRAY_SIZE(eth->dsa_meta) && |
| 1952 | + eth->dsa_meta[port]) |
| 1953 | + skb_dst_set_noref(skb, ð->dsa_meta[port]->dst); |
| 1954 | + |
| 1955 | + __vlan_hwaccel_clear_tag(skb); |
1949 | 1956 | }
|
1950 | 1957 |
|
1951 | 1958 | skb_record_rx_queue(skb, 0);
|
@@ -2990,11 +2997,46 @@ static void mtk_gdm_config(struct mtk_eth *eth, u32 config)
|
2990 | 2997 | mtk_w32(eth, 0, MTK_RST_GL);
|
2991 | 2998 | }
|
2992 | 2999 |
|
| 3000 | + |
| 3001 | +static bool mtk_uses_dsa(struct net_device *dev) |
| 3002 | +{ |
| 3003 | +#if IS_ENABLED(CONFIG_NET_DSA) |
| 3004 | + return netdev_uses_dsa(dev) && |
| 3005 | + dev->dsa_ptr->tag_ops->proto == DSA_TAG_PROTO_MTK; |
| 3006 | +#else |
| 3007 | + return false; |
| 3008 | +#endif |
| 3009 | +} |
| 3010 | + |
2993 | 3011 | static int mtk_open(struct net_device *dev)
|
2994 | 3012 | {
|
2995 | 3013 | struct mtk_mac *mac = netdev_priv(dev);
|
2996 | 3014 | struct mtk_eth *eth = mac->hw;
|
2997 |
| - int err; |
| 3015 | + int i, err; |
| 3016 | + |
| 3017 | + if (mtk_uses_dsa(dev) && !eth->prog) { |
| 3018 | + for (i = 0; i < ARRAY_SIZE(eth->dsa_meta); i++) { |
| 3019 | + struct metadata_dst *md_dst = eth->dsa_meta[i]; |
| 3020 | + |
| 3021 | + if (md_dst) |
| 3022 | + continue; |
| 3023 | + |
| 3024 | + md_dst = metadata_dst_alloc(0, METADATA_HW_PORT_MUX, |
| 3025 | + GFP_KERNEL); |
| 3026 | + if (!md_dst) |
| 3027 | + return -ENOMEM; |
| 3028 | + |
| 3029 | + md_dst->u.port_info.port_id = i; |
| 3030 | + eth->dsa_meta[i] = md_dst; |
| 3031 | + } |
| 3032 | + } else { |
| 3033 | + /* Hardware special tag parsing needs to be disabled if at least |
| 3034 | + * one MAC does not use DSA. |
| 3035 | + */ |
| 3036 | + u32 val = mtk_r32(eth, MTK_CDMP_IG_CTRL); |
| 3037 | + val &= ~MTK_CDMP_STAG_EN; |
| 3038 | + mtk_w32(eth, val, MTK_CDMP_IG_CTRL); |
| 3039 | + } |
2998 | 3040 |
|
2999 | 3041 | err = phylink_of_phy_connect(mac->phylink, mac->of_node, 0);
|
3000 | 3042 | if (err) {
|
@@ -3321,6 +3363,10 @@ static int mtk_hw_init(struct mtk_eth *eth)
|
3321 | 3363 | */
|
3322 | 3364 | val = mtk_r32(eth, MTK_CDMQ_IG_CTRL);
|
3323 | 3365 | mtk_w32(eth, val | MTK_CDMQ_STAG_EN, MTK_CDMQ_IG_CTRL);
|
| 3366 | + if (!MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { |
| 3367 | + val = mtk_r32(eth, MTK_CDMP_IG_CTRL); |
| 3368 | + mtk_w32(eth, val | MTK_CDMP_STAG_EN, MTK_CDMP_IG_CTRL); |
| 3369 | + } |
3324 | 3370 |
|
3325 | 3371 | /* Enable RX VLan Offloading */
|
3326 | 3372 | mtk_w32(eth, 1, MTK_CDMP_EG_CTRL);
|
@@ -3538,6 +3584,12 @@ static int mtk_free_dev(struct mtk_eth *eth)
|
3538 | 3584 | free_netdev(eth->netdev[i]);
|
3539 | 3585 | }
|
3540 | 3586 |
|
| 3587 | + for (i = 0; i < ARRAY_SIZE(eth->dsa_meta); i++) { |
| 3588 | + if (!eth->dsa_meta[i]) |
| 3589 | + break; |
| 3590 | + metadata_dst_free(eth->dsa_meta[i]); |
| 3591 | + } |
| 3592 | + |
3541 | 3593 | return 0;
|
3542 | 3594 | }
|
3543 | 3595 |
|
|
0 commit comments