openwrt/package/kernel/ipqess-dual-gmac.patch
2026-06-18 16:28:36 -04:00

125 lines
5.5 KiB
Diff
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

--- 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);