ath79/mikrotik: use routerbootpart partitions
[oweals/openwrt.git] / target / linux / layerscape / patches-5.4 / 701-net-0401-fsl_qbman-Framework-for-enabling-Link-status-notific.patch
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