125 lines
5.5 KiB
Diff
125 lines
5.5 KiB
Diff
--- 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);
|