blob: 5f48de4163a1674495e012fe4535edc0b016e5c8 [file] [log] [blame]
Shad Ansari2f7f9be2017-06-07 13:34:53 -07001#include <linux/proc_fs.h>
2#include <bcmolt_tr_nl_driver.h>
3#include <bcmolt_dev_log_kernel.h>
4#include <bcm_dev_log.h>
5#include <bcmolt_dev_ctrl.h>
6#include <bcmolt_tr_mux.h>
7#include <bcmos_system.h>
8#include <linux/cdev.h>
9#include <asm/uaccess.h> /*copy_from_user*/
10#include <linux/proc_fs.h>
11#include <bcmolt_dev_ctrl_ioctl.h>
12#include <bcmolt_user_utils.h>
13#include <bcmolt_host_api.h>
14#include <bcmolt_fld.h>
15#include <bcmtr_pcie.h>
16
17module_param(bcmos_sys_trace_level, uint, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
18MODULE_PARM_DESC(bcmos_sys_trace_level, "trace_level");
19
20
21int maple_dev_ctrl_chrdev_major = 237;
22module_param(maple_dev_ctrl_chrdev_major, int, S_IRUSR | S_IRGRP | S_IWGRP);
23MODULE_PARM_DESC(maple_dev_ctrl_chrdev_major, "maple_dev_ctrl_major");
24static char is_chrdev_reg;
25static char is_cdev_add;
26
27extern struct proc_dir_entry *bcmolt_dir;
28
29bcmos_errno bcmtr_init(void)
30{
31 return BCM_ERR_OK;
32}
33
34/* /proc/bcmolt/trmux read operation */
35static int trmux_stats_read(char *page, char **start, off_t off, int count, int *eof, void *data)
36{
37 static bcmtrmux_stat prev_stat;
38 int len;
39 bcmtrmux_stat stat;
40 bcmos_errno rc;
41 bcmolt_devid *device_id = data;
42
43 rc = bcmtrmux_stat_get(*device_id, &stat);
44 if (rc)
45 {
46 len = snprintf(page, count, "Can't read trmux statistics rc=%s\n", bcmos_strerror(rc));
47 return len;
48 }
49
50 len = snprintf(page, count, "trmux statistics\n\n");
51 len += sprintf(page + len, "tx_remote : %u\n", stat.tx_remote - prev_stat.tx_remote);
52 len += sprintf(page + len, "tx_local : %u\n", stat.tx_local - prev_stat.tx_local);
53 len += sprintf(page + len, "tx_disc_remote : %u\n", stat.tx_disc_remote - prev_stat.tx_disc_remote);
54 len += sprintf(page + len, "tx_disc_local : %u\n", stat.tx_disc_local - prev_stat.tx_disc_local);
55 len += sprintf(page + len, "rx_remote : %u\n", stat.rx_remote - prev_stat.rx_remote);
56 len += sprintf(page + len, "rx_local : %u\n", stat.rx_local - prev_stat.rx_local);
57 len += sprintf(page + len, "rx_auto : %u\n", stat.rx_auto - prev_stat.rx_auto);
58 len += sprintf(page + len, "rx_disc_remote : %u\n", stat.rx_disc_remote - prev_stat.rx_disc_remote);
59 len += sprintf(page + len, "rx_disc_local : %u\n", stat.rx_disc_local - prev_stat.rx_disc_local);
60 len += sprintf(page + len, "rx_disc_auto : %u\n", stat.rx_disc_auto - prev_stat.rx_disc_auto);
61 len += sprintf(page + len, "ctl_to_host : %u\n", stat.control_to_host - prev_stat.control_to_host);
62 len += sprintf(page + len, "ctl_to_line : %u\n", stat.control_to_line - prev_stat.control_to_line);
63 len += sprintf(page + len, "rx_disc_inv_ch : %u\n", stat.rx_disc_inv_ch - prev_stat.rx_disc_inv_ch);
64 len += sprintf(page + len, "rx_poll_urgent : %u\n", stat.rx_poll_urgent - prev_stat.rx_poll_urgent);
65 len += sprintf(page + len, "rx_poll_normal : %u\n", stat.rx_poll_normal - prev_stat.rx_poll_normal);
66 prev_stat = stat;
67
68 return len;
69}
70
71/* /proc/bcmolt/devctrl read operation */
72static int devctrl_debug_read(char *page, char **start, off_t off, int count, int *eof, void *data)
73{
74 int len;
75 dev_ctrl_database db;
76 bcmolt_devid *device_id = data;
77
78 dev_ctrl_read_db(*device_id, &db);
79
80 /* db contains the entire copy of dev_ctrl_database. add whatever you want to print. */
81 len = snprintf(page, count, "dev_ctrl debug information\n\n");
82 len += sprintf(page + len, "task name : %s\n", db.task_info.name);
83 len += sprintf(page + len, "module name : %s\n", db.module_info.name);
84 len += sprintf(page + len, "connection state : %s\n",
85 bcm_str_host_connecting_state(db.connection_info.state));
86 len += sprintf(page + len, "tod : %s\n",
87 (db.enable_tod == BCMOLT_CONTROL_STATE_DISABLE) ? "DISABLE" : "ENABLE");
88 len += sprintf(page + len, "last event : %s\n", bcm_str_device_event(db.last_event));
89 if (db.conn_fail_reason < BCMOLT_HOST_CONNECTION_FAIL_REASON__NUM_OF)
90 len += sprintf(page + len, "connection failure reason : %s\n",
91 bcm_str_host_connection_fail_reason(db.conn_fail_reason));
92 return len;
93}
94
95#ifdef ENABLE_LOG
96static bcmos_errno dev_ctrl_logger_init_cb(void)
97{
98 bcmos_errno rc;
99
100 /* Create kernel logger */
101 rc = bcm_dev_log_linux_init();
102 BUG_ON(rc);
103
104 /* For now just map BCMOS_TRACE_XX to dev_log. Later on dev_control
105 * can define its own log ids
106 */
107 rc = bcm_dev_log_os_trace_init();
108 BUG_ON(rc);
109
110 return rc;
111}
112#endif
113
114static struct cdev maple_dev_ctrl_chrdev_cdev;
115static int maple_dev_ctrl_chrdev_open(struct inode *inode, struct file *filp)
116{
117 return 0;
118}
119
120static int maple_dev_ctrl_chrdev_release(struct inode *inode, struct file *filp)
121{
122 return 0;
123}
124
125static long maple_dev_ctrl_chrdev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
126{
127 bcmos_errno bcmrc;
128 int linux_rc = 0;
129 int rc = 0;
130 dev_ctrl_ioctl_param params;
131
132 /* don't even decode wrong cmds: better returning ENOTTY than EFAULT */
133 if (_IOC_TYPE(cmd) != MAPLE_DEV_CTRL_IOCTL_MAGIC)
134 return -ENOTTY;
135
136 rc = copy_from_user((char *)&params, (char *)arg, sizeof(params));
137 if (rc < 0)
138 return rc;
139
140 switch (cmd)
141 {
142 case MAPLE_DEV_CTRL_IOCTL_OP_PCI_STAT:
143 {
144 bcm_pcied_stat stat;
145
146 memset(params.dumpptr, 0, sizeof(bcm_pcied_stat));
147 bcmrc = bcmtr_pcie_get_statistics(params.device, params.start_index, &stat);
148 if (bcmrc == BCM_ERR_OK)
149 memcpy(params.dumpptr, &stat, sizeof(bcm_pcied_stat));
150 else
151 linux_rc = (int)bcmrc;
152 }
153 break;
154 case MAPLE_DEV_CTRL_IOCTL_OP_PCI_DUMP_TX:
155 linux_rc = (int)bcmtr_pcie_tx_dump((char *)params.dumpptr, params.device, params.start_index, params.howmany);
156 break;
157 case MAPLE_DEV_CTRL_IOCTL_OP_PCI_DUMP_RX:
158 linux_rc = (int)bcmtr_pcie_rx_dump((char *)params.dumpptr, params.device, params.start_index, params.howmany);
159 break;
160 case MAPLE_DEV_CTRL_IOCTL_OP_HOST_EVENT_WRITE:
161 linux_rc = (int)bcmolt_dev_ctrl_host_event_write(params.device, params.event);
162 break;
163 default:
164 rc = -ENOTTY;
165 break;
166 }
167
168 return linux_rc;
169}
170static ssize_t maple_dev_ctrl_chrdev_write(struct file *filp, const char __user *buf,
171 size_t count, loff_t *f_pos)
172{
173 return 0;
174}
175
176static struct file_operations maple_dev_ctrl_chrdev_fops =
177{
178 .owner = THIS_MODULE,
179 .open = maple_dev_ctrl_chrdev_open,
180 .release = maple_dev_ctrl_chrdev_release,
181 .write = maple_dev_ctrl_chrdev_write,
182 .unlocked_ioctl = maple_dev_ctrl_chrdev_ioctl
183};
184
185static int maple_dev_ctrl_dev_create_chrdev(void)
186{
187 dev_t dev = MKDEV(maple_dev_ctrl_chrdev_major, 0);
188 int linux_rc;
189 is_chrdev_reg = 0;
190 is_cdev_add = 0;
191 /*
192 * Register your major, and accept a dynamic number.
193 */
194 if (!maple_dev_ctrl_chrdev_major)
195 return -1;
196 linux_rc = register_chrdev_region(dev, 0, "maple_dev_ctrl");
197 if (linux_rc < 0)
198 {
199 printk("register_chrdev_region()->%d\n", linux_rc);
200 return -EIO;
201 }
202 is_chrdev_reg = 1;
203
204 cdev_init(&maple_dev_ctrl_chrdev_cdev, &maple_dev_ctrl_chrdev_fops);
205 linux_rc = cdev_add(&maple_dev_ctrl_chrdev_cdev, dev, 1);
206 if (linux_rc < 0)
207 {
208 printk("cdev_add()->%d\n", linux_rc);
209 return -EIO;
210 }
211 is_cdev_add = 1;
212 return 0;
213}
214
215
216#define BCMOLT_PROCFS_NAME_LEN 4 /* device_id is 1-byte, which can be 3 digit in decimal. */
217#define PROC_TRMUX_NAME "trmux"
218#define PROC_DEVCTRL_NAME "devctrl"
219#define PROC_ENTRY_MODE (S_IFREG | S_IWUSR | S_IRUGO)
220
221typedef struct
222{
223 bcmolt_devid device_id;
224 char name[BCMOLT_PROCFS_NAME_LEN];
225} bcmolt_proc_ctx_t;
226
227static bcmolt_proc_ctx_t bcmolt_proc_ctx[BCMTR_MAX_OLTS];
228static bcmos_bool bcmdev_bcmolt_proc_initialized;
229struct proc_dir_entry *trmux_dir = NULL;
230struct proc_dir_entry *devctrl_dir = NULL;
231
232static void bcmdev_bcmolt_proc_init(void)
233{
234 bcmolt_devid devid;
235 if (!bcmdev_bcmolt_proc_initialized)
236 {
237 for (devid = 0; devid < BCMTR_MAX_OLTS; devid++)
238 {
239 bcmolt_proc_ctx[devid].device_id = devid;
240 sprintf(bcmolt_proc_ctx[devid].name, "%d", devid);
241 }
242 bcmdev_bcmolt_proc_initialized = BCMOS_TRUE;
243 }
244}
245
246static void bcmdev_module_exit(void)
247{
248 int devid;
249
250 if (trmux_dir)
251 {
252 for (devid = 0; devid < BCMTR_MAX_OLTS; devid++)
253 {
254 remove_proc_entry(bcmolt_proc_ctx[devid].name, trmux_dir);
255 }
256 remove_proc_entry(PROC_TRMUX_NAME, bcmolt_dir);
257 }
258 if (devctrl_dir)
259 {
260 for (devid = 0; devid < BCMTR_MAX_OLTS; devid++)
261 {
262 remove_proc_entry(bcmolt_proc_ctx[devid].name, devctrl_dir);
263 }
264 remove_proc_entry(PROC_DEVCTRL_NAME, bcmolt_dir);
265 }
266
267 bcmolt_dev_ctrl_exit();
268 bcmtr_nl_exit();
269 if (is_cdev_add)
270 cdev_del(&maple_dev_ctrl_chrdev_cdev);
271 if (is_chrdev_reg)
272 unregister_chrdev_region(MKDEV(maple_dev_ctrl_chrdev_major, 0), 1);
273#if defined(ENABLE_LOG)
274 bcm_dev_log_linux_exit();
275 bcm_dev_log_destroy();
276#endif
277 printk("%s\n", __FUNCTION__);
278}
279
280static int bcmdev_module_init(void)
281{
282 bcmos_errno rc;
283 struct proc_dir_entry *trmux_file;
284 struct proc_dir_entry *devctrl_file;
285 bcmolt_devid devid;
286 bcmolt_host_init_params params =
287 {
288#ifdef ENABLE_LOG
289 .logger_init_cb = dev_ctrl_logger_init_cb,
290#endif
291 .dev_ctrl_params =
292 {
293 .image_read_cb = bcmuser_image_read,
294 .system_mode_validate_cb = bcmuser_system_mode_validate,
295 .device_off_cb = bcmuser_device_off,
296 .device_on_cb = bcmuser_device_on,
297 .device_is_running_cb = bcmuser_device_is_running,
298 .host_reset_cb = bcmuser_host_reset,
299 .pcie_channel_prepare_cb = bcmuser_pcie_channel_prepare,
300 .pcie_channel_remove_cb = bcmuser_pcie_channel_remove,
301 }
302 };
303
304 if (!is_cdev_add)
305 {
306 if (maple_dev_ctrl_dev_create_chrdev() < 0)
307 printk("%s error to create dev ctrl cdev \n", __FUNCTION__);
308 }
309
310 printk("%s\n", __FUNCTION__);
311
312 rc = bcmolt_host_init(&params);
313 BUG_ON(rc);
314
315 bcmos_trace_level_set(BCMOS_TRACE_LEVEL_DEBUG);
316
317 bcmdev_bcmolt_proc_init();
318
319 rc = bcmtr_nl_init();
320 BUG_ON(rc);
321
322 rc = bcmuser_pcie_prepare();
323
324 if (rc == BCM_ERR_OK)
325 {
326 if ((trmux_dir = create_proc_entry(PROC_TRMUX_NAME, S_IFDIR, bcmolt_dir)) == NULL)
327 {
328 printk("Unable to create /proc/bcmolt/trmux directory\n");
329 return -1;
330 }
331
332 if ((devctrl_dir = create_proc_entry(PROC_DEVCTRL_NAME, S_IFDIR, bcmolt_dir)) == NULL)
333 {
334 printk("Unable to create /proc/bcmolt/devctrl directory\n");
335 return -1;
336 }
337
338 for (devid = 0; devid < BCMTR_MAX_OLTS; devid++)
339 {
340 if ((trmux_file = create_proc_entry(bcmolt_proc_ctx[devid].name, PROC_ENTRY_MODE, trmux_dir)) == NULL)
341 {
342 printk("Unable to create /proc/bcmolt/%s/%s\n", PROC_TRMUX_NAME, bcmolt_proc_ctx[devid].name);
343 return -1;
344 }
345 trmux_file->read_proc = (read_proc_t *)trmux_stats_read;
346 trmux_file->data = &bcmolt_proc_ctx[devid].device_id;
347
348 if ((devctrl_file = create_proc_entry(bcmolt_proc_ctx[devid].name, PROC_ENTRY_MODE, devctrl_dir)) == NULL)
349 {
350 printk("Unable to create /proc/bcmolt/%s/%s\n", PROC_DEVCTRL_NAME, bcmolt_proc_ctx[devid].name);
351 return -1;
352 }
353 devctrl_file->read_proc = (read_proc_t *)devctrl_debug_read;
354 devctrl_file->data = &bcmolt_proc_ctx[devid].device_id;
355 }
356 }
357 else
358 {
359 bcmos_usleep(2000000);
360 bcmdev_module_exit();
361 }
362
363 return rc ? -EINVAL : 0;
364}
365
366module_init(bcmdev_module_init);
367module_exit(bcmdev_module_exit);
368
369MODULE_DESCRIPTION("device_control");
370MODULE_LICENSE("Dual BSD/GPL");