blob: d1efa0b7ade97f89a99ace374eff3d3722b59c5a [file] [log] [blame]
Radhakrishna Jiguru1c9b2252013-08-27 23:57:48 +05301/*
2 **************************************************************************
3 * Copyright (c) 2013, Qualcomm Atheros, Inc.
4 * 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 */
22
23#include "nss_core.h"
24#include <nss_hal.h>
Thomas Wufb6a6842013-10-23 13:14:27 -070025#include <nss_clocks.h>
Abhishek Rastogibc74e432013-04-02 10:28:22 +053026
27#include <linux/module.h>
28#include <linux/platform_device.h>
wthomas442c7972013-08-05 14:28:17 -070029#include <linux/proc_fs.h>
30#include <linux/device.h>
Abhishek Rastogibc74e432013-04-02 10:28:22 +053031#include <mach/msm_nss.h>
32
wthomas442c7972013-08-05 14:28:17 -070033#include <linux/sysctl.h>
34#include <linux/regulator/consumer.h>
Thomas Wufb6a6842013-10-23 13:14:27 -070035#include <linux/clk.h>
wthomas442c7972013-08-05 14:28:17 -070036
Abhishek Rastogibc74e432013-04-02 10:28:22 +053037/*
Abhishek Rastogi38cffff2013-06-02 11:25:47 +053038 * Declare module parameters
39 */
40static int load0 = 0x40000000;
41module_param(load0, int, S_IRUSR | S_IWUSR);
42MODULE_PARM_DESC(load0, "NSS Core 0 load address");
43
44static int entry0 = 0x40000000;
45module_param(entry0, int, S_IRUSR | S_IWUSR);
46MODULE_PARM_DESC(load0, "NSS Core 0 entry address");
47
48static char *string0 = "nss0";
49module_param(string0, charp, 0);
50MODULE_PARM_DESC(string0, "NSS Core 0 identification string");
51
52static int load1 = 0x40100000;
53module_param(load1, int, S_IRUSR | S_IWUSR);
54MODULE_PARM_DESC(load0, "NSS Core 1 load address");
55
56static int entry1 = 0x40100000;
57module_param(entry1, int, S_IRUSR | S_IWUSR);
58MODULE_PARM_DESC(load0, "NSS Core 1 entry address");
59
60static char *string1 = "nss1";
61module_param(string1, charp, 0);
62MODULE_PARM_DESC(string1, "NSS Core 1 identification string");
63
64
65/*
Abhishek Rastogibc74e432013-04-02 10:28:22 +053066 * Global declarations
67 */
68
69/*
wthomas626147f2013-09-18 13:12:40 -070070 * Handler to send NSS messages
71 */
72void *nss_freq_change_context;
Thomas Wufb6a6842013-10-23 13:14:27 -070073struct clk *nss_core0_clk;
wthomas626147f2013-09-18 13:12:40 -070074
75/*
Abhishek Rastogibc74e432013-04-02 10:28:22 +053076 * Top level nss context structure
77 */
78struct nss_top_instance nss_top_main;
wthomas442c7972013-08-05 14:28:17 -070079struct nss_cmd_buffer nss_cmd_buf;
wthomas626147f2013-09-18 13:12:40 -070080struct nss_runtime_sampling nss_runtime_samples;
81struct workqueue_struct *nss_wq;
82
83/*
84 * Work Queue to handle messages to Kernel
85 */
86nss_work_t *nss_work;
Abhishek Rastogibc74e432013-04-02 10:28:22 +053087
88/*
89 * File local/Static variables/functions
90 */
91
Abhishek Rastogi271eee72013-07-29 21:08:36 +053092static const struct net_device_ops nss_netdev_ops;
93static const struct ethtool_ops nss_ethtool_ops;
94
95/*
96 * nss_dummy_netdev_setup()
97 * Dummy setup for net_device handler
98 */
99static void nss_dummy_netdev_setup(struct net_device *ndev)
100{
wthomas626147f2013-09-18 13:12:40 -0700101
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530102}
103
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530104/*
105 * nss_handle_irq()
106 * HLOS interrupt handler for nss interrupts
107 */
108static irqreturn_t nss_handle_irq (int irq, void *ctx)
109{
110 struct int_ctx_instance *int_ctx = (struct int_ctx_instance *) ctx;
Abhishek Rastogi80f4eb12013-09-24 14:31:21 +0530111 struct nss_ctx_instance *nss_ctx = int_ctx->nss_ctx;
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530112
113 /*
Abhishek Rastogi80f4eb12013-09-24 14:31:21 +0530114 * Mask interrupt until our bottom half re-enables it
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530115 */
Abhishek Rastogi80f4eb12013-09-24 14:31:21 +0530116 nss_hal_disable_interrupt(nss_ctx->nmap, int_ctx->irq,
117 int_ctx->shift_factor, NSS_HAL_SUPPORTED_INTERRUPTS);
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530118
119 /*
120 * Schedule tasklet to process interrupt cause
121 */
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530122 napi_schedule(&int_ctx->napi);
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530123 return IRQ_HANDLED;
124}
125
126/*
127 * nss_probe()
128 * HLOS device probe callback
129 */
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530130static int __devinit nss_probe(struct platform_device *nss_dev)
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530131{
132 struct nss_top_instance *nss_top = &nss_top_main;
133 struct nss_ctx_instance *nss_ctx = &nss_top->nss[nss_dev->id];
134 struct nss_platform_data *npd = (struct nss_platform_data *) nss_dev->dev.platform_data;
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530135 struct netdev_priv_instance *ndev_priv;
136 int i, err = 0;
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530137
138 nss_ctx->nss_top = nss_top;
139 nss_ctx->id = nss_dev->id;
140
wthomas442c7972013-08-05 14:28:17 -0700141 nss_info("%p: NSS_DEV_ID %s \n", nss_ctx, dev_name(&nss_dev->dev));
142
143 /*
144 * Both NSS cores controlled by same regulator, Hook only Once
145 */
146 if (!nss_dev->id) {
Thomas Wufb6a6842013-10-23 13:14:27 -0700147 nss_core0_clk = clk_get(&nss_dev->dev, "nss_core_clk");
148 if (IS_ERR(nss_core0_clk)) {
wthomas442c7972013-08-05 14:28:17 -0700149
Thomas Wufb6a6842013-10-23 13:14:27 -0700150 err = PTR_ERR(nss_core0_clk);
wthomas442c7972013-08-05 14:28:17 -0700151 nss_info("%p: Regulator %s get failed, err=%d\n", nss_ctx, dev_name(&nss_dev->dev), err);
152 return err;
153
wthomas442c7972013-08-05 14:28:17 -0700154 }
Thomas Wufb6a6842013-10-23 13:14:27 -0700155 clk_set_rate(nss_core0_clk, NSS_FREQ_550);
156 clk_prepare(nss_core0_clk);
157 clk_enable(nss_core0_clk);
wthomas442c7972013-08-05 14:28:17 -0700158 }
159
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530160 /*
161 * Get virtual and physical memory addresses for nss logical/hardware address maps
162 */
163
164 /*
165 * Virtual address of CSM space
166 */
167 nss_ctx->nmap = npd->nmap;
168 nss_assert(nss_ctx->nmap);
169
170 /*
171 * Physical address of CSM space
172 */
173 nss_ctx->nphys = npd->nphys;
174 nss_assert(nss_ctx->nphys);
175
176 /*
177 * Virtual address of logical registers space
178 */
179 nss_ctx->vmap = npd->vmap;
180 nss_assert(nss_ctx->vmap);
181
182 /*
183 * Physical address of logical registers space
184 */
185 nss_ctx->vphys = npd->vphys;
186 nss_assert(nss_ctx->vphys);
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530187 nss_info("%d:ctx=%p, vphys=%x, vmap=%x, nphys=%x, nmap=%x",
188 nss_dev->id, nss_ctx, nss_ctx->vphys, nss_ctx->vmap, nss_ctx->nphys, nss_ctx->nmap);
189
190 /*
191 * Register netdevice handlers
192 */
193 nss_ctx->int_ctx[0].ndev = alloc_netdev(sizeof(struct netdev_priv_instance),
194 "qca-nss-dev%d", nss_dummy_netdev_setup);
195 if (nss_ctx->int_ctx[0].ndev == NULL) {
196 nss_warning("%p: Could not allocate net_device #0", nss_ctx);
197 err = -ENOMEM;
198 goto err_init_0;
199 }
200
201 nss_ctx->int_ctx[0].ndev->netdev_ops = &nss_netdev_ops;
202 nss_ctx->int_ctx[0].ndev->ethtool_ops = &nss_ethtool_ops;
203 err = register_netdev(nss_ctx->int_ctx[0].ndev);
204 if (err) {
205 nss_warning("%p: Could not register net_device #0", nss_ctx);
206 goto err_init_1;
207 }
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530208
209 /*
210 * request for IRQs
211 *
212 * WARNING: CPU affinities should be set using OS supported methods
213 */
214 nss_ctx->int_ctx[0].nss_ctx = nss_ctx;
215 nss_ctx->int_ctx[0].shift_factor = 0;
216 nss_ctx->int_ctx[0].irq = npd->irq[0];
217 err = request_irq(npd->irq[0], nss_handle_irq, IRQF_DISABLED, "nss", &nss_ctx->int_ctx[0]);
218 if (err) {
219 nss_warning("%d: IRQ0 request failed", nss_dev->id);
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530220 goto err_init_2;
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530221 }
222
223 /*
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530224 * Register NAPI for NSS core interrupt #0
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530225 */
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530226 ndev_priv = netdev_priv(nss_ctx->int_ctx[0].ndev);
227 ndev_priv->int_ctx = &nss_ctx->int_ctx[0];
228 netif_napi_add(nss_ctx->int_ctx[0].ndev, &nss_ctx->int_ctx[0].napi, nss_core_handle_napi, 64);
229 napi_enable(&nss_ctx->int_ctx[0].napi);
230 nss_ctx->int_ctx[0].napi_active = true;
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530231
232 /*
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530233 * Check if second interrupt is supported on this nss core
234 */
235 if (npd->num_irq > 1) {
236 nss_info("%d: This NSS core supports two interrupts", nss_dev->id);
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530237
238 /*
239 * Register netdevice handlers
240 */
241 nss_ctx->int_ctx[1].ndev = alloc_netdev(sizeof(struct netdev_priv_instance),
242 "qca-nss-dev%d", nss_dummy_netdev_setup);
243 if (nss_ctx->int_ctx[1].ndev == NULL) {
244 nss_warning("%p: Could not allocate net_device #1", nss_ctx);
245 err = -ENOMEM;
246 goto err_init_3;
247 }
248
249 nss_ctx->int_ctx[1].ndev->netdev_ops = &nss_netdev_ops;
250 nss_ctx->int_ctx[1].ndev->ethtool_ops = &nss_ethtool_ops;
251 err = register_netdev(nss_ctx->int_ctx[1].ndev);
252 if (err) {
253 nss_warning("%p: Could not register net_device #1", nss_ctx);
254 goto err_init_4;
255 }
256
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530257 nss_ctx->int_ctx[1].nss_ctx = nss_ctx;
258 nss_ctx->int_ctx[1].shift_factor = 15;
259 nss_ctx->int_ctx[1].irq = npd->irq[1];
260 err = request_irq(npd->irq[1], nss_handle_irq, IRQF_DISABLED, "nss", &nss_ctx->int_ctx[1]);
261 if (err) {
262 nss_warning("%d: IRQ1 request failed for nss", nss_dev->id);
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530263 goto err_init_5;
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530264 }
265
266 /*
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530267 * Register NAPI for NSS core interrupt #1
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530268 */
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530269 ndev_priv = netdev_priv(nss_ctx->int_ctx[1].ndev);
270 ndev_priv->int_ctx = &nss_ctx->int_ctx[1];
271 netif_napi_add(nss_ctx->int_ctx[1].ndev, &nss_ctx->int_ctx[1].napi, nss_core_handle_napi, 64);
272 napi_enable(&nss_ctx->int_ctx[1].napi);
273 nss_ctx->int_ctx[1].napi_active = true;
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530274 }
275
276 spin_lock_bh(&(nss_top->lock));
277
278 /*
279 * Check functionalities are supported by this NSS core
280 */
281 if (npd->ipv4_enabled == NSS_FEATURE_ENABLED) {
282 nss_top->ipv4_handler_id = nss_dev->id;
283 }
284
285 if (npd->ipv6_enabled == NSS_FEATURE_ENABLED) {
286 nss_top->ipv6_handler_id = nss_dev->id;
287 }
288
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530289 if (npd->crypto_enabled == NSS_FEATURE_ENABLED) {
290 nss_top->crypto_handler_id = nss_dev->id;
291 }
292
293 if (npd->ipsec_enabled == NSS_FEATURE_ENABLED) {
294 nss_top->ipsec_handler_id = nss_dev->id;
295 }
296
297 if (npd->wlan_enabled == NSS_FEATURE_ENABLED) {
298 nss_top->wlan_handler_id = nss_dev->id;
299 }
300
Bharath M Kumar0d87e912013-08-12 18:32:57 +0530301 if (npd->tun6rd_enabled == NSS_FEATURE_ENABLED) {
302 nss_top->tun6rd_handler_id = nss_dev->id;
303 }
304
Bharath M Kumar614bbf82013-08-31 20:18:44 +0530305 if (npd->tunipip6_enabled == NSS_FEATURE_ENABLED) {
306 nss_top->tunipip6_handler_id = nss_dev->id;
307 }
308
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530309 if (npd->gmac_enabled[0] == NSS_FEATURE_ENABLED) {
310 nss_top->phys_if_handler_id[0] = nss_dev->id;
311 }
312
313 if (npd->gmac_enabled[1] == NSS_FEATURE_ENABLED) {
314 nss_top->phys_if_handler_id[1] = nss_dev->id;
315 }
316
317 if (npd->gmac_enabled[2] == NSS_FEATURE_ENABLED) {
318 nss_top->phys_if_handler_id[2] = nss_dev->id;
319 }
320
321 if (npd->gmac_enabled[3] == NSS_FEATURE_ENABLED) {
322 nss_top->phys_if_handler_id[3] = nss_dev->id;
323 }
324
wthomas626147f2013-09-18 13:12:40 -0700325 nss_top->frequency_handler_id = nss_dev->id;
326
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530327 spin_unlock_bh(&(nss_top->lock));
328
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530329 /*
330 * Initialize decongestion callbacks to NULL
331 */
332 for (i = 0; i< NSS_MAX_CLIENTS; i++) {
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530333 nss_ctx->queue_decongestion_callback[i] = 0;
334 nss_ctx->queue_decongestion_ctx[i] = 0;
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530335 }
336
337 spin_lock_init(&(nss_ctx->decongest_cb_lock));
338 nss_ctx->magic = NSS_CTX_MAGIC;
339
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530340 nss_info("%p: Reseting NSS core %d now", nss_ctx, nss_ctx->id);
341
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530342 /*
343 * Enable clocks and bring NSS core out of reset
344 */
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530345 nss_hal_core_reset(nss_dev->id, nss_ctx->nmap, nss_ctx->load, nss_top->clk_src);
346
347 /*
348 * Enable interrupts for NSS core
349 */
350 nss_hal_enable_interrupt(nss_ctx->nmap, nss_ctx->int_ctx[0].irq,
351 nss_ctx->int_ctx[0].shift_factor, NSS_HAL_SUPPORTED_INTERRUPTS);
352
353 if (npd->num_irq > 1) {
354 nss_hal_enable_interrupt(nss_ctx->nmap, nss_ctx->int_ctx[1].irq,
355 nss_ctx->int_ctx[1].shift_factor, NSS_HAL_SUPPORTED_INTERRUPTS);
356 }
357
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530358 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 +0530359 goto err_init_0;
360
361err_init_5:
362 unregister_netdev(nss_ctx->int_ctx[1].ndev);
363err_init_4:
364 free_netdev(nss_ctx->int_ctx[1].ndev);
365err_init_3:
366 free_irq(npd->irq[0], &nss_ctx->int_ctx[0]);
367err_init_2:
368 unregister_netdev(nss_ctx->int_ctx[0].ndev);
369err_init_1:
370 free_netdev(nss_ctx->int_ctx[0].ndev);
371err_init_0:
372 return err;
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530373}
374
375/*
376 * nss_remove()
377 * HLOS device remove callback
378 */
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530379static int __devexit nss_remove(struct platform_device *nss_dev)
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530380{
381 struct nss_top_instance *nss_top = &nss_top_main;
382 struct nss_ctx_instance *nss_ctx = &nss_top->nss[nss_dev->id];
383
384 /*
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530385 * Clean-up debugfs
386 */
387 nss_stats_clean();
388
389 /*
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530390 * Disable interrupts and bottom halves in HLOS
391 * Disable interrupts from NSS to HLOS
392 */
393 nss_hal_disable_interrupt(nss_ctx->nmap, nss_ctx->int_ctx[0].irq,
394 nss_ctx->int_ctx[0].shift_factor, NSS_HAL_SUPPORTED_INTERRUPTS);
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530395
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530396 free_irq(nss_ctx->int_ctx[0].irq, &nss_ctx->int_ctx[0]);
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530397 unregister_netdev(nss_ctx->int_ctx[0].ndev);
398 free_netdev(nss_ctx->int_ctx[0].ndev);
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530399
400 /*
401 * Check if second interrupt is supported
402 * If so then clear resources for second interrupt as well
403 */
404 if (nss_ctx->int_ctx[1].irq) {
405 nss_hal_disable_interrupt(nss_ctx->nmap, nss_ctx->int_ctx[1].irq,
406 nss_ctx->int_ctx[1].shift_factor, NSS_HAL_SUPPORTED_INTERRUPTS);
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530407 free_irq(nss_ctx->int_ctx[1].irq, &nss_ctx->int_ctx[1]);
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530408 unregister_netdev(nss_ctx->int_ctx[1].ndev);
409 free_netdev(nss_ctx->int_ctx[1].ndev);
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530410 }
411
412 nss_info("%p: All resources freed for nss core%d", nss_ctx, nss_dev->id);
413 return 0;
414}
415
416/*
417 * nss_driver
418 * Platform driver structure for NSS
419 */
420struct platform_driver nss_driver = {
421 .probe = nss_probe,
422 .remove = __devexit_p(nss_remove),
423 .driver = {
424 .name = "qca-nss",
425 .owner = THIS_MODULE,
426 },
427};
428
429/*
wthomas626147f2013-09-18 13:12:40 -0700430 ***************************************************************************************************
Thomas Wufb6a6842013-10-23 13:14:27 -0700431 * nss_wq_function() is used to queue up requests to change NSS frequencies.
432 * The function will take care of NSS notices and also control clock.
433 * The auto rate algorithmn will queue up requests or the procfs may also queue up these requests.
wthomas626147f2013-09-18 13:12:40 -0700434 ***************************************************************************************************
435 */
436
437/*
438 * nss_wq_function()
439 * Added to Handle BH requests to kernel
440 */
441void nss_wq_function (struct work_struct *work)
442{
443 nss_work_t *my_work = (nss_work_t *)work;
444
Thomas Wufb6a6842013-10-23 13:14:27 -0700445 nss_freq_change(nss_freq_change_context, my_work->frequency, 0);
446 clk_set_rate(nss_core0_clk, my_work->frequency);
447 nss_freq_change(nss_freq_change_context, my_work->frequency, 1);
wthomas626147f2013-09-18 13:12:40 -0700448
449 kfree((void *)work);
450}
451
452/*
wthomas442c7972013-08-05 14:28:17 -0700453 * nss_current_freq_handler()
454 * Handle Userspace Frequency Change Requests
455 */
456static int nss_current_freq_handler (ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos)
457{
wthomas442c7972013-08-05 14:28:17 -0700458 int ret;
wthomas626147f2013-09-18 13:12:40 -0700459
460 BUG_ON(!nss_wq);
wthomas442c7972013-08-05 14:28:17 -0700461
462 ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
463
wthomasd39fa822013-08-22 16:44:23 -0700464 if (!write) {
wthomas626147f2013-09-18 13:12:40 -0700465 printk("Frequency Set to %d\n", nss_cmd_buf.current_freq);
wthomasd39fa822013-08-22 16:44:23 -0700466 return ret;
wthomas442c7972013-08-05 14:28:17 -0700467 }
wthomasd39fa822013-08-22 16:44:23 -0700468
wthomas626147f2013-09-18 13:12:40 -0700469 /* Turn off Auto Scale */
470 nss_cmd_buf.auto_scale = 0;
471 nss_runtime_samples.freq_scale_ready = 0;
wthomasd39fa822013-08-22 16:44:23 -0700472
473 /* If support NSS freq is in the table send the new frequency request to NSS */
Thomas Wufb6a6842013-10-23 13:14:27 -0700474 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)) {
475 printk("Frequency not found. Please check Frequency Table\n");
wthomas626147f2013-09-18 13:12:40 -0700476 return ret;
wthomasd39fa822013-08-22 16:44:23 -0700477 }
478
wthomas626147f2013-09-18 13:12:40 -0700479 nss_work = (nss_work_t *)kmalloc(sizeof(nss_work_t), GFP_KERNEL);
480 if (!nss_work) {
481 nss_info("NSS Freq WQ kmalloc fail");
482 return ret;
483 }
484 INIT_WORK((struct work_struct *)nss_work, nss_wq_function);
485 nss_work->frequency = nss_cmd_buf.current_freq;
wthomas626147f2013-09-18 13:12:40 -0700486 queue_work(nss_wq, (struct work_struct *)nss_work);
487
wthomas442c7972013-08-05 14:28:17 -0700488 return ret;
489}
490
491/*
492 * nss_auto_scale_handler()
493 * Enables or Disable Auto Scaling
494 */
495static int nss_auto_scale_handler (ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos)
496{
497 int ret;
498
499 ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
500
wthomas626147f2013-09-18 13:12:40 -0700501 if (!write) {
502 return ret;
503 }
504
Thomas Wufb6a6842013-10-23 13:14:27 -0700505 if (nss_cmd_buf.auto_scale != 1) {
wthomas626147f2013-09-18 13:12:40 -0700506 /*
507 * Auto Scaling is already disabled
508 */
wthomas626147f2013-09-18 13:12:40 -0700509 nss_runtime_samples.freq_scale_ready = 0;
Thomas Wufb6a6842013-10-23 13:14:27 -0700510 return ret;
wthomas626147f2013-09-18 13:12:40 -0700511 }
wthomas442c7972013-08-05 14:28:17 -0700512
Thomas Wufb6a6842013-10-23 13:14:27 -0700513 /*
514 * Auto Scaling is already being done
515 */
516 if (nss_runtime_samples.freq_scale_ready == 1) {
517 return ret;
518 }
519
520 /*
521 * Setup default values - Middle of Freq Scale Band
522 */
523 nss_runtime_samples.freq_scale_index = 1;
524 nss_cmd_buf.current_freq = nss_runtime_samples.freq_scale[nss_runtime_samples.freq_scale_index].frequency;
525
526 nss_work = (nss_work_t *)kmalloc(sizeof(nss_work_t), GFP_KERNEL);
527 if (!nss_work) {
528 nss_info("NSS Freq WQ kmalloc fail");
529 return ret;
530 }
531 INIT_WORK((struct work_struct *)nss_work, nss_wq_function);
532 nss_work->frequency = nss_cmd_buf.current_freq;
533 queue_work(nss_wq, (struct work_struct *)nss_work);
534
535 nss_runtime_samples.freq_scale_ready = 1;
536
wthomas442c7972013-08-05 14:28:17 -0700537 return ret;
538}
539
540/*
541 * nss_get_freq_table_handler()
542 * Display Support Freq and Ex how to Change.
543 */
544static int nss_get_freq_table_handler (ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos)
545{
546 int ret;
547
548 ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
549
wthomas626147f2013-09-18 13:12:40 -0700550 printk("Frequency Supported - 110Mhz 275Mhz 550Mhz 733Mhz \n");
wthomas442c7972013-08-05 14:28:17 -0700551 printk("Ex. To Change Frequency - echo 110000000 > current_freq \n");
552
553 return ret;
554}
555
556/*
557 * sysctl-tuning infrastructure.
558 */
559static ctl_table nss_freq_table[] = {
560 {
561 .procname = "current_freq",
562 .data = &nss_cmd_buf.current_freq,
563 .maxlen = sizeof(int),
564 .mode = 0644,
565 .proc_handler = &nss_current_freq_handler,
566 },
567 {
568 .procname = "freq_table",
569 .data = &nss_cmd_buf.max_freq,
570 .maxlen = sizeof(int),
571 .mode = 0644,
572 .proc_handler = &nss_get_freq_table_handler,
573 },
574 {
575 .procname = "auto_scale",
576 .data = &nss_cmd_buf.auto_scale,
577 .maxlen = sizeof(int),
578 .mode = 0644,
579 .proc_handler = &nss_auto_scale_handler,
580 },
581 { }
582};
583
584static ctl_table nss_clock_dir[] = {
585 {
586 .procname = "clock",
587 .mode = 0555,
588 .child = nss_freq_table,
589 },
590 { }
591};
592
593static ctl_table nss_root_dir[] = {
594 {
595 .procname = "nss",
596 .mode = 0555,
597 .child = nss_clock_dir,
598 },
599 { }
600};
601
602static ctl_table nss_root[] = {
603 {
604 .procname = "dev",
605 .mode = 0555,
606 .child = nss_root_dir,
607 },
608 { }
609};
610
611static struct ctl_table_header *nss_dev_header;
612
613/*
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530614 * nss_init()
615 * Registers nss driver
616 */
617static int __init nss_init(void)
618{
619 nss_info("Init NSS driver");
620
wthomas626147f2013-09-18 13:12:40 -0700621 nss_freq_change_context = nss_get_frequency_mgr();
622
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530623 /*
624 * Perform clock init common to all NSS cores
625 */
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530626 nss_hal_common_reset(&(nss_top_main.clk_src));
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530627
628 /*
629 * Enable spin locks
630 */
631 spin_lock_init(&(nss_top_main.lock));
632 spin_lock_init(&(nss_top_main.stats_lock));
633
634 /*
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530635 * Enable NSS statistics
636 */
637 nss_stats_init();
638
639 /*
640 * Store load addresses
641 */
642 nss_top_main.nss[0].load = (uint32_t)load0;
643 nss_top_main.nss[1].load = (uint32_t)load1;
644
645 /*
wthomas442c7972013-08-05 14:28:17 -0700646 * Register sysctl table.
647 */
648 nss_dev_header = register_sysctl_table(nss_root);
649
650 /*
wthomas626147f2013-09-18 13:12:40 -0700651 * Setup Runtime Sample values
652 */
653 nss_runtime_samples.freq_scale[0].frequency = NSS_FREQ_110;
wthomas626147f2013-09-18 13:12:40 -0700654 nss_runtime_samples.freq_scale[0].minimum = NSS_FREQ_110_MIN;
655 nss_runtime_samples.freq_scale[0].maximum = NSS_FREQ_110_MAX;
wthomas626147f2013-09-18 13:12:40 -0700656 nss_runtime_samples.freq_scale[1].frequency = NSS_FREQ_550;
wthomas626147f2013-09-18 13:12:40 -0700657 nss_runtime_samples.freq_scale[1].minimum = NSS_FREQ_550_MIN;
658 nss_runtime_samples.freq_scale[1].maximum = NSS_FREQ_550_MAX;
wthomas626147f2013-09-18 13:12:40 -0700659 nss_runtime_samples.freq_scale[2].frequency = NSS_FREQ_733;
wthomas626147f2013-09-18 13:12:40 -0700660 nss_runtime_samples.freq_scale[2].minimum = NSS_FREQ_733_MIN;
661 nss_runtime_samples.freq_scale[2].maximum = NSS_FREQ_733_MAX;
wthomas626147f2013-09-18 13:12:40 -0700662 nss_runtime_samples.freq_scale_index = 1;
663 nss_runtime_samples.freq_scale_ready = 0;
664 nss_runtime_samples.freq_scale_rate_limit = 0;
665 nss_runtime_samples.buffer_index = 0;
666 nss_runtime_samples.sum = 0;
667 nss_runtime_samples.sample_count = 0;
668 nss_runtime_samples.average = 0;
669 nss_runtime_samples.message_rate_limit = 0;
670
671 /*
672 * Initial Workqueue
673 */
674 nss_wq = create_workqueue("nss_freq_queue");
675
676 /*
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530677 * Register platform_driver
678 */
679 return platform_driver_register(&nss_driver);
680}
681
682/*
683 * nss_cleanup()
684 * Unregisters nss driver
685 */
686static void __exit nss_cleanup(void)
687{
688 nss_info("Exit NSS driver");
wthomas442c7972013-08-05 14:28:17 -0700689
690 if (nss_dev_header)
691 unregister_sysctl_table(nss_dev_header);
692
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530693 platform_driver_unregister(&nss_driver);
694}
695
696module_init(nss_init);
697module_exit(nss_cleanup);
698
699MODULE_DESCRIPTION("QCA NSS Driver");
700MODULE_AUTHOR("Qualcomm Atheros Inc");
701MODULE_LICENSE("Dual BSD/GPL");