Files
openwrt_mitrastar/target/linux/qualcommbe/patches-6.12/0343-net-ethernet-qualcomm-Add-netdevice-support-for-QCOM.patch
Alexandru Gagniuc f3fc278fcb qualcommbe: v6.12: add PPE driver (part 2)
Add the second part of the PPE driver. This includes the EDMA and
network device support. This part does not appear to have been
officially submitted for upstream review. The series is taken from
target/linux/qualcommbe/patches-6.6, and had to be heavily modified
in order to compile of v6.12. Changes to patches are noted in the
respective patch body.

Also add the PPE and EDMA nodes in this series.

Signed-off-by: Alexandru Gagniuc <mr.nuke.me@gmail.com>
Link: https://github.com/openwrt/openwrt/pull/18796
Signed-off-by: Robert Marko <robimarko@gmail.com>
2025-05-31 12:25:48 +02:00

398 lines
10 KiB
Diff

From 5dc80c468c668d855d76b323f09bbadb95cc3147 Mon Sep 17 00:00:00 2001
From: Suruchi Agarwal <quic_suruchia@quicinc.com>
Date: Thu, 21 Mar 2024 16:14:46 -0700
Subject: [PATCH] net: ethernet: qualcomm: Add netdevice support for QCOM
IPQ9574 chipset.
Add EDMA ports and netdevice operations for QCOM IPQ9574 chipset.
Change-Id: I08b2eff52b4ef0d6d428c1c416f5580ef010973f
Co-developed-by: Pavithra R <quic_pavir@quicinc.com>
Signed-off-by: Pavithra R <quic_pavir@quicinc.com>
Signed-off-by: Suruchi Agarwal <quic_suruchia@quicinc.com>
---
drivers/net/ethernet/qualcomm/ppe/Makefile | 2 +-
drivers/net/ethernet/qualcomm/ppe/edma.h | 3 +
drivers/net/ethernet/qualcomm/ppe/edma_port.c | 270 ++++++++++++++++++
drivers/net/ethernet/qualcomm/ppe/edma_port.h | 31 ++
drivers/net/ethernet/qualcomm/ppe/ppe_port.c | 19 ++
5 files changed, 324 insertions(+), 1 deletion(-)
create mode 100644 drivers/net/ethernet/qualcomm/ppe/edma_port.c
create mode 100644 drivers/net/ethernet/qualcomm/ppe/edma_port.h
--- a/drivers/net/ethernet/qualcomm/ppe/Makefile
+++ b/drivers/net/ethernet/qualcomm/ppe/Makefile
@@ -7,4 +7,4 @@ obj-$(CONFIG_QCOM_PPE) += qcom-ppe.o
qcom-ppe-objs := ppe.o ppe_config.o ppe_debugfs.o ppe_port.o
#EDMA
-qcom-ppe-objs += edma.o
+qcom-ppe-objs += edma.o edma_port.o
--- a/drivers/net/ethernet/qualcomm/ppe/edma.h
+++ b/drivers/net/ethernet/qualcomm/ppe/edma.h
@@ -26,6 +26,9 @@
/* Number of PPE queue priorities supported per ARM core. */
#define EDMA_PRI_MAX_PER_CORE 8
+/* Interface ID start. */
+#define EDMA_START_IFNUM 1
+
/**
* enum ppe_queue_class_type - PPE queue class type
* @PPE_QUEUE_CLASS_PRIORITY: Queue offset configured from internal priority
--- /dev/null
+++ b/drivers/net/ethernet/qualcomm/ppe/edma_port.c
@@ -0,0 +1,270 @@
+// SPDX-License-Identifier: GPL-2.0-only
+ /* Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+/* EDMA port initialization, configuration and netdevice ops handling */
+
+#include <linux/etherdevice.h>
+#include <linux/net.h>
+#include <linux/netdevice.h>
+#include <linux/of_net.h>
+#include <linux/phylink.h>
+#include <linux/printk.h>
+
+#include "edma.h"
+#include "edma_port.h"
+#include "ppe_regs.h"
+
+/* Number of netdev queues. */
+#define EDMA_NETDEV_QUEUE_NUM 4
+
+static u16 __maybe_unused edma_port_select_queue(__maybe_unused struct net_device *netdev,
+ __maybe_unused struct sk_buff *skb,
+ __maybe_unused struct net_device *sb_dev)
+{
+ int cpu = get_cpu();
+
+ put_cpu();
+
+ return cpu;
+}
+
+static int edma_port_open(struct net_device *netdev)
+{
+ struct edma_port_priv *port_priv = (struct edma_port_priv *)netdev_priv(netdev);
+ struct ppe_port *ppe_port;
+
+ if (!port_priv)
+ return -EINVAL;
+
+ /* Inform the Linux Networking stack about the hardware capability of
+ * checksum offloading and other features. Each port is
+ * responsible to maintain the feature set it supports.
+ */
+ netdev->features |= EDMA_NETDEV_FEATURES;
+ netdev->hw_features |= EDMA_NETDEV_FEATURES;
+ netdev->vlan_features |= EDMA_NETDEV_FEATURES;
+ netdev->wanted_features |= EDMA_NETDEV_FEATURES;
+
+ ppe_port = port_priv->ppe_port;
+
+ if (ppe_port->phylink)
+ phylink_start(ppe_port->phylink);
+
+ netif_start_queue(netdev);
+
+ return 0;
+}
+
+static int edma_port_close(struct net_device *netdev)
+{
+ struct edma_port_priv *port_priv = (struct edma_port_priv *)netdev_priv(netdev);
+ struct ppe_port *ppe_port;
+
+ if (!port_priv)
+ return -EINVAL;
+
+ netif_stop_queue(netdev);
+
+ ppe_port = port_priv->ppe_port;
+
+ /* Phylink close. */
+ if (ppe_port->phylink)
+ phylink_stop(ppe_port->phylink);
+
+ return 0;
+}
+
+static int edma_port_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
+{
+ struct edma_port_priv *port_priv = (struct edma_port_priv *)netdev_priv(netdev);
+ struct ppe_port *ppe_port;
+ int ret = -EINVAL;
+
+ if (!port_priv)
+ return -EINVAL;
+
+ ppe_port = port_priv->ppe_port;
+ if (ppe_port->phylink)
+ return phylink_mii_ioctl(ppe_port->phylink, ifr, cmd);
+
+ return ret;
+}
+
+static int edma_port_change_mtu(struct net_device *netdev, int mtu)
+{
+ struct edma_port_priv *port_priv = (struct edma_port_priv *)netdev_priv(netdev);
+
+ if (!port_priv)
+ return -EINVAL;
+
+ netdev->mtu = mtu;
+
+ return ppe_port_set_maxframe(port_priv->ppe_port, mtu);
+}
+
+static netdev_features_t edma_port_feature_check(__maybe_unused struct sk_buff *skb,
+ __maybe_unused struct net_device *netdev,
+ netdev_features_t features)
+{
+ return features;
+}
+
+static void edma_port_get_stats64(struct net_device *netdev,
+ struct rtnl_link_stats64 *stats)
+{
+ struct edma_port_priv *port_priv = (struct edma_port_priv *)netdev_priv(netdev);
+
+ if (!port_priv)
+ return;
+
+ ppe_port_get_stats64(port_priv->ppe_port, stats);
+}
+
+static int edma_port_set_mac_address(struct net_device *netdev, void *macaddr)
+{
+ struct edma_port_priv *port_priv = (struct edma_port_priv *)netdev_priv(netdev);
+ struct sockaddr *addr = (struct sockaddr *)macaddr;
+ int ret;
+
+ if (!port_priv)
+ return -EINVAL;
+
+ netdev_dbg(netdev, "AddrFamily: %d, %0x:%0x:%0x:%0x:%0x:%0x\n",
+ addr->sa_family, addr->sa_data[0], addr->sa_data[1],
+ addr->sa_data[2], addr->sa_data[3], addr->sa_data[4],
+ addr->sa_data[5]);
+
+ ret = eth_prepare_mac_addr_change(netdev, addr);
+ if (ret)
+ return ret;
+
+ if (ppe_port_set_mac_address(port_priv->ppe_port, (u8 *)addr)) {
+ netdev_err(netdev, "set mac address failed for dev: %s\n", netdev->name);
+ return -EINVAL;
+ }
+
+ eth_commit_mac_addr_change(netdev, addr);
+
+ return 0;
+}
+
+static const struct net_device_ops edma_port_netdev_ops = {
+ .ndo_open = edma_port_open,
+ .ndo_stop = edma_port_close,
+ .ndo_get_stats64 = edma_port_get_stats64,
+ .ndo_set_mac_address = edma_port_set_mac_address,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_change_mtu = edma_port_change_mtu,
+ .ndo_eth_ioctl = edma_port_ioctl,
+ .ndo_features_check = edma_port_feature_check,
+ .ndo_select_queue = edma_port_select_queue,
+};
+
+/**
+ * edma_port_destroy - EDMA port destroy.
+ * @port: PPE port
+ *
+ * Unregister and free the netdevice.
+ */
+void edma_port_destroy(struct ppe_port *port)
+{
+ int port_id = port->port_id;
+ struct net_device *netdev = edma_ctx->netdev_arr[port_id - 1];
+
+ unregister_netdev(netdev);
+ free_netdev(netdev);
+ ppe_port_phylink_destroy(port);
+ edma_ctx->netdev_arr[port_id - 1] = NULL;
+}
+
+/**
+ * edma_port_setup - EDMA port Setup.
+ * @port: PPE port
+ *
+ * Initialize and register the netdevice.
+ *
+ * Return 0 on success, negative error code on failure.
+ */
+int edma_port_setup(struct ppe_port *port)
+{
+ struct ppe_device *ppe_dev = edma_ctx->ppe_dev;
+ struct device_node *np = port->np;
+ struct edma_port_priv *port_priv;
+ int port_id = port->port_id;
+ struct net_device *netdev;
+ u8 mac_addr[ETH_ALEN];
+ int ret = 0;
+ u8 *maddr;
+
+ netdev = alloc_etherdev_mqs(sizeof(struct edma_port_priv),
+ EDMA_NETDEV_QUEUE_NUM, EDMA_NETDEV_QUEUE_NUM);
+ if (!netdev) {
+ pr_err("alloc_etherdev() failed\n");
+ return -ENOMEM;
+ }
+
+ SET_NETDEV_DEV(netdev, ppe_dev->dev);
+ netdev->dev.of_node = np;
+
+ /* max_mtu is set to 1500 in ether_setup(). */
+ netdev->max_mtu = ETH_MAX_MTU;
+
+ port_priv = netdev_priv(netdev);
+ memset((void *)port_priv, 0, sizeof(struct edma_port_priv));
+
+ port_priv->ppe_port = port;
+ port_priv->netdev = netdev;
+ netdev->watchdog_timeo = 5 * HZ;
+ netdev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
+ netdev->netdev_ops = &edma_port_netdev_ops;
+ netdev->gso_max_segs = GSO_MAX_SEGS;
+
+ maddr = mac_addr;
+ if (of_get_mac_address(np, maddr))
+ maddr = NULL;
+
+ if (maddr && is_valid_ether_addr(maddr)) {
+ eth_hw_addr_set(netdev, maddr);
+ } else {
+ eth_hw_addr_random(netdev);
+ netdev_info(netdev, "GMAC%d Using random MAC address - %pM\n",
+ port_id, netdev->dev_addr);
+ }
+
+ netdev_dbg(netdev, "Configuring the port %s(qcom-id:%d)\n",
+ netdev->name, port_id);
+
+ /* We expect 'port_id' to correspond to ports numbers on SoC.
+ * These begin from '1' and hence we subtract
+ * one when using it as an array index.
+ */
+ edma_ctx->netdev_arr[port_id - 1] = netdev;
+
+ /* Setup phylink. */
+ ret = ppe_port_phylink_setup(port, netdev);
+ if (ret) {
+ netdev_dbg(netdev, "EDMA port phylink setup for netdevice %s\n",
+ netdev->name);
+ goto port_phylink_setup_fail;
+ }
+
+ /* Register the network interface. */
+ ret = register_netdev(netdev);
+ if (ret) {
+ netdev_dbg(netdev, "Error registering netdevice %s\n",
+ netdev->name);
+ goto register_netdev_fail;
+ }
+
+ netdev_dbg(netdev, "Setup EDMA port GMAC%d done\n", port_id);
+ return ret;
+
+register_netdev_fail:
+ ppe_port_phylink_destroy(port);
+port_phylink_setup_fail:
+ free_netdev(netdev);
+ edma_ctx->netdev_arr[port_id - 1] = NULL;
+
+ return ret;
+}
--- /dev/null
+++ b/drivers/net/ethernet/qualcomm/ppe/edma_port.h
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: GPL-2.0-only
+ * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef __EDMA_PORTS__
+#define __EDMA_PORTS__
+
+#include "ppe_port.h"
+
+#define EDMA_NETDEV_FEATURES (NETIF_F_FRAGLIST \
+ | NETIF_F_SG \
+ | NETIF_F_RXCSUM \
+ | NETIF_F_HW_CSUM \
+ | NETIF_F_TSO \
+ | NETIF_F_TSO6)
+
+/**
+ * struct edma_port_priv - EDMA port priv structure.
+ * @ppe_port: Pointer to PPE port
+ * @netdev: Corresponding netdevice
+ * @flags: Feature flags
+ */
+struct edma_port_priv {
+ struct ppe_port *ppe_port;
+ struct net_device *netdev;
+ unsigned long flags;
+};
+
+void edma_port_destroy(struct ppe_port *port);
+int edma_port_setup(struct ppe_port *port);
+#endif
--- a/drivers/net/ethernet/qualcomm/ppe/ppe_port.c
+++ b/drivers/net/ethernet/qualcomm/ppe/ppe_port.c
@@ -13,6 +13,7 @@
#include <linux/regmap.h>
#include <linux/rtnetlink.h>
+#include "edma_port.h"
#include "ppe.h"
#include "ppe_port.h"
#include "ppe_regs.h"
@@ -1277,12 +1278,26 @@ int ppe_port_mac_init(struct ppe_device
goto err_port_node;
}
+ ret = edma_port_setup(&ppe_ports->port[i]);
+ if (ret) {
+ dev_err(ppe_dev->dev, "QCOM EDMA port setup failed\n");
+ i--;
+ goto err_port_setup;
+ }
+
i++;
}
of_node_put(ports_node);
return 0;
+err_port_setup:
+ /* Destroy edma ports created till now */
+ while (i >= 0) {
+ edma_port_destroy(&ppe_ports->port[i]);
+ i--;
+ }
+
err_port_clk:
for (j = 0; j < i; j++)
ppe_port_clock_deinit(&ppe_ports->port[j]);
@@ -1307,6 +1322,10 @@ void ppe_port_mac_deinit(struct ppe_devi
for (i = 0; i < ppe_dev->ports->num; i++) {
ppe_port = &ppe_dev->ports->port[i];
+
+ /* Destroy all phylinks and edma ports */
+ edma_port_destroy(ppe_port);
+
ppe_port_clock_deinit(ppe_port);
}
}