diff --git a/package/kernel/ipqess-dual-gmac.patch b/package/kernel/ipqess-dual-gmac.patch new file mode 100644 index 0000000000..aa6c46a6f3 --- /dev/null +++ b/package/kernel/ipqess-dual-gmac.patch @@ -0,0 +1,124 @@ +--- a/drivers/net/ethernet/qualcomm/ipqess/ipqess.h ++++ b/drivers/net/ethernet/qualcomm/ipqess/ipqess.h +@@ -162,6 +162,9 @@ struct ipqess_rx_ring_refill { + struct ipqess { + struct net_device *netdev; ++ /* second netdev for the QCA8337 CPU port (port 5 of the internal switch) */ ++ struct net_device *netdev2; ++ u32 gmac1_port; /* switch port number routed to netdev2, 0 = disabled */ + void __iomem *hw_addr; + + struct clk *ess_clk; +--- a/drivers/net/ethernet/qualcomm/ipqess/ipqess.c ++++ b/drivers/net/ethernet/qualcomm/ipqess/ipqess.c +@@ -393,8 +393,22 @@ static int ipqess_rx_poll(struct ipqess_rx_ring *rx_ring, int budget) + skb_put(skb, length); + } + +- skb->dev = rx_ring->ess->netdev; +- skb->protocol = eth_type_trans(skb, rx_ring->ess->netdev); ++ /* Demux to netdev2 if the RRD source port matches gmac1_port. ++ * rrd0 bits [14:12] carry the originating switch port id. ++ * IPQESS_RRD_PORT_ID_MASK = 0x7000 ++ */ ++ if (rx_ring->ess->gmac1_port && ++ rx_ring->ess->netdev2 && ++ netif_running(rx_ring->ess->netdev2)) { ++ u16 src_port = (le16_to_cpu(rd->rrd0) & IPQESS_RRD_PORT_ID_MASK) >> 12; ++ ++ if (src_port == rx_ring->ess->gmac1_port) { ++ skb->dev = rx_ring->ess->netdev2; ++ skb->protocol = eth_type_trans(skb, rx_ring->ess->netdev2); ++ goto rx_demux_done; ++ } ++ } ++ skb->dev = rx_ring->ess->netdev; ++ skb->protocol = eth_type_trans(skb, rx_ring->ess->netdev); ++rx_demux_done: + skb_record_rx_queue(skb, rx_ring->ring_id); + +@@ -1185,6 +1199,7 @@ static int ipqess_axi_probe(struct platform_device *pdev) + struct device_node *np = pdev->dev.of_node; + struct net_device *netdev; ++ struct net_device *netdev2 = NULL; + phy_interface_t phy_mode; + struct ipqess *ess; + int i, err = 0; +@@ -1199,6 +1214,7 @@ static int ipqess_axi_probe(struct platform_device *pdev) + ess = netdev_priv(netdev); + ess->netdev = netdev; + ess->pdev = pdev; ++ ess->gmac1_port = 0; + spin_lock_init(&ess->stats_lock); + SET_NETDEV_DEV(netdev, &pdev->dev); + platform_set_drvdata(pdev, netdev); +@@ -1275,6 +1291,51 @@ static int ipqess_axi_probe(struct platform_device *pdev) + err = register_netdev(netdev); + if (err) + goto err_notifier_unregister; ++ ++ /* Optional second GMAC for TEW-829DRU / dual-switch boards. ++ * DTS: qcom,gmac1-port = <5>; in the ethernet node selects ++ * which switch CPU port is demuxed to the second netdev. ++ */ ++ { ++ u32 port; ++ if (!of_property_read_u32(np, "qcom,gmac1-port", &port) && port) { ++ netdev2 = alloc_etherdev(0); ++ if (!netdev2) { ++ dev_warn(&pdev->dev, ++ "gmac1: failed to alloc netdev2, single-GMAC mode\n"); ++ goto skip_gmac1; ++ } ++ ++ SET_NETDEV_DEV(netdev2, &pdev->dev); ++ netdev2->netdev_ops = &ipqess_axi_netdev_ops; ++ netdev2->features = netdev->features; ++ netdev2->hw_features = 0; ++ netdev2->vlan_features = netdev->vlan_features; ++ netdev2->watchdog_timeo = 5 * HZ; ++ netdev2->max_mtu = 9000; ++ netdev2->gso_max_segs = IPQESS_TX_RING_SIZE / 2; ++ /* Give it a MAC derived from netdev's by flipping one bit */ ++ eth_hw_addr_inherit(netdev2, netdev); ++ netdev2->dev_addr [5] ^= 0x01; ++ ++ /* Point priv back to the same ess so all ring/hw ++ * operations reuse the existing infrastructure. ++ * netdev_priv(netdev2) would return garbage because ++ * we used alloc_etherdev(0) – store ess in ++ * netdev->ml_priv instead. ++ */ ++ netdev2->ml_priv = ess; ++ ++ err = register_netdev(netdev2); ++ if (err) { ++ free_netdev(netdev2); ++ dev_warn(&pdev->dev, ++ "gmac1: register_netdev failed (%d), single-GMAC mode\n", ++ err); ++ goto skip_gmac1; ++ } ++ ++ ess->gmac1_port = port; ++ ess->netdev2 = netdev2; ++ dev_info(&pdev->dev, "gmac1: netdev2=%s demuxing switch port %u\n", ++ netdev2->name, port); ++ } ++ } ++skip_gmac1: + + dev_set_threaded(netdev, true); + +@@ -1305,6 +1366,11 @@ static void ipqess_axi_remove(struct platform_device *pdev) + const struct net_device *netdev = platform_get_drvdata(pdev); + struct ipqess *ess = netdev_priv(netdev); + ++ if (ess->netdev2) { ++ unregister_netdev(ess->netdev2); ++ free_netdev(ess->netdev2); ++ ess->netdev2 = NULL; ++ } ++ + unregister_netdev(ess->netdev); + ipqess_hw_stop(ess); diff --git a/target/linux/ipq40xx/config-6.12 b/target/linux/ipq40xx/config-6.12 index aca3af0f50..e5fef3578a 100644 --- a/target/linux/ipq40xx/config-6.12 +++ b/target/linux/ipq40xx/config-6.12 @@ -499,7 +499,6 @@ CONFIG_SPMI=y # CONFIG_SPMI_HISI3670 is not set CONFIG_SPMI_MSM_PMIC_ARB=y # CONFIG_SPMI_PMIC_CLKDIV is not set -CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU=y CONFIG_SWPHY=y CONFIG_SWP_EMULATE=y CONFIG_SYS_SUPPORTS_APM_EMULATION=y diff --git a/target/linux/ipq40xx/files-6.12/arch/arm/boot/dts/qcom/qcom-ipq4019-tew-829dru.dts b/target/linux/ipq40xx/files-6.12/arch/arm/boot/dts/qcom/qcom-ipq4019-tew-829dru.dts index 202a38c79c..2c0454c2d3 100644 --- a/target/linux/ipq40xx/files-6.12/arch/arm/boot/dts/qcom/qcom-ipq4019-tew-829dru.dts +++ b/target/linux/ipq40xx/files-6.12/arch/arm/boot/dts/qcom/qcom-ipq4019-tew-829dru.dts @@ -60,6 +60,8 @@ }; }; /* end of gmac */ +/* we are working on driver patch for second gmac for QCA8075/QCA8337 side-by-side config */ + /* TOP SWITCH: ESS built-in (QCA8075 via PSGMII) at c000000 */ /* compatible MUST be qca,ipq4019-qca8337n — this is what ran on the device */ &switch {