4d89b875a3c1cb56538f0a8723a08334dcbe78a1
[openwrt/staging/stintel.git] /
1 From cbcaf81cd148b77ee0570a482b536f269a9f6657 Mon Sep 17 00:00:00 2001
2 From: Suruchi Agarwal <quic_suruchia@quicinc.com>
3 Date: Thu, 21 Mar 2024 16:14:46 -0700
4 Subject: [PATCH 39/50] net: ethernet: qualcomm: Add netdevice support for QCOM
5 IPQ9574 chipset.
6
7 Add EDMA ports and netdevice operations for QCOM IPQ9574 chipset.
8
9 Change-Id: I08b2eff52b4ef0d6d428c1c416f5580ef010973f
10 Co-developed-by: Pavithra R <quic_pavir@quicinc.com>
11 Signed-off-by: Pavithra R <quic_pavir@quicinc.com>
12 Signed-off-by: Suruchi Agarwal <quic_suruchia@quicinc.com>
13 ---
14 drivers/net/ethernet/qualcomm/ppe/Makefile | 2 +-
15 drivers/net/ethernet/qualcomm/ppe/edma.h | 3 +
16 drivers/net/ethernet/qualcomm/ppe/edma_port.c | 270 ++++++++++++++++++
17 drivers/net/ethernet/qualcomm/ppe/edma_port.h | 31 ++
18 drivers/net/ethernet/qualcomm/ppe/ppe_port.c | 19 ++
19 5 files changed, 324 insertions(+), 1 deletion(-)
20 create mode 100644 drivers/net/ethernet/qualcomm/ppe/edma_port.c
21 create mode 100644 drivers/net/ethernet/qualcomm/ppe/edma_port.h
22
23 diff --git a/drivers/net/ethernet/qualcomm/ppe/Makefile b/drivers/net/ethernet/qualcomm/ppe/Makefile
24 index 7fea135ceb36..e26677644aa9 100644
25 --- a/drivers/net/ethernet/qualcomm/ppe/Makefile
26 +++ b/drivers/net/ethernet/qualcomm/ppe/Makefile
27 @@ -7,4 +7,4 @@ obj-$(CONFIG_QCOM_PPE) += qcom-ppe.o
28 qcom-ppe-objs := ppe.o ppe_config.o ppe_api.o ppe_debugfs.o ppe_port.o
29
30 #EDMA
31 -qcom-ppe-objs += edma.o
32 \ No newline at end of file
33 +qcom-ppe-objs += edma.o edma_port.o
34 \ No newline at end of file
35 diff --git a/drivers/net/ethernet/qualcomm/ppe/edma.h b/drivers/net/ethernet/qualcomm/ppe/edma.h
36 index 6bad51c976dd..5261002f883d 100644
37 --- a/drivers/net/ethernet/qualcomm/ppe/edma.h
38 +++ b/drivers/net/ethernet/qualcomm/ppe/edma.h
39 @@ -26,6 +26,9 @@
40 /* Number of PPE queue priorities supported per ARM core. */
41 #define EDMA_PRI_MAX_PER_CORE 8
42
43 +/* Interface ID start. */
44 +#define EDMA_START_IFNUM 1
45 +
46 /**
47 * struct edma_ring_info - EDMA ring data structure.
48 * @max_rings: Maximum number of rings
49 diff --git a/drivers/net/ethernet/qualcomm/ppe/edma_port.c b/drivers/net/ethernet/qualcomm/ppe/edma_port.c
50 new file mode 100644
51 index 000000000000..6292b83d746d
52 --- /dev/null
53 +++ b/drivers/net/ethernet/qualcomm/ppe/edma_port.c
54 @@ -0,0 +1,270 @@
55 +// SPDX-License-Identifier: GPL-2.0-only
56 + /* Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
57 + */
58 +
59 +/* EDMA port initialization, configuration and netdevice ops handling */
60 +
61 +#include <linux/etherdevice.h>
62 +#include <linux/net.h>
63 +#include <linux/netdevice.h>
64 +#include <linux/of_net.h>
65 +#include <linux/phylink.h>
66 +#include <linux/printk.h>
67 +
68 +#include "edma.h"
69 +#include "edma_port.h"
70 +#include "ppe_regs.h"
71 +
72 +/* Number of netdev queues. */
73 +#define EDMA_NETDEV_QUEUE_NUM 4
74 +
75 +static u16 __maybe_unused edma_port_select_queue(__maybe_unused struct net_device *netdev,
76 + __maybe_unused struct sk_buff *skb,
77 + __maybe_unused struct net_device *sb_dev)
78 +{
79 + int cpu = get_cpu();
80 +
81 + put_cpu();
82 +
83 + return cpu;
84 +}
85 +
86 +static int edma_port_open(struct net_device *netdev)
87 +{
88 + struct edma_port_priv *port_priv = (struct edma_port_priv *)netdev_priv(netdev);
89 + struct ppe_port *ppe_port;
90 +
91 + if (!port_priv)
92 + return -EINVAL;
93 +
94 + /* Inform the Linux Networking stack about the hardware capability of
95 + * checksum offloading and other features. Each port is
96 + * responsible to maintain the feature set it supports.
97 + */
98 + netdev->features |= EDMA_NETDEV_FEATURES;
99 + netdev->hw_features |= EDMA_NETDEV_FEATURES;
100 + netdev->vlan_features |= EDMA_NETDEV_FEATURES;
101 + netdev->wanted_features |= EDMA_NETDEV_FEATURES;
102 +
103 + ppe_port = port_priv->ppe_port;
104 +
105 + if (ppe_port->phylink)
106 + phylink_start(ppe_port->phylink);
107 +
108 + netif_start_queue(netdev);
109 +
110 + return 0;
111 +}
112 +
113 +static int edma_port_close(struct net_device *netdev)
114 +{
115 + struct edma_port_priv *port_priv = (struct edma_port_priv *)netdev_priv(netdev);
116 + struct ppe_port *ppe_port;
117 +
118 + if (!port_priv)
119 + return -EINVAL;
120 +
121 + netif_stop_queue(netdev);
122 +
123 + ppe_port = port_priv->ppe_port;
124 +
125 + /* Phylink close. */
126 + if (ppe_port->phylink)
127 + phylink_stop(ppe_port->phylink);
128 +
129 + return 0;
130 +}
131 +
132 +static int edma_port_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
133 +{
134 + struct edma_port_priv *port_priv = (struct edma_port_priv *)netdev_priv(netdev);
135 + struct ppe_port *ppe_port;
136 + int ret = -EINVAL;
137 +
138 + if (!port_priv)
139 + return -EINVAL;
140 +
141 + ppe_port = port_priv->ppe_port;
142 + if (ppe_port->phylink)
143 + return phylink_mii_ioctl(ppe_port->phylink, ifr, cmd);
144 +
145 + return ret;
146 +}
147 +
148 +static int edma_port_change_mtu(struct net_device *netdev, int mtu)
149 +{
150 + struct edma_port_priv *port_priv = (struct edma_port_priv *)netdev_priv(netdev);
151 +
152 + if (!port_priv)
153 + return -EINVAL;
154 +
155 + netdev->mtu = mtu;
156 +
157 + return ppe_port_set_maxframe(port_priv->ppe_port, mtu);
158 +}
159 +
160 +static netdev_features_t edma_port_feature_check(__maybe_unused struct sk_buff *skb,
161 + __maybe_unused struct net_device *netdev,
162 + netdev_features_t features)
163 +{
164 + return features;
165 +}
166 +
167 +static void edma_port_get_stats64(struct net_device *netdev,
168 + struct rtnl_link_stats64 *stats)
169 +{
170 + struct edma_port_priv *port_priv = (struct edma_port_priv *)netdev_priv(netdev);
171 +
172 + if (!port_priv)
173 + return;
174 +
175 + ppe_port_get_stats64(port_priv->ppe_port, stats);
176 +}
177 +
178 +static int edma_port_set_mac_address(struct net_device *netdev, void *macaddr)
179 +{
180 + struct edma_port_priv *port_priv = (struct edma_port_priv *)netdev_priv(netdev);
181 + struct sockaddr *addr = (struct sockaddr *)macaddr;
182 + int ret;
183 +
184 + if (!port_priv)
185 + return -EINVAL;
186 +
187 + netdev_dbg(netdev, "AddrFamily: %d, %0x:%0x:%0x:%0x:%0x:%0x\n",
188 + addr->sa_family, addr->sa_data[0], addr->sa_data[1],
189 + addr->sa_data[2], addr->sa_data[3], addr->sa_data[4],
190 + addr->sa_data[5]);
191 +
192 + ret = eth_prepare_mac_addr_change(netdev, addr);
193 + if (ret)
194 + return ret;
195 +
196 + if (ppe_port_set_mac_address(port_priv->ppe_port, (u8 *)addr)) {
197 + netdev_err(netdev, "set mac address failed for dev: %s\n", netdev->name);
198 + return -EINVAL;
199 + }
200 +
201 + eth_commit_mac_addr_change(netdev, addr);
202 +
203 + return 0;
204 +}
205 +
206 +static const struct net_device_ops edma_port_netdev_ops = {
207 + .ndo_open = edma_port_open,
208 + .ndo_stop = edma_port_close,
209 + .ndo_get_stats64 = edma_port_get_stats64,
210 + .ndo_set_mac_address = edma_port_set_mac_address,
211 + .ndo_validate_addr = eth_validate_addr,
212 + .ndo_change_mtu = edma_port_change_mtu,
213 + .ndo_eth_ioctl = edma_port_ioctl,
214 + .ndo_features_check = edma_port_feature_check,
215 + .ndo_select_queue = edma_port_select_queue,
216 +};
217 +
218 +/**
219 + * edma_port_destroy - EDMA port destroy.
220 + * @port: PPE port
221 + *
222 + * Unregister and free the netdevice.
223 + */
224 +void edma_port_destroy(struct ppe_port *port)
225 +{
226 + int port_id = port->port_id;
227 + struct net_device *netdev = edma_ctx->netdev_arr[port_id - 1];
228 +
229 + unregister_netdev(netdev);
230 + free_netdev(netdev);
231 + ppe_port_phylink_destroy(port);
232 + edma_ctx->netdev_arr[port_id - 1] = NULL;
233 +}
234 +
235 +/**
236 + * edma_port_setup - EDMA port Setup.
237 + * @port: PPE port
238 + *
239 + * Initialize and register the netdevice.
240 + *
241 + * Return 0 on success, negative error code on failure.
242 + */
243 +int edma_port_setup(struct ppe_port *port)
244 +{
245 + struct ppe_device *ppe_dev = edma_ctx->ppe_dev;
246 + struct device_node *np = port->np;
247 + struct edma_port_priv *port_priv;
248 + int port_id = port->port_id;
249 + struct net_device *netdev;
250 + u8 mac_addr[ETH_ALEN];
251 + int ret = 0;
252 + u8 *maddr;
253 +
254 + netdev = alloc_etherdev_mqs(sizeof(struct edma_port_priv),
255 + EDMA_NETDEV_QUEUE_NUM, EDMA_NETDEV_QUEUE_NUM);
256 + if (!netdev) {
257 + pr_err("alloc_etherdev() failed\n");
258 + return -ENOMEM;
259 + }
260 +
261 + SET_NETDEV_DEV(netdev, ppe_dev->dev);
262 + netdev->dev.of_node = np;
263 +
264 + /* max_mtu is set to 1500 in ether_setup(). */
265 + netdev->max_mtu = ETH_MAX_MTU;
266 +
267 + port_priv = netdev_priv(netdev);
268 + memset((void *)port_priv, 0, sizeof(struct edma_port_priv));
269 +
270 + port_priv->ppe_port = port;
271 + port_priv->netdev = netdev;
272 + netdev->watchdog_timeo = 5 * HZ;
273 + netdev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
274 + netdev->netdev_ops = &edma_port_netdev_ops;
275 + netdev->gso_max_segs = GSO_MAX_SEGS;
276 +
277 + maddr = mac_addr;
278 + if (of_get_mac_address(np, maddr))
279 + maddr = NULL;
280 +
281 + if (maddr && is_valid_ether_addr(maddr)) {
282 + eth_hw_addr_set(netdev, maddr);
283 + } else {
284 + eth_hw_addr_random(netdev);
285 + netdev_info(netdev, "GMAC%d Using random MAC address - %pM\n",
286 + port_id, netdev->dev_addr);
287 + }
288 +
289 + netdev_dbg(netdev, "Configuring the port %s(qcom-id:%d)\n",
290 + netdev->name, port_id);
291 +
292 + /* We expect 'port_id' to correspond to ports numbers on SoC.
293 + * These begin from '1' and hence we subtract
294 + * one when using it as an array index.
295 + */
296 + edma_ctx->netdev_arr[port_id - 1] = netdev;
297 +
298 + /* Setup phylink. */
299 + ret = ppe_port_phylink_setup(port, netdev);
300 + if (ret) {
301 + netdev_dbg(netdev, "EDMA port phylink setup for netdevice %s\n",
302 + netdev->name);
303 + goto port_phylink_setup_fail;
304 + }
305 +
306 + /* Register the network interface. */
307 + ret = register_netdev(netdev);
308 + if (ret) {
309 + netdev_dbg(netdev, "Error registering netdevice %s\n",
310 + netdev->name);
311 + goto register_netdev_fail;
312 + }
313 +
314 + netdev_dbg(netdev, "Setup EDMA port GMAC%d done\n", port_id);
315 + return ret;
316 +
317 +register_netdev_fail:
318 + ppe_port_phylink_destroy(port);
319 +port_phylink_setup_fail:
320 + free_netdev(netdev);
321 + edma_ctx->netdev_arr[port_id - 1] = NULL;
322 +
323 + return ret;
324 +}
325 diff --git a/drivers/net/ethernet/qualcomm/ppe/edma_port.h b/drivers/net/ethernet/qualcomm/ppe/edma_port.h
326 new file mode 100644
327 index 000000000000..0f2deb39556e
328 --- /dev/null
329 +++ b/drivers/net/ethernet/qualcomm/ppe/edma_port.h
330 @@ -0,0 +1,31 @@
331 +/* SPDX-License-Identifier: GPL-2.0-only
332 + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
333 + */
334 +
335 +#ifndef __EDMA_PORTS__
336 +#define __EDMA_PORTS__
337 +
338 +#include "ppe_port.h"
339 +
340 +#define EDMA_NETDEV_FEATURES (NETIF_F_FRAGLIST \
341 + | NETIF_F_SG \
342 + | NETIF_F_RXCSUM \
343 + | NETIF_F_HW_CSUM \
344 + | NETIF_F_TSO \
345 + | NETIF_F_TSO6)
346 +
347 +/**
348 + * struct edma_port_priv - EDMA port priv structure.
349 + * @ppe_port: Pointer to PPE port
350 + * @netdev: Corresponding netdevice
351 + * @flags: Feature flags
352 + */
353 +struct edma_port_priv {
354 + struct ppe_port *ppe_port;
355 + struct net_device *netdev;
356 + unsigned long flags;
357 +};
358 +
359 +void edma_port_destroy(struct ppe_port *port);
360 +int edma_port_setup(struct ppe_port *port);
361 +#endif
362 diff --git a/drivers/net/ethernet/qualcomm/ppe/ppe_port.c b/drivers/net/ethernet/qualcomm/ppe/ppe_port.c
363 index 52820e2eedf8..05c52ba07aef 100644
364 --- a/drivers/net/ethernet/qualcomm/ppe/ppe_port.c
365 +++ b/drivers/net/ethernet/qualcomm/ppe/ppe_port.c
366 @@ -13,6 +13,7 @@
367 #include <linux/regmap.h>
368 #include <linux/rtnetlink.h>
369
370 +#include "edma_port.h"
371 #include "ppe.h"
372 #include "ppe_port.h"
373 #include "ppe_regs.h"
374 @@ -1277,12 +1278,26 @@ int ppe_port_mac_init(struct ppe_device *ppe_dev)
375 goto err_port_node;
376 }
377
378 + ret = edma_port_setup(&ppe_ports->port[i]);
379 + if (ret) {
380 + dev_err(ppe_dev->dev, "QCOM EDMA port setup failed\n");
381 + i--;
382 + goto err_port_setup;
383 + }
384 +
385 i++;
386 }
387
388 of_node_put(ports_node);
389 return 0;
390
391 +err_port_setup:
392 + /* Destroy edma ports created till now */
393 + while (i >= 0) {
394 + edma_port_destroy(&ppe_ports->port[i]);
395 + i--;
396 + }
397 +
398 err_port_clk:
399 for (j = 0; j < i; j++)
400 ppe_port_clock_deinit(&ppe_ports->port[j]);
401 @@ -1307,6 +1322,10 @@ void ppe_port_mac_deinit(struct ppe_device *ppe_dev)
402
403 for (i = 0; i < ppe_dev->ports->num; i++) {
404 ppe_port = &ppe_dev->ports->port[i];
405 +
406 + /* Destroy all phylinks and edma ports */
407 + edma_port_destroy(ppe_port);
408 +
409 ppe_port_clock_deinit(ppe_port);
410 }
411 }
412 --
413 2.45.2
414