31308eeaf5ddc929ee4be61689d31665adcbb9fb
[linux-3.10.git] / drivers / net / wireless / bcmdhd / dhd_custom_sysfs_tegra_stat.c
1 /*
2  * drivers/net/wireless/bcmdhd/dhd_custom_sysfs_tegra_stat.c
3  *
4  * NVIDIA Tegra Sysfs for BCMDHD driver
5  *
6  * Copyright (C) 2014 NVIDIA Corporation. All rights reserved.
7  *
8  * This software is licensed under the terms of the GNU General Public
9  * License version 2, as published by the Free Software Foundation, and
10  * may be copied, distributed, and modified under those terms.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  */
18
19 #include "dhd_custom_sysfs_tegra.h"
20 #include "bcmutils.h"
21 #include "wlioctl.h"
22 #include "wldev_common.h"
23
24 struct net_device *dhd_custom_sysfs_tegra_histogram_stat_netdev;
25
26 static void
27 stat_work_func(struct work_struct *work);
28
29 static unsigned int stat_delay_ms;
30 static unsigned int stat_rate_ms = 10 * 1000;
31 static DECLARE_DELAYED_WORK(stat_work, stat_work_func);
32
33 void
34 tegra_sysfs_histogram_stat_work_run(unsigned int ms)
35 {
36         stat_delay_ms = ms;
37 }
38
39 void
40 tegra_sysfs_histogram_stat_work_start(void)
41 {
42 //      pr_info("%s\n", __func__);
43         if (stat_rate_ms > 0)
44                 schedule_delayed_work(&stat_work,
45                         msecs_to_jiffies(stat_rate_ms));
46 }
47
48 void
49 tegra_sysfs_histogram_stat_work_stop(void)
50 {
51 //      pr_info("%s\n", __func__);
52         cancel_delayed_work_sync(&stat_work);
53 }
54
55 static void
56 stat_work_func(struct work_struct *work)
57 {
58         struct delayed_work *dwork = to_delayed_work(work);
59         struct net_device *net = dhd_custom_sysfs_tegra_histogram_stat_netdev;
60         char *netif = net ? net->name : "";
61         wl_cnt_t *cnt;
62         int i;
63
64 //      pr_info("%s\n", __func__);
65
66         /* create stat request */
67         cnt = kmalloc(sizeof(wl_cnt_t), GFP_KERNEL);
68         if (!cnt) {
69 //              pr_err("%s: kmalloc(wl_cnt_t) failed\n", __func__);
70                 goto fail;
71         }
72
73         /* send stat request */
74         if (wldev_iovar_getbuf(net, "counters", NULL, 0,
75                 (void *) cnt, sizeof(wl_cnt_t), NULL) != BCME_OK) {
76 //              pr_err("%s: wldev_iovar_getbuf() failed\n", __func__);
77                 kfree(cnt);
78                 goto fail;
79         }
80
81         /* log stat request */
82         for (i = 0; i < sizeof(wl_cnt_t); i += 64) {
83                 tcpdump_pkt_save('a' + i / 64,
84                         netif,
85                         __func__,
86                         __LINE__,
87                         ((unsigned char *) cnt) + i,
88                         (i + 64) <= sizeof(wl_cnt_t)
89                                 ? 64 : sizeof(wl_cnt_t) - i,
90                         0);
91         }
92         kfree(cnt);
93
94         /* schedule next stat */
95 fail:
96         if (stat_delay_ms) {
97                 stat_delay_ms = 0;
98                 msleep(stat_delay_ms);
99                 schedule_delayed_work(&stat_work, 0);
100                 return;
101         }
102         schedule_delayed_work(&stat_work,
103                 msecs_to_jiffies(stat_rate_ms));
104
105 }
106
107 ssize_t
108 tegra_sysfs_histogram_stat_show(struct device *dev,
109         struct device_attribute *attr,
110         char *buf)
111 {
112         static int i;
113
114 //      pr_info("%s\n", __func__);
115
116         if (!i) {
117                 i++;
118                 strcpy(buf, "dummy stat!");
119                 return strlen(buf);
120         } else {
121                 i = 0;
122                 return 0;
123         }
124 }
125
126 ssize_t
127 tegra_sysfs_histogram_stat_store(struct device *dev,
128         struct device_attribute *attr,
129         const char *buf, size_t count)
130 {
131         int err;
132         unsigned int uint;
133
134 //      pr_info("%s\n", __func__);
135
136         if (strncmp(buf, "enable", 6) == 0) {
137                 pr_info("%s: starting stat delayed work...\n", __func__);
138                 tegra_sysfs_histogram_stat_work_start();
139         } else if (strncmp(buf, "disable", 7) == 0) {
140                 pr_info("%s: stopping stat delayed work...\n", __func__);
141                 tegra_sysfs_histogram_stat_work_stop();
142         } else if (strncmp(buf, "rate ", 5) == 0) {
143                 err = kstrtouint(buf + 5, 0, &uint);
144                 if (err < 0) {
145                         pr_err("%s: invalid stat rate (ms)\n", __func__);
146                         return count;
147                 }
148                 pr_info("%s: set stat rate (ms) %u\n", __func__, uint);
149                 stat_rate_ms = uint;
150         } else {
151                 pr_err("%s: unknown command\n", __func__);
152         }
153
154         return count;
155 }