c445952222b197c205e960cb91510a1ddf376ae3
[openwrt/openwrt.git] /
1 From a41d4af2ed4b02edca9d7f69955893d407274dc2 Mon Sep 17 00:00:00 2001
2 From: Shreyansh Jain <shreyansh.jain@nxp.com>
3 Date: Wed, 6 Jun 2018 14:19:34 +0530
4 Subject: [PATCH] staging: fsl_ppfe: add support for a char dev for link status
5
6 Read and IOCTL support is added. Application would need to open,
7 read/ioctl the /dev/pfe_us_cdev device.
8 select is pending as it requires a wait_queue.
9
10 Signed-off-by: Shreyansh Jain <shreyansh.jain@nxp.com>
11 Signed-off-by: Calvin Johnson <calvin.johnson@nxp.com>
12 ---
13 drivers/staging/fsl_ppfe/Makefile | 3 +-
14 drivers/staging/fsl_ppfe/pfe_cdev.c | 207 ++++++++++++++++++++++++++++++++++++
15 drivers/staging/fsl_ppfe/pfe_cdev.h | 52 +++++++++
16 drivers/staging/fsl_ppfe/pfe_eth.c | 14 +++
17 drivers/staging/fsl_ppfe/pfe_mod.c | 14 +++
18 5 files changed, 289 insertions(+), 1 deletion(-)
19 create mode 100644 drivers/staging/fsl_ppfe/pfe_cdev.c
20 create mode 100644 drivers/staging/fsl_ppfe/pfe_cdev.h
21
22 --- a/drivers/staging/fsl_ppfe/Makefile
23 +++ b/drivers/staging/fsl_ppfe/Makefile
24 @@ -16,4 +16,5 @@ pfe-y += pfe_mod.o \
25 pfe_sysfs.o \
26 pfe_debugfs.o \
27 pfe_ls1012a_platform.o \
28 - pfe_hal.o
29 + pfe_hal.o \
30 + pfe_cdev.o
31 --- /dev/null
32 +++ b/drivers/staging/fsl_ppfe/pfe_cdev.c
33 @@ -0,0 +1,207 @@
34 +/*
35 + * Copyright 2018 NXP
36 + *
37 + * This program is free software; you can redistribute it and/or modify
38 + * it under the terms of the GNU General Public License as published by
39 + * the Free Software Foundation; either version 2 of the License, or
40 + * (at your option) any later version.
41 + *
42 + * This program is distributed in the hope that it will be useful,
43 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
44 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
45 + * GNU General Public License for more details.
46 + *
47 + * You should have received a copy of the GNU General Public License
48 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
49 + */
50 +
51 +/* @pfe_cdev.c.
52 + * Dummy device representing the PFE US in userspace.
53 + * - used for interacting with the kernel layer for link status
54 + */
55 +
56 +#include "pfe_cdev.h"
57 +
58 +static int pfe_majno;
59 +static struct class *pfe_char_class;
60 +static struct device *pfe_char_dev;
61 +
62 +struct pfe_shared_info link_states[PFE_CDEV_ETH_COUNT];
63 +
64 +static int pfe_cdev_open(struct inode *inp, struct file *fp)
65 +{
66 + pr_debug("PFE CDEV device opened.\n");
67 + return 0;
68 +}
69 +
70 +static ssize_t pfe_cdev_read(struct file *fp, char *buf,
71 + size_t len, loff_t *off)
72 +{
73 + int ret = 0;
74 +
75 + pr_info("PFE CDEV attempt copying (%lu) size of user.\n",
76 + sizeof(link_states));
77 +
78 + pr_debug("Dump link_state on screen before copy_to_user\n");
79 + for (; ret < PFE_CDEV_ETH_COUNT; ret++) {
80 + pr_debug("%u %u", link_states[ret].phy_id,
81 + link_states[ret].state);
82 + pr_debug("\n");
83 + }
84 +
85 + /* Copy to user the value in buffer sized len */
86 + ret = copy_to_user(buf, &link_states, sizeof(link_states));
87 + if (ret != 0) {
88 + pr_err("Failed to send (%d)bytes of (%lu) requested.\n",
89 + ret, len);
90 + return -EFAULT;
91 + }
92 +
93 + /* offset set back to 0 as there is contextual reading offset */
94 + *off = 0;
95 + pr_debug("Read of (%lu) bytes performed.\n", sizeof(link_states));
96 +
97 + return sizeof(link_states);
98 +}
99 +
100 +/**
101 + * This function is for getting some commands from user through non-IOCTL
102 + * channel. It can used to configure the device.
103 + * TODO: To be filled in future, if require duplex communication with user
104 + * space.
105 + */
106 +static ssize_t pfe_cdev_write(struct file *fp, const char *buf,
107 + size_t len, loff_t *off)
108 +{
109 + pr_info("PFE CDEV Write operation not supported!\n");
110 +
111 + return -EFAULT;
112 +}
113 +
114 +static int pfe_cdev_release(struct inode *inp, struct file *fp)
115 +{
116 + pr_info("PFE_CDEV: Device successfully closed\n");
117 + return 0;
118 +}
119 +
120 +static long pfe_cdev_ioctl(struct file *fp, unsigned int cmd,
121 + unsigned long arg)
122 +{
123 + int ret = -EFAULT;
124 + int __user *argp = (int __user *)arg;
125 +
126 + pr_debug("PFE CDEV IOCTL Called with cmd=(%u)\n", cmd);
127 +
128 + switch (cmd) {
129 + case PFE_CDEV_ETH0_STATE_GET:
130 + /* Return an unsigned int (link state) for ETH0 */
131 + *argp = link_states[0].state;
132 + pr_debug("Returning state=%d for ETH0\n", *argp);
133 + ret = 0;
134 + break;
135 + case PFE_CDEV_ETH1_STATE_GET:
136 + /* Return an unsigned int (link state) for ETH0 */
137 + *argp = link_states[1].state;
138 + pr_debug("Returning state=%d for ETH1\n", *argp);
139 + ret = 0;
140 + break;
141 + default:
142 + pr_info("Unsupport cmd (%d) for PFE CDEV.\n", cmd);
143 + break;
144 + };
145 +
146 + return ret;
147 +}
148 +
149 +static unsigned int pfe_cdev_poll(struct file *fp,
150 + struct poll_table_struct *wait)
151 +{
152 + pr_info("PFE CDEV poll method not supported\n");
153 + return 0;
154 +}
155 +
156 +static const struct file_operations pfe_cdev_fops = {
157 + .open = pfe_cdev_open,
158 + .read = pfe_cdev_read,
159 + .write = pfe_cdev_write,
160 + .release = pfe_cdev_release,
161 + .unlocked_ioctl = pfe_cdev_ioctl,
162 + .poll = pfe_cdev_poll,
163 +};
164 +
165 +int pfe_cdev_init(void)
166 +{
167 + int ret;
168 +
169 + pr_debug("PFE CDEV initialization begin\n");
170 +
171 + /* Register the major number for the device */
172 + pfe_majno = register_chrdev(0, PFE_CDEV_NAME, &pfe_cdev_fops);
173 + if (pfe_majno < 0) {
174 + pr_err("Unable to register PFE CDEV. PFE CDEV not available\n");
175 + ret = pfe_majno;
176 + goto cleanup;
177 + }
178 +
179 + pr_debug("PFE CDEV assigned major number: %d\n", pfe_majno);
180 +
181 + /* Register the class for the device */
182 + pfe_char_class = class_create(THIS_MODULE, PFE_CLASS_NAME);
183 + if (IS_ERR(pfe_char_class)) {
184 + pr_err(
185 + "Failed to init class for PFE CDEV. PFE CDEV not available.\n");
186 + goto cleanup;
187 + }
188 +
189 + pr_debug("PFE CDEV Class created successfully.\n");
190 +
191 + /* Create the device without any parent and without any callback data */
192 + pfe_char_dev = device_create(pfe_char_class, NULL,
193 + MKDEV(pfe_majno, 0), NULL,
194 + PFE_CDEV_NAME);
195 + if (IS_ERR(pfe_char_dev)) {
196 + pr_err("Unable to PFE CDEV device. PFE CDEV not available.\n");
197 + ret = PTR_ERR(pfe_char_dev);
198 + goto cleanup;
199 + }
200 +
201 + /* Information structure being shared with the userspace */
202 + memset(link_states, 0, sizeof(struct pfe_shared_info) *
203 + PFE_CDEV_ETH_COUNT);
204 +
205 + pr_info("PFE CDEV created: %s\n", PFE_CDEV_NAME);
206 +
207 + ret = 0;
208 + return ret;
209 +
210 +cleanup:
211 + if (!IS_ERR(pfe_char_class))
212 + class_destroy(pfe_char_class);
213 +
214 + if (pfe_majno > 0)
215 + unregister_chrdev(pfe_majno, PFE_CDEV_NAME);
216 +
217 + ret = -EFAULT;
218 + return ret;
219 +}
220 +
221 +void pfe_cdev_exit(void)
222 +{
223 + if (!IS_ERR(pfe_char_dev))
224 + device_destroy(pfe_char_class, MKDEV(pfe_majno, 0));
225 +
226 + if (!IS_ERR(pfe_char_class)) {
227 + class_unregister(pfe_char_class);
228 + class_destroy(pfe_char_class);
229 + }
230 +
231 + if (pfe_majno > 0)
232 + unregister_chrdev(pfe_majno, PFE_CDEV_NAME);
233 +
234 + /* reset the variables */
235 + pfe_majno = 0;
236 + pfe_char_class = NULL;
237 + pfe_char_dev = NULL;
238 +
239 + pr_info("PFE CDEV Removed.\n");
240 +}
241 --- /dev/null
242 +++ b/drivers/staging/fsl_ppfe/pfe_cdev.h
243 @@ -0,0 +1,52 @@
244 +/*
245 + * Copyright 2018 NXP
246 + *
247 + * This program is free software; you can redistribute it and/or modify
248 + * it under the terms of the GNU General Public License as published by
249 + * the Free Software Foundation; either version 2 of the License, or
250 + * (at your option) any later version.
251 + *
252 + * This program is distributed in the hope that it will be useful,
253 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
254 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
255 + * GNU General Public License for more details.
256 + *
257 + * You should have received a copy of the GNU General Public License
258 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
259 + */
260 +
261 +#ifndef _PFE_CDEV_H_
262 +#define _PFE_CDEV_H_
263 +
264 +#include <linux/init.h>
265 +#include <linux/device.h>
266 +#include <linux/err.h>
267 +#include <linux/kernel.h>
268 +#include <linux/fs.h>
269 +#include <linux/uaccess.h>
270 +#include <linux/poll.h>
271 +
272 +#define PFE_CDEV_NAME "pfe_us_cdev"
273 +#define PFE_CLASS_NAME "ppfe_us"
274 +
275 +/* Extracted from ls1012a_pfe_platform_data, there are 3 interfaces which are
276 + * supported by PFE driver. Should be updated if number of eth devices are
277 + * changed.
278 + */
279 +#define PFE_CDEV_ETH_COUNT 3
280 +
281 +struct pfe_shared_info {
282 + uint32_t phy_id; /* Link phy ID */
283 + uint8_t state; /* Has either 0 or 1 */
284 +};
285 +
286 +extern struct pfe_shared_info link_states[PFE_CDEV_ETH_COUNT];
287 +
288 +/* IOCTL Commands */
289 +#define PFE_CDEV_ETH0_STATE_GET 0
290 +#define PFE_CDEV_ETH1_STATE_GET 1
291 +
292 +int pfe_cdev_init(void);
293 +void pfe_cdev_exit(void);
294 +
295 +#endif /* _PFE_CDEV_H_ */
296 --- a/drivers/staging/fsl_ppfe/pfe_eth.c
297 +++ b/drivers/staging/fsl_ppfe/pfe_eth.c
298 @@ -55,6 +55,7 @@
299
300 #include "pfe_mod.h"
301 #include "pfe_eth.h"
302 +#include "pfe_cdev.h"
303
304 #define LS1012A_REV_1_0 0x87040010
305
306 @@ -1160,6 +1161,19 @@ static void pfe_eth_adjust_link(struct n
307 phy_print_status(phydev);
308
309 spin_unlock_irqrestore(&priv->lock, flags);
310 +
311 + /* Now, dump the details to the cdev.
312 + * XXX: Locking would be required? (uniprocess arch)
313 + * Or, maybe move it in spinlock above
314 + */
315 + if (us && priv->einfo->gem_id < PFE_CDEV_ETH_COUNT) {
316 + pr_debug("Changing link state from (%u) to (%u) for ID=(%u)\n",
317 + link_states[priv->einfo->gem_id].state,
318 + phydev->link,
319 + priv->einfo->gem_id);
320 + link_states[priv->einfo->gem_id].phy_id = priv->einfo->gem_id;
321 + link_states[priv->einfo->gem_id].state = phydev->link;
322 + }
323 }
324
325 /* pfe_phy_exit
326 --- a/drivers/staging/fsl_ppfe/pfe_mod.c
327 +++ b/drivers/staging/fsl_ppfe/pfe_mod.c
328 @@ -18,6 +18,7 @@
329
330 #include <linux/dma-mapping.h>
331 #include "pfe_mod.h"
332 +#include "pfe_cdev.h"
333
334 unsigned int us;
335 module_param(us, uint, 0444);
336 @@ -92,8 +93,18 @@ firmware_init:
337 if (rc < 0)
338 goto err_debugfs;
339
340 + if (us) {
341 + /* Creating a character device */
342 + rc = pfe_cdev_init();
343 + if (rc < 0)
344 + goto err_cdev;
345 + }
346 +
347 return 0;
348
349 +err_cdev:
350 + pfe_debugfs_exit(pfe);
351 +
352 err_debugfs:
353 pfe_sysfs_exit(pfe);
354
355 @@ -129,6 +140,9 @@ int pfe_remove(struct pfe *pfe)
356 {
357 pr_info("%s\n", __func__);
358
359 + if (us)
360 + pfe_cdev_exit();
361 +
362 pfe_debugfs_exit(pfe);
363
364 pfe_sysfs_exit(pfe);