b4767511f46d6d17bb2b23fd4f975a6c97bec8c5
[openwrt/staging/ldir.git] /
1 From 136d46d2fa27815cc4cc3a57d5e3d54523028768 Mon Sep 17 00:00:00 2001
2 From: Sachin Saxena <sachin.saxena@nxp.com>
3 Date: Thu, 19 Dec 2019 12:57:35 +0530
4 Subject: [PATCH] fsl_qbman: Framework for enabling Link status notification
5
6 - This will enable link update event notification for
7 user space USDPAA application.
8
9 Signed-off-by: Sachin Saxena <sachin.saxena@nxp.com>
10 DPDK-2128
11 (cherry picked from commit fb53c813a779cc3fc28c8ed3fc8bc0dde24db0ea)
12 ---
13 drivers/staging/fsl_qbman/Makefile | 4 +
14 drivers/staging/fsl_qbman/fsl_usdpaa.c | 278 ++++++++++++++++++++++++++++++++-
15 include/linux/fsl_usdpaa.h | 32 ++++
16 3 files changed, 313 insertions(+), 1 deletion(-)
17
18 --- a/drivers/staging/fsl_qbman/Makefile
19 +++ b/drivers/staging/fsl_qbman/Makefile
20 @@ -1,5 +1,9 @@
21 subdir-ccflags-y := -Werror
22
23 +# Include netcomm SW specific definitions
24 +include $(srctree)/drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk
25 +ccflags-y += -I$(NET_DPA)
26 +
27 # Common
28 obj-$(CONFIG_FSL_SDK_DPA) += dpa_alloc.o
29 obj-$(CONFIG_FSL_SDK_DPA) += qbman_driver.o
30 --- a/drivers/staging/fsl_qbman/fsl_usdpaa.c
31 +++ b/drivers/staging/fsl_qbman/fsl_usdpaa.c
32 @@ -18,6 +18,8 @@
33 #include <linux/slab.h>
34 #include <linux/mman.h>
35 #include <linux/of_reserved_mem.h>
36 +#include <linux/eventfd.h>
37 +#include <linux/fdtable.h>
38
39 #if !(defined(CONFIG_ARM) || defined(CONFIG_ARM64))
40 #include <mm/mmu_decl.h>
41 @@ -27,6 +29,26 @@
42 #include <linux/fsl_usdpaa.h>
43 #include "bman_low.h"
44 #include "qman_low.h"
45 +/* Headers requires for
46 + * Link status support
47 + */
48 +#include <linux/device.h>
49 +#include <linux/of_mdio.h>
50 +#include "mac.h"
51 +#include "dpaa_eth_common.h"
52 +
53 +/* Private data for Proxy Interface */
54 +struct dpa_proxy_priv_s {
55 + struct mac_device *mac_dev;
56 + struct eventfd_ctx *efd_ctx;
57 +};
58 +/* Interface Helpers */
59 +static inline struct device *get_dev_ptr(char *if_name);
60 +static void phy_link_updates(struct net_device *net_dev);
61 +/* IOCTL handlers */
62 +static inline int ioctl_usdpaa_get_link_status(char *if_name);
63 +static int ioctl_en_if_link_status(struct usdpaa_ioctl_link_status *args);
64 +static int ioctl_disable_if_link_status(char *if_name);
65
66 /* Physical address range of the memory reservation, exported for mm/mem.c */
67 static u64 phys_start;
68 @@ -556,7 +578,6 @@ static bool check_portal_channel(void *c
69
70
71
72 -
73 static int usdpaa_release(struct inode *inode, struct file *filp)
74 {
75 int err = 0;
76 @@ -1656,6 +1677,220 @@ found:
77 return 0;
78 }
79
80 +
81 +static inline struct device *get_dev_ptr(char *if_name)
82 +{
83 + struct device *dev;
84 + char node[NODE_NAME_LEN];
85 +
86 + sprintf(node, "soc:fsl,dpaa:%s",if_name);
87 + dev = bus_find_device_by_name(&platform_bus_type, NULL, node);
88 + if (dev == NULL) {
89 + pr_err(KBUILD_MODNAME "IF %s not found\n", if_name);
90 + return NULL;
91 + }
92 + pr_debug("%s: found dev 0x%lX for If %s ,dev->platform_data %p\n",
93 + __func__, (unsigned long)dev,
94 + if_name, dev->platform_data);
95 +
96 + return dev;
97 +}
98 +
99 +/* This function will return Current link status of the device
100 + * '1' if Link is UP, '0' otherwise.
101 + *
102 + * Input parameter:
103 + * if_name: Interface node name
104 + *
105 + */
106 +static inline int ioctl_usdpaa_get_link_status(char *if_name)
107 +{
108 + struct net_device *net_dev = NULL;
109 + struct device *dev;
110 +
111 + dev = get_dev_ptr(if_name);
112 + if (dev == NULL)
113 + return -ENODEV;
114 + net_dev = dev->platform_data;
115 + if (net_dev == NULL)
116 + return -ENODEV;
117 +
118 + if (test_bit(__LINK_STATE_NOCARRIER, &net_dev->state))
119 + return 0; /* Link is DOWN */
120 + else
121 + return 1; /* Link is UP */
122 +}
123 +
124 +
125 +/* Link Status Callback Function
126 + * This function will be resgitered to PHY framework to get
127 + * Link update notifications and should be responsible for waking up
128 + * user space task when there is a link update notification.
129 + */
130 +static void phy_link_updates(struct net_device *net_dev)
131 +{
132 + struct dpa_proxy_priv_s *priv = NULL;
133 +
134 + pr_debug("%s: Link '%s': Speed '%d-Mbps': Autoneg '%d': Duplex '%d'\n",
135 + net_dev->name,
136 + ioctl_usdpaa_get_link_status(net_dev->name)?"UP":"DOWN",
137 + net_dev->phydev->speed,
138 + net_dev->phydev->autoneg,
139 + net_dev->phydev->duplex);
140 +
141 + /* Wake up the user space context to notify PHY update */
142 + priv = netdev_priv(net_dev);
143 + eventfd_signal(priv->efd_ctx, 1);
144 +}
145 +
146 +
147 +/* IOCTL handler for enabling Link status request for a given interface
148 + * Input parameters:
149 + * args->if_name: This the network interface node name as defind in
150 + * device tree file. Currently, it has format of
151 + * "ethernet@x" type for each interface.
152 + * args->efd: The eventfd value which should be waked up when
153 + * there is any link update received.
154 + */
155 +static int ioctl_en_if_link_status(struct usdpaa_ioctl_link_status *args)
156 +{
157 + struct net_device *net_dev = NULL;
158 + struct dpa_proxy_priv_s *priv = NULL;
159 + struct device *dev;
160 + struct mac_device *mac_dev;
161 + struct proxy_device *proxy_dev;
162 + struct task_struct *userspace_task = NULL;
163 + struct file *efd_file = NULL;
164 +
165 + dev = get_dev_ptr(args->if_name);
166 + if (dev == NULL)
167 + return -ENODEV;
168 + /* Utilize dev->platform_data to save netdevice
169 + pointer as it will not be registered */
170 + if (dev->platform_data) {
171 + pr_debug("%s: IF %s already initialized\n",
172 + __func__, args->if_name);
173 + /* This will happen when application is not able to initiate
174 + * cleanup in last run. We still need to save the new
175 + * eventfd context.
176 + */
177 + net_dev = dev->platform_data;
178 + priv = netdev_priv(net_dev);
179 +
180 + /* Get current task context from which IOCTL was called */
181 + userspace_task = current;
182 +
183 + rcu_read_lock();
184 + efd_file = fcheck_files(userspace_task->files, args->efd);
185 + rcu_read_unlock();
186 +
187 + priv->efd_ctx = eventfd_ctx_fileget(efd_file);
188 + if (!priv->efd_ctx) {
189 + pr_err(KBUILD_MODNAME "get eventfd context failed\n");
190 + /* Free the allocated memory for net device */
191 + dev->platform_data = NULL;
192 + free_netdev(net_dev);
193 + return -EINVAL;
194 + }
195 + /* Since there will be NO PHY update as link is already setup,
196 + * wake user context once so that current PHY status can
197 + * be fetched.
198 + */
199 + phy_link_updates(net_dev);
200 + return 0;
201 + }
202 +
203 + proxy_dev = dev_get_drvdata(dev);
204 + mac_dev = proxy_dev->mac_dev;
205 + /* Allocate an dummy net device for proxy interface */
206 + net_dev = alloc_etherdev(sizeof(*priv));
207 + if (!net_dev) {
208 + pr_err(KBUILD_MODNAME "alloc_etherdev failed\n");
209 + return -ENOMEM;
210 + } else {
211 + SET_NETDEV_DEV(net_dev, dev);
212 + priv = netdev_priv(net_dev);
213 + priv->mac_dev = mac_dev;
214 + /* Get current task context from which IOCTL was called */
215 + userspace_task = current;
216 +
217 + rcu_read_lock();
218 + efd_file = fcheck_files(userspace_task->files, args->efd);
219 + rcu_read_unlock();
220 +
221 + priv->efd_ctx = eventfd_ctx_fileget(efd_file);
222 +
223 + if (!priv->efd_ctx) {
224 + pr_err(KBUILD_MODNAME "get eventfd context failed\n");
225 + /* Free the allocated memory for net device */
226 + free_netdev(net_dev);
227 + return -EINVAL;
228 + }
229 + strncpy(net_dev->name, args->if_name, IF_NAME_MAX_LEN);
230 + dev->platform_data = net_dev;
231 + }
232 +
233 + pr_debug("%s: mac_dev %p cell_index %d\n",
234 + __func__, mac_dev, mac_dev->cell_index);
235 + mac_dev->phy_dev = of_phy_connect(net_dev, mac_dev->phy_node,
236 + phy_link_updates, 0, mac_dev->phy_if);
237 + if (unlikely(mac_dev->phy_dev == NULL) || IS_ERR(mac_dev->phy_dev)) {
238 + pr_err("%s: --------Error in PHY Connect\n", __func__);
239 + /* Free the allocated memory for net device */
240 + free_netdev(net_dev);
241 + return -ENODEV;
242 + }
243 + net_dev->phydev = mac_dev->phy_dev;
244 + mac_dev->start(mac_dev);
245 + pr_debug("%s: --- PHY connected for %s\n", __func__, args->if_name);
246 +
247 + return 0;
248 +}
249 +
250 +/* IOCTL handler for disabling Link status for a given interface
251 + * Input parameters:
252 + * if_name: This the network interface node name as defind in
253 + * device tree file. Currently, it has format of
254 + * "ethernet@x" type for each interface.
255 + */
256 +static int ioctl_disable_if_link_status(char *if_name)
257 +{
258 + struct net_device *net_dev = NULL;
259 + struct device *dev;
260 + struct mac_device *mac_dev;
261 + struct proxy_device *proxy_dev;
262 + struct dpa_proxy_priv_s *priv = NULL;
263 +
264 + dev = get_dev_ptr(if_name);
265 + if (dev == NULL)
266 + return -ENODEV;
267 + /* Utilize dev->platform_data to save netdevice
268 + pointer as it will not be registered */
269 + if (!dev->platform_data) {
270 + pr_debug("%s: IF %s already Disabled for Link status\n",
271 + __func__, if_name);
272 + return 0;
273 + }
274 +
275 + net_dev = dev->platform_data;
276 + proxy_dev = dev_get_drvdata(dev);
277 + mac_dev = proxy_dev->mac_dev;
278 + mac_dev->stop(mac_dev);
279 +
280 + priv = netdev_priv(net_dev);
281 + eventfd_ctx_put(priv->efd_ctx);
282 +
283 + /* This will also deregister the call back */
284 + phy_disconnect(mac_dev->phy_dev);
285 + phy_resume(mac_dev->phy_dev);
286 +
287 + free_netdev(net_dev);
288 + dev->platform_data = NULL;
289 +
290 + pr_debug("%s: Link status Disabled for %s\n", __func__, if_name);
291 + return 0;
292 +}
293 +
294 static long usdpaa_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
295 {
296 struct ctx *ctx = fp->private_data;
297 @@ -1722,6 +1957,47 @@ static long usdpaa_ioctl(struct file *fp
298 return -EFAULT;
299 return ioctl_free_raw_portal(fp, ctx, &input);
300 }
301 + case USDPAA_IOCTL_ENABLE_LINK_STATUS_INTERRUPT:
302 + {
303 + struct usdpaa_ioctl_link_status input;
304 + int ret;
305 +
306 + if (copy_from_user(&input, a, sizeof(input)))
307 + return -EFAULT;
308 + ret = ioctl_en_if_link_status(&input);
309 + if (ret)
310 + pr_err("Error(%d) enable link interrupt:IF: %s\n",
311 + ret, input.if_name);
312 + return ret;
313 + }
314 + case USDPAA_IOCTL_DISABLE_LINK_STATUS_INTERRUPT:
315 + {
316 + char *input;
317 + int ret;
318 +
319 + if (copy_from_user(&input, a, sizeof(input)))
320 + return -EFAULT;
321 + ret = ioctl_disable_if_link_status(input);
322 + if (ret)
323 + pr_err("Error(%d) Disabling link interrupt:IF: %s\n",
324 + ret, input);
325 + return ret;
326 + }
327 + case USDPAA_IOCTL_GET_LINK_STATUS:
328 + {
329 + struct usdpaa_ioctl_link_status_args input;
330 +
331 + if (copy_from_user(&input, a, sizeof(input)))
332 + return -EFAULT;
333 +
334 + input.link_status = ioctl_usdpaa_get_link_status(input.if_name);
335 + if (input.link_status < 0)
336 + return input.link_status;
337 + if (copy_to_user(a, &input, sizeof(input)))
338 + return -EFAULT;
339 +
340 + return 0;
341 + }
342 }
343 return -EINVAL;
344 }
345 --- a/include/linux/fsl_usdpaa.h
346 +++ b/include/linux/fsl_usdpaa.h
347 @@ -365,6 +365,38 @@ int dpa_alloc_pop(struct dpa_alloc *allo
348 int dpa_alloc_check(struct dpa_alloc *list, u32 id);
349 #endif /* __KERNEL__ */
350
351 +
352 +/************************************
353 + * Link Status support for user space
354 + * interface
355 + ************************************/
356 +#define IF_NAME_MAX_LEN 16
357 +#define NODE_NAME_LEN 32
358 +
359 +struct usdpaa_ioctl_link_status {
360 + /* network device node name */
361 + char if_name[IF_NAME_MAX_LEN];
362 + /* Eventfd value */
363 + uint32_t efd;
364 +};
365 +
366 +#define USDPAA_IOCTL_ENABLE_LINK_STATUS_INTERRUPT \
367 + _IOW(USDPAA_IOCTL_MAGIC, 0x0E, struct usdpaa_ioctl_link_status)
368 +
369 +#define USDPAA_IOCTL_DISABLE_LINK_STATUS_INTERRUPT \
370 + _IOW(USDPAA_IOCTL_MAGIC, 0x0F, char *)
371 +
372 +struct usdpaa_ioctl_link_status_args {
373 + /* network device node name */
374 + char if_name[IF_NAME_MAX_LEN];
375 + /* link status(UP/DOWN) */
376 + int link_status;
377 +};
378 +
379 +#define USDPAA_IOCTL_GET_LINK_STATUS \
380 + _IOWR(USDPAA_IOCTL_MAGIC, 0x10, struct usdpaa_ioctl_link_status_args)
381 +
382 +
383 #ifdef __cplusplus
384 }
385 #endif