| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397 |
- From 5dc80c468c668d855d76b323f09bbadb95cc3147 Mon Sep 17 00:00:00 2001
- From: Suruchi Agarwal <[email protected]>
- 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 <[email protected]>
- Signed-off-by: Pavithra R <[email protected]>
- Signed-off-by: Suruchi Agarwal <[email protected]>
- ---
- 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);
- }
- }
|