From: Markus Stockhausen Date: Tue, 23 Jun 2026 16:50:48 +0000 (+0200) Subject: realtek: dsa/eth: adapt receive path X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=e59484b39ea79e8a77f3bb953f25b25769ef9ebe;p=thirdparty%2Fopenwrt.git realtek: dsa/eth: adapt receive path Improve the DSA receive tagging. For this convert the receive path to METADATA_HW_PORT_MUX. This way no skb data mangling is needed. See e.g. airoha_eth.c or mtk_eth_soc.c. Link: https://github.com/openwrt/openwrt/pull/23948 Signed-off-by: Markus Stockhausen --- diff --git a/target/linux/realtek/files-6.18/drivers/net/ethernet/rtl838x_eth.c b/target/linux/realtek/files-6.18/drivers/net/ethernet/rtl838x_eth.c index b9cb5724923..0dfd36a82f4 100644 --- a/target/linux/realtek/files-6.18/drivers/net/ethernet/rtl838x_eth.c +++ b/target/linux/realtek/files-6.18/drivers/net/ethernet/rtl838x_eth.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -113,6 +114,7 @@ struct rteth_ctrl { struct phylink_config phylink_config; const struct rteth_config *r; u32 lastEvent; + struct metadata_dst *dsa_meta[RTETH_931X_CPU_PORT]; /* receive handling */ dma_addr_t rx_data_dma; spinlock_t rx_lock; @@ -1097,11 +1099,10 @@ static int rteth_start_xmit(struct sk_buff *skb, struct net_device *dev) static int rteth_hw_receive(struct net_device *dev, int ring, int budget) { - int slot, len, work_done = 0, rx_packets = 0, rx_bytes = 0; + int slot, work_done = 0, rx_packets = 0, rx_bytes = 0; struct rteth_ctrl *ctrl = netdev_priv(dev); - unsigned int new_offset, old_offset; + unsigned int len, new_offset, old_offset; struct page *old_page, *new_page; - bool dsa = netdev_uses_dsa(dev); struct rteth_packet *packet; dma_addr_t packet_dma; struct sk_buff *skb; @@ -1116,9 +1117,9 @@ static int rteth_hw_receive(struct net_device *dev, int ring, int budget) break; packet = &ctrl->rx_data[ring].packet[slot]; - len = packet->len; + len = packet->len - ETH_FCS_LEN; - if (unlikely(len < ETH_FCS_LEN || len > RING_BUFFER)) { + if (unlikely(len > RING_BUFFER)) { netdev_err(dev, "invalid packet with %d bytes received\n", len); dev->stats.rx_errors++; goto recycle; @@ -1138,9 +1139,6 @@ static int rteth_hw_receive(struct net_device *dev, int ring, int budget) packet->page_offset = new_offset; packet->dma = page_pool_get_dma_addr(new_page) + new_offset + RTETH_SKB_HEADROOM; - if (!dsa) - len -= ETH_FCS_LEN; - page_pool_dma_sync_for_cpu(ctrl->rx_qs[ring].page_pool, old_page, old_offset + RTETH_SKB_HEADROOM, len); @@ -1156,13 +1154,11 @@ static int rteth_hw_receive(struct net_device *dev, int ring, int budget) skb_put(skb, len); ctrl->r->decode_tag(packet, &tag); - if (dsa) { - skb->data[len - 4] = 0x80; - skb->data[len - 3] = tag.port; - skb->data[len - 2] = 0x10; - skb->data[len - 1] = 0x00; + if (netdev_uses_dsa(dev)) { + if (tag.port < ctrl->r->cpu_port) + skb_dst_set_noref(skb, &ctrl->dsa_meta[tag.port]->dst); if (tag.l2_offloaded) - skb->data[len - 3] |= 0x40; + skb->offload_fwd_mark = 1; } skb->protocol = eth_type_trans(skb, dev); @@ -1606,6 +1602,32 @@ static const struct ethtool_ops rteth_ethtool_ops = { .set_link_ksettings = rteth_set_link_ksettings, }; +static int rteth_metadata_dst_alloc(struct rteth_ctrl *ctrl) +{ + struct metadata_dst *md_dst; + + for (int i = 0; i < ARRAY_SIZE(ctrl->dsa_meta); i++) { + md_dst = metadata_dst_alloc(0, METADATA_HW_PORT_MUX, GFP_KERNEL); + if (!md_dst) + return -ENOMEM; + + md_dst->u.port_info.port_id = i; + ctrl->dsa_meta[i] = md_dst; + } + + return 0; +} + +static void rteth_metadata_dst_free(struct rteth_ctrl *ctrl) +{ + for (int i = 0; i < ARRAY_SIZE(ctrl->dsa_meta); i++) { + if (!ctrl->dsa_meta[i]) + continue; + + metadata_dst_free(ctrl->dsa_meta[i]); + } +} + static int rteth_probe(struct platform_device *pdev) { struct page_pool_params pp_params = { @@ -1762,6 +1784,10 @@ static int rteth_probe(struct platform_device *pdev) } } + err = rteth_metadata_dst_alloc(ctrl); + if (err) + goto cleanup; + err = register_netdev(dev); if (err) goto cleanup; @@ -1769,6 +1795,7 @@ static int rteth_probe(struct platform_device *pdev) return 0; cleanup: + rteth_metadata_dst_free(ctrl); if (ctrl->phylink) phylink_destroy(ctrl->phylink); for (int i = 0; i < RTETH_RX_RINGS; i++) { @@ -1787,6 +1814,7 @@ static void rteth_remove(struct platform_device *pdev) pr_info("Removing platform driver for rtl838x-eth\n"); unregister_netdev(dev); + rteth_metadata_dst_free(ctrl); if (ctrl->phylink) phylink_destroy(ctrl->phylink); diff --git a/target/linux/realtek/files-6.18/net/dsa/tag_rtl_otto.c b/target/linux/realtek/files-6.18/net/dsa/tag_rtl_otto.c index 2048d5addbe..ecbf67b42ae 100644 --- a/target/linux/realtek/files-6.18/net/dsa/tag_rtl_otto.c +++ b/target/linux/realtek/files-6.18/net/dsa/tag_rtl_otto.c @@ -26,29 +26,8 @@ static struct sk_buff *rtl_otto_xmit(struct sk_buff *skb, struct net_device *dev static struct sk_buff *rtl_otto_rcv(struct sk_buff *skb, struct net_device *dev) { - u8 *trailer; - int source_port; - - if (skb_linearize(skb)) - return NULL; - - trailer = skb_tail_pointer(skb) - 4; - - if (trailer[0] != 0x80 || (trailer[1] & 0x80) != 0x00 || - (trailer[2] & 0xef) != 0x00 || trailer[3] != 0x00) - return NULL; - - if (trailer[1] & 0x40) - skb->offload_fwd_mark = 1; - - source_port = trailer[1] & 0x3f; - - skb->dev = dsa_conduit_find_user(dev, 0, source_port); - if (!skb->dev) - return NULL; - - if (pskb_trim_rcsum(skb, skb->len - 4)) - return NULL; + /* RX path uses METADATA_HW_PORT_MUX. This function just makes netdev_uses_dsa() happy. */ + netdev_err(dev, "ethernet driver did not set METADATA\n"); return skb; }