blob: ccb2f0701bb17ff96a744d925566b9eef76a0e06 [file] [log] [blame]
Radhakrishna Jiguru1c9b2252013-08-27 23:57:48 +05301/*
2 **************************************************************************
Zac Livingston866b0e22013-10-23 18:14:17 -06003 * Copyright (c) 2013, The Linux Foundation. All rights reserved.
Radhakrishna Jiguru1c9b2252013-08-27 23:57:48 +05304 * Permission to use, copy, modify, and/or distribute this software for
5 * any purpose with or without fee is hereby granted, provided that the
6 * above copyright notice and this permission notice appear in all copies.
7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
10 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
12 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
13 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14 **************************************************************************
15 */
Abhishek Rastogibc74e432013-04-02 10:28:22 +053016
17/*
18 * nss_init.c
19 * NSS init APIs
20 *
21 */
Abhishek Rastogibc74e432013-04-02 10:28:22 +053022#include "nss_core.h"
Pamidipati, Vijay7f413b52013-09-24 19:07:12 +053023#include "nss_pm.h"
24
Abhishek Rastogibc74e432013-04-02 10:28:22 +053025#include <nss_hal.h>
Thomas Wufb6a6842013-10-23 13:14:27 -070026#include <nss_clocks.h>
Abhishek Rastogibc74e432013-04-02 10:28:22 +053027
28#include <linux/module.h>
29#include <linux/platform_device.h>
wthomas442c7972013-08-05 14:28:17 -070030#include <linux/proc_fs.h>
31#include <linux/device.h>
Abhishek Rastogibc74e432013-04-02 10:28:22 +053032#include <mach/msm_nss.h>
33
wthomas442c7972013-08-05 14:28:17 -070034#include <linux/sysctl.h>
35#include <linux/regulator/consumer.h>
Thomas Wufb6a6842013-10-23 13:14:27 -070036#include <linux/clk.h>
wthomas442c7972013-08-05 14:28:17 -070037
Abhishek Rastogibc74e432013-04-02 10:28:22 +053038/*
Abhishek Rastogi38cffff2013-06-02 11:25:47 +053039 * Declare module parameters
40 */
41static int load0 = 0x40000000;
42module_param(load0, int, S_IRUSR | S_IWUSR);
43MODULE_PARM_DESC(load0, "NSS Core 0 load address");
44
45static int entry0 = 0x40000000;
46module_param(entry0, int, S_IRUSR | S_IWUSR);
47MODULE_PARM_DESC(load0, "NSS Core 0 entry address");
48
49static char *string0 = "nss0";
50module_param(string0, charp, 0);
51MODULE_PARM_DESC(string0, "NSS Core 0 identification string");
52
53static int load1 = 0x40100000;
54module_param(load1, int, S_IRUSR | S_IWUSR);
55MODULE_PARM_DESC(load0, "NSS Core 1 load address");
56
57static int entry1 = 0x40100000;
58module_param(entry1, int, S_IRUSR | S_IWUSR);
59MODULE_PARM_DESC(load0, "NSS Core 1 entry address");
60
61static char *string1 = "nss1";
62module_param(string1, charp, 0);
63MODULE_PARM_DESC(string1, "NSS Core 1 identification string");
64
65
66/*
Abhishek Rastogibc74e432013-04-02 10:28:22 +053067 * Global declarations
68 */
Abhishek Rastogi5cd2e4c2013-11-13 18:09:08 +053069int nss_ctl_redirect __read_mostly = 0;
70
Abhishek Rastogibc74e432013-04-02 10:28:22 +053071
72/*
wthomas626147f2013-09-18 13:12:40 -070073 * Handler to send NSS messages
74 */
75void *nss_freq_change_context;
Thomas Wufb6a6842013-10-23 13:14:27 -070076struct clk *nss_core0_clk;
wthomas626147f2013-09-18 13:12:40 -070077
78/*
Abhishek Rastogibc74e432013-04-02 10:28:22 +053079 * Top level nss context structure
80 */
81struct nss_top_instance nss_top_main;
wthomas442c7972013-08-05 14:28:17 -070082struct nss_cmd_buffer nss_cmd_buf;
wthomas626147f2013-09-18 13:12:40 -070083struct nss_runtime_sampling nss_runtime_samples;
84struct workqueue_struct *nss_wq;
85
86/*
87 * Work Queue to handle messages to Kernel
88 */
89nss_work_t *nss_work;
Abhishek Rastogibc74e432013-04-02 10:28:22 +053090
91/*
92 * File local/Static variables/functions
93 */
94
Abhishek Rastogi271eee72013-07-29 21:08:36 +053095static const struct net_device_ops nss_netdev_ops;
96static const struct ethtool_ops nss_ethtool_ops;
97
98/*
99 * nss_dummy_netdev_setup()
100 * Dummy setup for net_device handler
101 */
102static void nss_dummy_netdev_setup(struct net_device *ndev)
103{
wthomas626147f2013-09-18 13:12:40 -0700104
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530105}
106
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530107/*
108 * nss_handle_irq()
109 * HLOS interrupt handler for nss interrupts
110 */
111static irqreturn_t nss_handle_irq (int irq, void *ctx)
112{
113 struct int_ctx_instance *int_ctx = (struct int_ctx_instance *) ctx;
Abhishek Rastogi80f4eb12013-09-24 14:31:21 +0530114 struct nss_ctx_instance *nss_ctx = int_ctx->nss_ctx;
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530115
116 /*
Abhishek Rastogi80f4eb12013-09-24 14:31:21 +0530117 * Mask interrupt until our bottom half re-enables it
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530118 */
Abhishek Rastogi80f4eb12013-09-24 14:31:21 +0530119 nss_hal_disable_interrupt(nss_ctx->nmap, int_ctx->irq,
120 int_ctx->shift_factor, NSS_HAL_SUPPORTED_INTERRUPTS);
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530121
122 /*
123 * Schedule tasklet to process interrupt cause
124 */
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530125 napi_schedule(&int_ctx->napi);
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530126 return IRQ_HANDLED;
127}
128
129/*
130 * nss_probe()
131 * HLOS device probe callback
132 */
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530133static int __devinit nss_probe(struct platform_device *nss_dev)
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530134{
135 struct nss_top_instance *nss_top = &nss_top_main;
136 struct nss_ctx_instance *nss_ctx = &nss_top->nss[nss_dev->id];
137 struct nss_platform_data *npd = (struct nss_platform_data *) nss_dev->dev.platform_data;
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530138 struct netdev_priv_instance *ndev_priv;
139 int i, err = 0;
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530140
141 nss_ctx->nss_top = nss_top;
142 nss_ctx->id = nss_dev->id;
143
wthomas442c7972013-08-05 14:28:17 -0700144 nss_info("%p: NSS_DEV_ID %s \n", nss_ctx, dev_name(&nss_dev->dev));
145
146 /*
147 * Both NSS cores controlled by same regulator, Hook only Once
148 */
149 if (!nss_dev->id) {
Thomas Wufb6a6842013-10-23 13:14:27 -0700150 nss_core0_clk = clk_get(&nss_dev->dev, "nss_core_clk");
151 if (IS_ERR(nss_core0_clk)) {
wthomas442c7972013-08-05 14:28:17 -0700152
Thomas Wufb6a6842013-10-23 13:14:27 -0700153 err = PTR_ERR(nss_core0_clk);
wthomas442c7972013-08-05 14:28:17 -0700154 nss_info("%p: Regulator %s get failed, err=%d\n", nss_ctx, dev_name(&nss_dev->dev), err);
155 return err;
156
wthomas442c7972013-08-05 14:28:17 -0700157 }
Thomas Wufb6a6842013-10-23 13:14:27 -0700158 clk_set_rate(nss_core0_clk, NSS_FREQ_550);
159 clk_prepare(nss_core0_clk);
160 clk_enable(nss_core0_clk);
wthomas442c7972013-08-05 14:28:17 -0700161 }
162
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530163 /*
164 * Get virtual and physical memory addresses for nss logical/hardware address maps
165 */
166
167 /*
168 * Virtual address of CSM space
169 */
170 nss_ctx->nmap = npd->nmap;
171 nss_assert(nss_ctx->nmap);
172
173 /*
174 * Physical address of CSM space
175 */
176 nss_ctx->nphys = npd->nphys;
177 nss_assert(nss_ctx->nphys);
178
179 /*
180 * Virtual address of logical registers space
181 */
182 nss_ctx->vmap = npd->vmap;
183 nss_assert(nss_ctx->vmap);
184
185 /*
186 * Physical address of logical registers space
187 */
188 nss_ctx->vphys = npd->vphys;
189 nss_assert(nss_ctx->vphys);
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530190 nss_info("%d:ctx=%p, vphys=%x, vmap=%x, nphys=%x, nmap=%x",
191 nss_dev->id, nss_ctx, nss_ctx->vphys, nss_ctx->vmap, nss_ctx->nphys, nss_ctx->nmap);
192
193 /*
194 * Register netdevice handlers
195 */
196 nss_ctx->int_ctx[0].ndev = alloc_netdev(sizeof(struct netdev_priv_instance),
197 "qca-nss-dev%d", nss_dummy_netdev_setup);
198 if (nss_ctx->int_ctx[0].ndev == NULL) {
199 nss_warning("%p: Could not allocate net_device #0", nss_ctx);
200 err = -ENOMEM;
201 goto err_init_0;
202 }
203
204 nss_ctx->int_ctx[0].ndev->netdev_ops = &nss_netdev_ops;
205 nss_ctx->int_ctx[0].ndev->ethtool_ops = &nss_ethtool_ops;
206 err = register_netdev(nss_ctx->int_ctx[0].ndev);
207 if (err) {
208 nss_warning("%p: Could not register net_device #0", nss_ctx);
209 goto err_init_1;
210 }
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530211
212 /*
213 * request for IRQs
214 *
215 * WARNING: CPU affinities should be set using OS supported methods
216 */
217 nss_ctx->int_ctx[0].nss_ctx = nss_ctx;
218 nss_ctx->int_ctx[0].shift_factor = 0;
219 nss_ctx->int_ctx[0].irq = npd->irq[0];
220 err = request_irq(npd->irq[0], nss_handle_irq, IRQF_DISABLED, "nss", &nss_ctx->int_ctx[0]);
221 if (err) {
222 nss_warning("%d: IRQ0 request failed", nss_dev->id);
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530223 goto err_init_2;
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530224 }
225
226 /*
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530227 * Register NAPI for NSS core interrupt #0
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530228 */
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530229 ndev_priv = netdev_priv(nss_ctx->int_ctx[0].ndev);
230 ndev_priv->int_ctx = &nss_ctx->int_ctx[0];
231 netif_napi_add(nss_ctx->int_ctx[0].ndev, &nss_ctx->int_ctx[0].napi, nss_core_handle_napi, 64);
232 napi_enable(&nss_ctx->int_ctx[0].napi);
233 nss_ctx->int_ctx[0].napi_active = true;
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530234
235 /*
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530236 * Check if second interrupt is supported on this nss core
237 */
238 if (npd->num_irq > 1) {
239 nss_info("%d: This NSS core supports two interrupts", nss_dev->id);
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530240
241 /*
242 * Register netdevice handlers
243 */
244 nss_ctx->int_ctx[1].ndev = alloc_netdev(sizeof(struct netdev_priv_instance),
245 "qca-nss-dev%d", nss_dummy_netdev_setup);
246 if (nss_ctx->int_ctx[1].ndev == NULL) {
247 nss_warning("%p: Could not allocate net_device #1", nss_ctx);
248 err = -ENOMEM;
249 goto err_init_3;
250 }
251
252 nss_ctx->int_ctx[1].ndev->netdev_ops = &nss_netdev_ops;
253 nss_ctx->int_ctx[1].ndev->ethtool_ops = &nss_ethtool_ops;
254 err = register_netdev(nss_ctx->int_ctx[1].ndev);
255 if (err) {
256 nss_warning("%p: Could not register net_device #1", nss_ctx);
257 goto err_init_4;
258 }
259
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530260 nss_ctx->int_ctx[1].nss_ctx = nss_ctx;
261 nss_ctx->int_ctx[1].shift_factor = 15;
262 nss_ctx->int_ctx[1].irq = npd->irq[1];
263 err = request_irq(npd->irq[1], nss_handle_irq, IRQF_DISABLED, "nss", &nss_ctx->int_ctx[1]);
264 if (err) {
265 nss_warning("%d: IRQ1 request failed for nss", nss_dev->id);
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530266 goto err_init_5;
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530267 }
268
269 /*
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530270 * Register NAPI for NSS core interrupt #1
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530271 */
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530272 ndev_priv = netdev_priv(nss_ctx->int_ctx[1].ndev);
273 ndev_priv->int_ctx = &nss_ctx->int_ctx[1];
274 netif_napi_add(nss_ctx->int_ctx[1].ndev, &nss_ctx->int_ctx[1].napi, nss_core_handle_napi, 64);
275 napi_enable(&nss_ctx->int_ctx[1].napi);
276 nss_ctx->int_ctx[1].napi_active = true;
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530277 }
278
279 spin_lock_bh(&(nss_top->lock));
280
281 /*
282 * Check functionalities are supported by this NSS core
283 */
284 if (npd->ipv4_enabled == NSS_FEATURE_ENABLED) {
285 nss_top->ipv4_handler_id = nss_dev->id;
286 }
287
288 if (npd->ipv6_enabled == NSS_FEATURE_ENABLED) {
289 nss_top->ipv6_handler_id = nss_dev->id;
290 }
291
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530292 if (npd->crypto_enabled == NSS_FEATURE_ENABLED) {
293 nss_top->crypto_handler_id = nss_dev->id;
294 }
295
296 if (npd->ipsec_enabled == NSS_FEATURE_ENABLED) {
297 nss_top->ipsec_handler_id = nss_dev->id;
298 }
299
300 if (npd->wlan_enabled == NSS_FEATURE_ENABLED) {
301 nss_top->wlan_handler_id = nss_dev->id;
302 }
303
Bharath M Kumar0d87e912013-08-12 18:32:57 +0530304 if (npd->tun6rd_enabled == NSS_FEATURE_ENABLED) {
305 nss_top->tun6rd_handler_id = nss_dev->id;
306 }
307
Bharath M Kumar614bbf82013-08-31 20:18:44 +0530308 if (npd->tunipip6_enabled == NSS_FEATURE_ENABLED) {
309 nss_top->tunipip6_handler_id = nss_dev->id;
310 }
311
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530312 if (npd->gmac_enabled[0] == NSS_FEATURE_ENABLED) {
313 nss_top->phys_if_handler_id[0] = nss_dev->id;
314 }
315
316 if (npd->gmac_enabled[1] == NSS_FEATURE_ENABLED) {
317 nss_top->phys_if_handler_id[1] = nss_dev->id;
318 }
319
320 if (npd->gmac_enabled[2] == NSS_FEATURE_ENABLED) {
321 nss_top->phys_if_handler_id[2] = nss_dev->id;
322 }
323
324 if (npd->gmac_enabled[3] == NSS_FEATURE_ENABLED) {
325 nss_top->phys_if_handler_id[3] = nss_dev->id;
326 }
327
wthomas626147f2013-09-18 13:12:40 -0700328 nss_top->frequency_handler_id = nss_dev->id;
329
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530330 spin_unlock_bh(&(nss_top->lock));
331
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530332 /*
333 * Initialize decongestion callbacks to NULL
334 */
335 for (i = 0; i< NSS_MAX_CLIENTS; i++) {
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530336 nss_ctx->queue_decongestion_callback[i] = 0;
337 nss_ctx->queue_decongestion_ctx[i] = 0;
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530338 }
339
340 spin_lock_init(&(nss_ctx->decongest_cb_lock));
341 nss_ctx->magic = NSS_CTX_MAGIC;
342
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530343 nss_info("%p: Reseting NSS core %d now", nss_ctx, nss_ctx->id);
344
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530345 /*
346 * Enable clocks and bring NSS core out of reset
347 */
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530348 nss_hal_core_reset(nss_dev->id, nss_ctx->nmap, nss_ctx->load, nss_top->clk_src);
349
350 /*
351 * Enable interrupts for NSS core
352 */
353 nss_hal_enable_interrupt(nss_ctx->nmap, nss_ctx->int_ctx[0].irq,
354 nss_ctx->int_ctx[0].shift_factor, NSS_HAL_SUPPORTED_INTERRUPTS);
355
356 if (npd->num_irq > 1) {
357 nss_hal_enable_interrupt(nss_ctx->nmap, nss_ctx->int_ctx[1].irq,
358 nss_ctx->int_ctx[1].shift_factor, NSS_HAL_SUPPORTED_INTERRUPTS);
359 }
360
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530361 nss_info("%p: All resources initialized and nss core%d has been brought out of reset", nss_ctx, nss_dev->id);
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530362 goto err_init_0;
363
364err_init_5:
365 unregister_netdev(nss_ctx->int_ctx[1].ndev);
366err_init_4:
367 free_netdev(nss_ctx->int_ctx[1].ndev);
368err_init_3:
369 free_irq(npd->irq[0], &nss_ctx->int_ctx[0]);
370err_init_2:
371 unregister_netdev(nss_ctx->int_ctx[0].ndev);
372err_init_1:
373 free_netdev(nss_ctx->int_ctx[0].ndev);
374err_init_0:
375 return err;
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530376}
377
378/*
379 * nss_remove()
380 * HLOS device remove callback
381 */
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530382static int __devexit nss_remove(struct platform_device *nss_dev)
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530383{
384 struct nss_top_instance *nss_top = &nss_top_main;
385 struct nss_ctx_instance *nss_ctx = &nss_top->nss[nss_dev->id];
386
387 /*
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530388 * Clean-up debugfs
389 */
390 nss_stats_clean();
391
392 /*
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530393 * Disable interrupts and bottom halves in HLOS
394 * Disable interrupts from NSS to HLOS
395 */
396 nss_hal_disable_interrupt(nss_ctx->nmap, nss_ctx->int_ctx[0].irq,
397 nss_ctx->int_ctx[0].shift_factor, NSS_HAL_SUPPORTED_INTERRUPTS);
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530398
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530399 free_irq(nss_ctx->int_ctx[0].irq, &nss_ctx->int_ctx[0]);
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530400 unregister_netdev(nss_ctx->int_ctx[0].ndev);
401 free_netdev(nss_ctx->int_ctx[0].ndev);
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530402
403 /*
404 * Check if second interrupt is supported
405 * If so then clear resources for second interrupt as well
406 */
407 if (nss_ctx->int_ctx[1].irq) {
408 nss_hal_disable_interrupt(nss_ctx->nmap, nss_ctx->int_ctx[1].irq,
409 nss_ctx->int_ctx[1].shift_factor, NSS_HAL_SUPPORTED_INTERRUPTS);
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530410 free_irq(nss_ctx->int_ctx[1].irq, &nss_ctx->int_ctx[1]);
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530411 unregister_netdev(nss_ctx->int_ctx[1].ndev);
412 free_netdev(nss_ctx->int_ctx[1].ndev);
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530413 }
414
415 nss_info("%p: All resources freed for nss core%d", nss_ctx, nss_dev->id);
416 return 0;
417}
418
419/*
420 * nss_driver
421 * Platform driver structure for NSS
422 */
423struct platform_driver nss_driver = {
424 .probe = nss_probe,
425 .remove = __devexit_p(nss_remove),
426 .driver = {
427 .name = "qca-nss",
428 .owner = THIS_MODULE,
429 },
430};
431
432/*
wthomas626147f2013-09-18 13:12:40 -0700433 ***************************************************************************************************
Thomas Wufb6a6842013-10-23 13:14:27 -0700434 * nss_wq_function() is used to queue up requests to change NSS frequencies.
435 * The function will take care of NSS notices and also control clock.
436 * The auto rate algorithmn will queue up requests or the procfs may also queue up these requests.
wthomas626147f2013-09-18 13:12:40 -0700437 ***************************************************************************************************
438 */
439
440/*
441 * nss_wq_function()
442 * Added to Handle BH requests to kernel
443 */
444void nss_wq_function (struct work_struct *work)
445{
446 nss_work_t *my_work = (nss_work_t *)work;
447
Thomas Wufb6a6842013-10-23 13:14:27 -0700448 nss_freq_change(nss_freq_change_context, my_work->frequency, 0);
449 clk_set_rate(nss_core0_clk, my_work->frequency);
450 nss_freq_change(nss_freq_change_context, my_work->frequency, 1);
wthomas626147f2013-09-18 13:12:40 -0700451
452 kfree((void *)work);
453}
454
455/*
wthomas442c7972013-08-05 14:28:17 -0700456 * nss_current_freq_handler()
457 * Handle Userspace Frequency Change Requests
458 */
459static int nss_current_freq_handler (ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos)
460{
wthomas442c7972013-08-05 14:28:17 -0700461 int ret;
wthomas626147f2013-09-18 13:12:40 -0700462
463 BUG_ON(!nss_wq);
wthomas442c7972013-08-05 14:28:17 -0700464
465 ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
466
wthomasd39fa822013-08-22 16:44:23 -0700467 if (!write) {
wthomas626147f2013-09-18 13:12:40 -0700468 printk("Frequency Set to %d\n", nss_cmd_buf.current_freq);
wthomasd39fa822013-08-22 16:44:23 -0700469 return ret;
wthomas442c7972013-08-05 14:28:17 -0700470 }
wthomasd39fa822013-08-22 16:44:23 -0700471
wthomas626147f2013-09-18 13:12:40 -0700472 /* Turn off Auto Scale */
473 nss_cmd_buf.auto_scale = 0;
474 nss_runtime_samples.freq_scale_ready = 0;
wthomasd39fa822013-08-22 16:44:23 -0700475
476 /* If support NSS freq is in the table send the new frequency request to NSS */
Thomas Wufb6a6842013-10-23 13:14:27 -0700477 if ((nss_cmd_buf.current_freq != NSS_FREQ_110) && (nss_cmd_buf.current_freq != NSS_FREQ_275) && (nss_cmd_buf.current_freq != NSS_FREQ_550) && (nss_cmd_buf.current_freq != NSS_FREQ_733)) {
478 printk("Frequency not found. Please check Frequency Table\n");
wthomas626147f2013-09-18 13:12:40 -0700479 return ret;
wthomasd39fa822013-08-22 16:44:23 -0700480 }
481
wthomas626147f2013-09-18 13:12:40 -0700482 nss_work = (nss_work_t *)kmalloc(sizeof(nss_work_t), GFP_KERNEL);
483 if (!nss_work) {
484 nss_info("NSS Freq WQ kmalloc fail");
485 return ret;
486 }
487 INIT_WORK((struct work_struct *)nss_work, nss_wq_function);
488 nss_work->frequency = nss_cmd_buf.current_freq;
wthomas626147f2013-09-18 13:12:40 -0700489 queue_work(nss_wq, (struct work_struct *)nss_work);
490
wthomas442c7972013-08-05 14:28:17 -0700491 return ret;
492}
493
494/*
495 * nss_auto_scale_handler()
496 * Enables or Disable Auto Scaling
497 */
498static int nss_auto_scale_handler (ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos)
499{
500 int ret;
501
502 ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
503
wthomas626147f2013-09-18 13:12:40 -0700504 if (!write) {
505 return ret;
506 }
507
Thomas Wufb6a6842013-10-23 13:14:27 -0700508 if (nss_cmd_buf.auto_scale != 1) {
wthomas626147f2013-09-18 13:12:40 -0700509 /*
510 * Auto Scaling is already disabled
511 */
wthomas626147f2013-09-18 13:12:40 -0700512 nss_runtime_samples.freq_scale_ready = 0;
Thomas Wufb6a6842013-10-23 13:14:27 -0700513 return ret;
wthomas626147f2013-09-18 13:12:40 -0700514 }
wthomas442c7972013-08-05 14:28:17 -0700515
Thomas Wufb6a6842013-10-23 13:14:27 -0700516 /*
517 * Auto Scaling is already being done
518 */
519 if (nss_runtime_samples.freq_scale_ready == 1) {
520 return ret;
521 }
522
523 /*
524 * Setup default values - Middle of Freq Scale Band
525 */
526 nss_runtime_samples.freq_scale_index = 1;
527 nss_cmd_buf.current_freq = nss_runtime_samples.freq_scale[nss_runtime_samples.freq_scale_index].frequency;
528
529 nss_work = (nss_work_t *)kmalloc(sizeof(nss_work_t), GFP_KERNEL);
530 if (!nss_work) {
531 nss_info("NSS Freq WQ kmalloc fail");
532 return ret;
533 }
534 INIT_WORK((struct work_struct *)nss_work, nss_wq_function);
535 nss_work->frequency = nss_cmd_buf.current_freq;
536 queue_work(nss_wq, (struct work_struct *)nss_work);
537
538 nss_runtime_samples.freq_scale_ready = 1;
539
wthomas442c7972013-08-05 14:28:17 -0700540 return ret;
541}
542
543/*
544 * nss_get_freq_table_handler()
545 * Display Support Freq and Ex how to Change.
546 */
547static int nss_get_freq_table_handler (ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos)
548{
549 int ret;
550
551 ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
552
wthomas626147f2013-09-18 13:12:40 -0700553 printk("Frequency Supported - 110Mhz 275Mhz 550Mhz 733Mhz \n");
wthomas442c7972013-08-05 14:28:17 -0700554 printk("Ex. To Change Frequency - echo 110000000 > current_freq \n");
555
556 return ret;
557}
558
559/*
560 * sysctl-tuning infrastructure.
561 */
562static ctl_table nss_freq_table[] = {
563 {
564 .procname = "current_freq",
565 .data = &nss_cmd_buf.current_freq,
566 .maxlen = sizeof(int),
567 .mode = 0644,
568 .proc_handler = &nss_current_freq_handler,
569 },
570 {
571 .procname = "freq_table",
572 .data = &nss_cmd_buf.max_freq,
573 .maxlen = sizeof(int),
574 .mode = 0644,
575 .proc_handler = &nss_get_freq_table_handler,
576 },
577 {
578 .procname = "auto_scale",
579 .data = &nss_cmd_buf.auto_scale,
580 .maxlen = sizeof(int),
581 .mode = 0644,
582 .proc_handler = &nss_auto_scale_handler,
583 },
584 { }
585};
586
Abhishek Rastogi5cd2e4c2013-11-13 18:09:08 +0530587static ctl_table nss_general_table[] = {
588 {
589 .procname = "redirect",
590 .data = &nss_ctl_redirect,
591 .maxlen = sizeof(int),
592 .mode = 0644,
593 .proc_handler = proc_dointvec,
594 },
595 { }
596};
597
wthomas442c7972013-08-05 14:28:17 -0700598static ctl_table nss_clock_dir[] = {
599 {
Abhishek Rastogi5cd2e4c2013-11-13 18:09:08 +0530600 .procname = "clock",
601 .mode = 0555,
602 .child = nss_freq_table,
603 },
604 {
605 .procname = "general",
606 .mode = 0555,
607 .child = nss_general_table,
wthomas442c7972013-08-05 14:28:17 -0700608 },
609 { }
610};
611
612static ctl_table nss_root_dir[] = {
613 {
614 .procname = "nss",
615 .mode = 0555,
616 .child = nss_clock_dir,
617 },
618 { }
619};
620
621static ctl_table nss_root[] = {
622 {
623 .procname = "dev",
624 .mode = 0555,
625 .child = nss_root_dir,
626 },
627 { }
628};
629
630static struct ctl_table_header *nss_dev_header;
631
632/*
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530633 * nss_init()
634 * Registers nss driver
635 */
636static int __init nss_init(void)
637{
638 nss_info("Init NSS driver");
639
wthomas626147f2013-09-18 13:12:40 -0700640 nss_freq_change_context = nss_get_frequency_mgr();
641
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530642 /*
643 * Perform clock init common to all NSS cores
644 */
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530645 nss_hal_common_reset(&(nss_top_main.clk_src));
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530646
647 /*
648 * Enable spin locks
649 */
650 spin_lock_init(&(nss_top_main.lock));
651 spin_lock_init(&(nss_top_main.stats_lock));
652
653 /*
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530654 * Enable NSS statistics
655 */
656 nss_stats_init();
657
658 /*
659 * Store load addresses
660 */
661 nss_top_main.nss[0].load = (uint32_t)load0;
662 nss_top_main.nss[1].load = (uint32_t)load1;
663
664 /*
wthomas442c7972013-08-05 14:28:17 -0700665 * Register sysctl table.
666 */
667 nss_dev_header = register_sysctl_table(nss_root);
668
669 /*
wthomas626147f2013-09-18 13:12:40 -0700670 * Setup Runtime Sample values
671 */
672 nss_runtime_samples.freq_scale[0].frequency = NSS_FREQ_110;
wthomas626147f2013-09-18 13:12:40 -0700673 nss_runtime_samples.freq_scale[0].minimum = NSS_FREQ_110_MIN;
674 nss_runtime_samples.freq_scale[0].maximum = NSS_FREQ_110_MAX;
wthomas626147f2013-09-18 13:12:40 -0700675 nss_runtime_samples.freq_scale[1].frequency = NSS_FREQ_550;
wthomas626147f2013-09-18 13:12:40 -0700676 nss_runtime_samples.freq_scale[1].minimum = NSS_FREQ_550_MIN;
677 nss_runtime_samples.freq_scale[1].maximum = NSS_FREQ_550_MAX;
wthomas626147f2013-09-18 13:12:40 -0700678 nss_runtime_samples.freq_scale[2].frequency = NSS_FREQ_733;
wthomas626147f2013-09-18 13:12:40 -0700679 nss_runtime_samples.freq_scale[2].minimum = NSS_FREQ_733_MIN;
680 nss_runtime_samples.freq_scale[2].maximum = NSS_FREQ_733_MAX;
wthomas626147f2013-09-18 13:12:40 -0700681 nss_runtime_samples.freq_scale_index = 1;
682 nss_runtime_samples.freq_scale_ready = 0;
Thomas Wu9681f7e2013-11-06 13:12:57 -0800683 nss_runtime_samples.freq_scale_rate_limit_up = 0;
684 nss_runtime_samples.freq_scale_rate_limit_down = 0;
wthomas626147f2013-09-18 13:12:40 -0700685 nss_runtime_samples.buffer_index = 0;
686 nss_runtime_samples.sum = 0;
687 nss_runtime_samples.sample_count = 0;
688 nss_runtime_samples.average = 0;
689 nss_runtime_samples.message_rate_limit = 0;
690
691 /*
692 * Initial Workqueue
693 */
694 nss_wq = create_workqueue("nss_freq_queue");
695
696 /*
Pamidipati, Vijay7f413b52013-09-24 19:07:12 +0530697 * Initialize NSS Bus PM module
698 */
699 nss_pm_init();
700
701 /*
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530702 * Register platform_driver
703 */
704 return platform_driver_register(&nss_driver);
705}
706
707/*
708 * nss_cleanup()
709 * Unregisters nss driver
710 */
711static void __exit nss_cleanup(void)
712{
713 nss_info("Exit NSS driver");
wthomas442c7972013-08-05 14:28:17 -0700714
715 if (nss_dev_header)
716 unregister_sysctl_table(nss_dev_header);
717
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530718 platform_driver_unregister(&nss_driver);
719}
720
721module_init(nss_init);
722module_exit(nss_cleanup);
723
724MODULE_DESCRIPTION("QCA NSS Driver");
725MODULE_AUTHOR("Qualcomm Atheros Inc");
726MODULE_LICENSE("Dual BSD/GPL");