blob: 6e4dd3f7f7b50b9438754a214a8dcb5be763a14f [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;
Abhishek Rastogi1626a902013-11-21 17:09:49 +053070int nss_ctl_debug __read_mostly = 0;
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/*
Abhishek Rastogi1626a902013-11-21 17:09:49 +0530560 * nss_debug_handler()
561 * Enable NSS debug output
562 */
563static int nss_debug_handler(ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos)
564{
565 int ret;
566
567 ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
568 if (!ret) {
569 if ((write) && (nss_ctl_debug != 0)) {
570 printk("Enabling NSS SPI Debug\n");
571 nss_hal_debug_enable();
572 }
573 }
574
575 return ret;
576}
577
578/*
wthomas442c7972013-08-05 14:28:17 -0700579 * sysctl-tuning infrastructure.
580 */
581static ctl_table nss_freq_table[] = {
582 {
583 .procname = "current_freq",
584 .data = &nss_cmd_buf.current_freq,
585 .maxlen = sizeof(int),
586 .mode = 0644,
587 .proc_handler = &nss_current_freq_handler,
588 },
589 {
590 .procname = "freq_table",
591 .data = &nss_cmd_buf.max_freq,
592 .maxlen = sizeof(int),
593 .mode = 0644,
594 .proc_handler = &nss_get_freq_table_handler,
595 },
596 {
597 .procname = "auto_scale",
598 .data = &nss_cmd_buf.auto_scale,
599 .maxlen = sizeof(int),
600 .mode = 0644,
601 .proc_handler = &nss_auto_scale_handler,
602 },
603 { }
604};
605
Abhishek Rastogi5cd2e4c2013-11-13 18:09:08 +0530606static ctl_table nss_general_table[] = {
607 {
608 .procname = "redirect",
609 .data = &nss_ctl_redirect,
610 .maxlen = sizeof(int),
611 .mode = 0644,
612 .proc_handler = proc_dointvec,
613 },
Abhishek Rastogi1626a902013-11-21 17:09:49 +0530614 {
615 .procname = "debug",
616 .data = &nss_ctl_debug,
617 .maxlen = sizeof(int),
618 .mode = 0644,
619 .proc_handler = &nss_debug_handler,
620 },
Abhishek Rastogi5cd2e4c2013-11-13 18:09:08 +0530621 { }
622};
623
wthomas442c7972013-08-05 14:28:17 -0700624static ctl_table nss_clock_dir[] = {
625 {
Abhishek Rastogi5cd2e4c2013-11-13 18:09:08 +0530626 .procname = "clock",
627 .mode = 0555,
628 .child = nss_freq_table,
629 },
630 {
631 .procname = "general",
632 .mode = 0555,
633 .child = nss_general_table,
wthomas442c7972013-08-05 14:28:17 -0700634 },
635 { }
636};
637
638static ctl_table nss_root_dir[] = {
639 {
640 .procname = "nss",
641 .mode = 0555,
642 .child = nss_clock_dir,
643 },
644 { }
645};
646
647static ctl_table nss_root[] = {
648 {
649 .procname = "dev",
650 .mode = 0555,
651 .child = nss_root_dir,
652 },
653 { }
654};
655
656static struct ctl_table_header *nss_dev_header;
657
658/*
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530659 * nss_init()
660 * Registers nss driver
661 */
662static int __init nss_init(void)
663{
664 nss_info("Init NSS driver");
665
wthomas626147f2013-09-18 13:12:40 -0700666 nss_freq_change_context = nss_get_frequency_mgr();
667
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530668 /*
669 * Perform clock init common to all NSS cores
670 */
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530671 nss_hal_common_reset(&(nss_top_main.clk_src));
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530672
673 /*
674 * Enable spin locks
675 */
676 spin_lock_init(&(nss_top_main.lock));
677 spin_lock_init(&(nss_top_main.stats_lock));
678
679 /*
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530680 * Enable NSS statistics
681 */
682 nss_stats_init();
683
684 /*
685 * Store load addresses
686 */
687 nss_top_main.nss[0].load = (uint32_t)load0;
688 nss_top_main.nss[1].load = (uint32_t)load1;
689
690 /*
wthomas442c7972013-08-05 14:28:17 -0700691 * Register sysctl table.
692 */
693 nss_dev_header = register_sysctl_table(nss_root);
694
695 /*
wthomas626147f2013-09-18 13:12:40 -0700696 * Setup Runtime Sample values
697 */
698 nss_runtime_samples.freq_scale[0].frequency = NSS_FREQ_110;
wthomas626147f2013-09-18 13:12:40 -0700699 nss_runtime_samples.freq_scale[0].minimum = NSS_FREQ_110_MIN;
700 nss_runtime_samples.freq_scale[0].maximum = NSS_FREQ_110_MAX;
wthomas626147f2013-09-18 13:12:40 -0700701 nss_runtime_samples.freq_scale[1].frequency = NSS_FREQ_550;
wthomas626147f2013-09-18 13:12:40 -0700702 nss_runtime_samples.freq_scale[1].minimum = NSS_FREQ_550_MIN;
703 nss_runtime_samples.freq_scale[1].maximum = NSS_FREQ_550_MAX;
wthomas626147f2013-09-18 13:12:40 -0700704 nss_runtime_samples.freq_scale[2].frequency = NSS_FREQ_733;
wthomas626147f2013-09-18 13:12:40 -0700705 nss_runtime_samples.freq_scale[2].minimum = NSS_FREQ_733_MIN;
706 nss_runtime_samples.freq_scale[2].maximum = NSS_FREQ_733_MAX;
wthomas626147f2013-09-18 13:12:40 -0700707 nss_runtime_samples.freq_scale_index = 1;
708 nss_runtime_samples.freq_scale_ready = 0;
Thomas Wu9681f7e2013-11-06 13:12:57 -0800709 nss_runtime_samples.freq_scale_rate_limit_up = 0;
710 nss_runtime_samples.freq_scale_rate_limit_down = 0;
wthomas626147f2013-09-18 13:12:40 -0700711 nss_runtime_samples.buffer_index = 0;
712 nss_runtime_samples.sum = 0;
713 nss_runtime_samples.sample_count = 0;
714 nss_runtime_samples.average = 0;
715 nss_runtime_samples.message_rate_limit = 0;
716
717 /*
718 * Initial Workqueue
719 */
720 nss_wq = create_workqueue("nss_freq_queue");
721
722 /*
Pamidipati, Vijay7f413b52013-09-24 19:07:12 +0530723 * Initialize NSS Bus PM module
724 */
725 nss_pm_init();
726
727 /*
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530728 * Register platform_driver
729 */
730 return platform_driver_register(&nss_driver);
731}
732
733/*
734 * nss_cleanup()
735 * Unregisters nss driver
736 */
737static void __exit nss_cleanup(void)
738{
739 nss_info("Exit NSS driver");
wthomas442c7972013-08-05 14:28:17 -0700740
741 if (nss_dev_header)
742 unregister_sysctl_table(nss_dev_header);
743
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530744 platform_driver_unregister(&nss_driver);
745}
746
747module_init(nss_init);
748module_exit(nss_cleanup);
749
750MODULE_DESCRIPTION("QCA NSS Driver");
751MODULE_AUTHOR("Qualcomm Atheros Inc");
752MODULE_LICENSE("Dual BSD/GPL");