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