blob: 13858f0213528b46ef71a3c4c94ece5a34eb4728 [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/*
Pamidipati, Vijay5d27d812013-11-22 16:48:11 +053073 * PM client handle
74 */
75static void *pm_client;
76
77/*
wthomas626147f2013-09-18 13:12:40 -070078 * Handler to send NSS messages
79 */
80void *nss_freq_change_context;
Thomas Wufb6a6842013-10-23 13:14:27 -070081struct clk *nss_core0_clk;
wthomas626147f2013-09-18 13:12:40 -070082
83/*
Abhishek Rastogibc74e432013-04-02 10:28:22 +053084 * Top level nss context structure
85 */
86struct nss_top_instance nss_top_main;
wthomas442c7972013-08-05 14:28:17 -070087struct nss_cmd_buffer nss_cmd_buf;
wthomas626147f2013-09-18 13:12:40 -070088struct nss_runtime_sampling nss_runtime_samples;
89struct workqueue_struct *nss_wq;
90
91/*
92 * Work Queue to handle messages to Kernel
93 */
94nss_work_t *nss_work;
Abhishek Rastogibc74e432013-04-02 10:28:22 +053095
96/*
97 * File local/Static variables/functions
98 */
99
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530100static const struct net_device_ops nss_netdev_ops;
101static const struct ethtool_ops nss_ethtool_ops;
102
103/*
104 * nss_dummy_netdev_setup()
105 * Dummy setup for net_device handler
106 */
107static void nss_dummy_netdev_setup(struct net_device *ndev)
108{
wthomas626147f2013-09-18 13:12:40 -0700109
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530110}
111
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530112/*
113 * nss_handle_irq()
114 * HLOS interrupt handler for nss interrupts
115 */
116static irqreturn_t nss_handle_irq (int irq, void *ctx)
117{
118 struct int_ctx_instance *int_ctx = (struct int_ctx_instance *) ctx;
Abhishek Rastogi80f4eb12013-09-24 14:31:21 +0530119 struct nss_ctx_instance *nss_ctx = int_ctx->nss_ctx;
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530120
121 /*
Abhishek Rastogi80f4eb12013-09-24 14:31:21 +0530122 * Mask interrupt until our bottom half re-enables it
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530123 */
Abhishek Rastogi80f4eb12013-09-24 14:31:21 +0530124 nss_hal_disable_interrupt(nss_ctx->nmap, int_ctx->irq,
125 int_ctx->shift_factor, NSS_HAL_SUPPORTED_INTERRUPTS);
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530126
127 /*
128 * Schedule tasklet to process interrupt cause
129 */
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530130 napi_schedule(&int_ctx->napi);
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530131 return IRQ_HANDLED;
132}
133
134/*
135 * nss_probe()
136 * HLOS device probe callback
137 */
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530138static int __devinit nss_probe(struct platform_device *nss_dev)
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530139{
140 struct nss_top_instance *nss_top = &nss_top_main;
141 struct nss_ctx_instance *nss_ctx = &nss_top->nss[nss_dev->id];
142 struct nss_platform_data *npd = (struct nss_platform_data *) nss_dev->dev.platform_data;
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530143 struct netdev_priv_instance *ndev_priv;
144 int i, err = 0;
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530145
146 nss_ctx->nss_top = nss_top;
147 nss_ctx->id = nss_dev->id;
148
wthomas442c7972013-08-05 14:28:17 -0700149 nss_info("%p: NSS_DEV_ID %s \n", nss_ctx, dev_name(&nss_dev->dev));
150
151 /*
152 * Both NSS cores controlled by same regulator, Hook only Once
153 */
154 if (!nss_dev->id) {
Thomas Wufb6a6842013-10-23 13:14:27 -0700155 nss_core0_clk = clk_get(&nss_dev->dev, "nss_core_clk");
156 if (IS_ERR(nss_core0_clk)) {
wthomas442c7972013-08-05 14:28:17 -0700157
Thomas Wufb6a6842013-10-23 13:14:27 -0700158 err = PTR_ERR(nss_core0_clk);
wthomas442c7972013-08-05 14:28:17 -0700159 nss_info("%p: Regulator %s get failed, err=%d\n", nss_ctx, dev_name(&nss_dev->dev), err);
160 return err;
161
wthomas442c7972013-08-05 14:28:17 -0700162 }
Thomas Wufb6a6842013-10-23 13:14:27 -0700163 clk_set_rate(nss_core0_clk, NSS_FREQ_550);
164 clk_prepare(nss_core0_clk);
165 clk_enable(nss_core0_clk);
wthomas442c7972013-08-05 14:28:17 -0700166 }
167
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530168 /*
169 * Get virtual and physical memory addresses for nss logical/hardware address maps
170 */
171
172 /*
173 * Virtual address of CSM space
174 */
175 nss_ctx->nmap = npd->nmap;
176 nss_assert(nss_ctx->nmap);
177
178 /*
179 * Physical address of CSM space
180 */
181 nss_ctx->nphys = npd->nphys;
182 nss_assert(nss_ctx->nphys);
183
184 /*
185 * Virtual address of logical registers space
186 */
187 nss_ctx->vmap = npd->vmap;
188 nss_assert(nss_ctx->vmap);
189
190 /*
191 * Physical address of logical registers space
192 */
193 nss_ctx->vphys = npd->vphys;
194 nss_assert(nss_ctx->vphys);
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530195 nss_info("%d:ctx=%p, vphys=%x, vmap=%x, nphys=%x, nmap=%x",
196 nss_dev->id, nss_ctx, nss_ctx->vphys, nss_ctx->vmap, nss_ctx->nphys, nss_ctx->nmap);
197
198 /*
199 * Register netdevice handlers
200 */
201 nss_ctx->int_ctx[0].ndev = alloc_netdev(sizeof(struct netdev_priv_instance),
202 "qca-nss-dev%d", nss_dummy_netdev_setup);
203 if (nss_ctx->int_ctx[0].ndev == NULL) {
204 nss_warning("%p: Could not allocate net_device #0", nss_ctx);
205 err = -ENOMEM;
206 goto err_init_0;
207 }
208
209 nss_ctx->int_ctx[0].ndev->netdev_ops = &nss_netdev_ops;
210 nss_ctx->int_ctx[0].ndev->ethtool_ops = &nss_ethtool_ops;
211 err = register_netdev(nss_ctx->int_ctx[0].ndev);
212 if (err) {
213 nss_warning("%p: Could not register net_device #0", nss_ctx);
214 goto err_init_1;
215 }
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530216
217 /*
218 * request for IRQs
219 *
220 * WARNING: CPU affinities should be set using OS supported methods
221 */
222 nss_ctx->int_ctx[0].nss_ctx = nss_ctx;
223 nss_ctx->int_ctx[0].shift_factor = 0;
224 nss_ctx->int_ctx[0].irq = npd->irq[0];
225 err = request_irq(npd->irq[0], nss_handle_irq, IRQF_DISABLED, "nss", &nss_ctx->int_ctx[0]);
226 if (err) {
227 nss_warning("%d: IRQ0 request failed", nss_dev->id);
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530228 goto err_init_2;
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530229 }
230
231 /*
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530232 * Register NAPI for NSS core interrupt #0
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530233 */
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530234 ndev_priv = netdev_priv(nss_ctx->int_ctx[0].ndev);
235 ndev_priv->int_ctx = &nss_ctx->int_ctx[0];
236 netif_napi_add(nss_ctx->int_ctx[0].ndev, &nss_ctx->int_ctx[0].napi, nss_core_handle_napi, 64);
237 napi_enable(&nss_ctx->int_ctx[0].napi);
238 nss_ctx->int_ctx[0].napi_active = true;
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530239
240 /*
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530241 * Check if second interrupt is supported on this nss core
242 */
243 if (npd->num_irq > 1) {
244 nss_info("%d: This NSS core supports two interrupts", nss_dev->id);
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530245
246 /*
247 * Register netdevice handlers
248 */
249 nss_ctx->int_ctx[1].ndev = alloc_netdev(sizeof(struct netdev_priv_instance),
250 "qca-nss-dev%d", nss_dummy_netdev_setup);
251 if (nss_ctx->int_ctx[1].ndev == NULL) {
252 nss_warning("%p: Could not allocate net_device #1", nss_ctx);
253 err = -ENOMEM;
254 goto err_init_3;
255 }
256
257 nss_ctx->int_ctx[1].ndev->netdev_ops = &nss_netdev_ops;
258 nss_ctx->int_ctx[1].ndev->ethtool_ops = &nss_ethtool_ops;
259 err = register_netdev(nss_ctx->int_ctx[1].ndev);
260 if (err) {
261 nss_warning("%p: Could not register net_device #1", nss_ctx);
262 goto err_init_4;
263 }
264
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530265 nss_ctx->int_ctx[1].nss_ctx = nss_ctx;
266 nss_ctx->int_ctx[1].shift_factor = 15;
267 nss_ctx->int_ctx[1].irq = npd->irq[1];
268 err = request_irq(npd->irq[1], nss_handle_irq, IRQF_DISABLED, "nss", &nss_ctx->int_ctx[1]);
269 if (err) {
270 nss_warning("%d: IRQ1 request failed for nss", nss_dev->id);
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530271 goto err_init_5;
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530272 }
273
274 /*
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530275 * Register NAPI for NSS core interrupt #1
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530276 */
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530277 ndev_priv = netdev_priv(nss_ctx->int_ctx[1].ndev);
278 ndev_priv->int_ctx = &nss_ctx->int_ctx[1];
279 netif_napi_add(nss_ctx->int_ctx[1].ndev, &nss_ctx->int_ctx[1].napi, nss_core_handle_napi, 64);
280 napi_enable(&nss_ctx->int_ctx[1].napi);
281 nss_ctx->int_ctx[1].napi_active = true;
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530282 }
283
284 spin_lock_bh(&(nss_top->lock));
285
286 /*
287 * Check functionalities are supported by this NSS core
288 */
289 if (npd->ipv4_enabled == NSS_FEATURE_ENABLED) {
290 nss_top->ipv4_handler_id = nss_dev->id;
291 }
292
293 if (npd->ipv6_enabled == NSS_FEATURE_ENABLED) {
294 nss_top->ipv6_handler_id = nss_dev->id;
295 }
296
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530297 if (npd->crypto_enabled == NSS_FEATURE_ENABLED) {
298 nss_top->crypto_handler_id = nss_dev->id;
299 }
300
301 if (npd->ipsec_enabled == NSS_FEATURE_ENABLED) {
302 nss_top->ipsec_handler_id = nss_dev->id;
303 }
304
305 if (npd->wlan_enabled == NSS_FEATURE_ENABLED) {
306 nss_top->wlan_handler_id = nss_dev->id;
307 }
308
Bharath M Kumar0d87e912013-08-12 18:32:57 +0530309 if (npd->tun6rd_enabled == NSS_FEATURE_ENABLED) {
310 nss_top->tun6rd_handler_id = nss_dev->id;
311 }
312
Bharath M Kumar614bbf82013-08-31 20:18:44 +0530313 if (npd->tunipip6_enabled == NSS_FEATURE_ENABLED) {
314 nss_top->tunipip6_handler_id = nss_dev->id;
315 }
316
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530317 if (npd->gmac_enabled[0] == NSS_FEATURE_ENABLED) {
318 nss_top->phys_if_handler_id[0] = nss_dev->id;
319 }
320
321 if (npd->gmac_enabled[1] == NSS_FEATURE_ENABLED) {
322 nss_top->phys_if_handler_id[1] = nss_dev->id;
323 }
324
325 if (npd->gmac_enabled[2] == NSS_FEATURE_ENABLED) {
326 nss_top->phys_if_handler_id[2] = nss_dev->id;
327 }
328
329 if (npd->gmac_enabled[3] == NSS_FEATURE_ENABLED) {
330 nss_top->phys_if_handler_id[3] = nss_dev->id;
331 }
332
wthomas626147f2013-09-18 13:12:40 -0700333 nss_top->frequency_handler_id = nss_dev->id;
334
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530335 spin_unlock_bh(&(nss_top->lock));
336
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530337 /*
338 * Initialize decongestion callbacks to NULL
339 */
340 for (i = 0; i< NSS_MAX_CLIENTS; i++) {
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530341 nss_ctx->queue_decongestion_callback[i] = 0;
342 nss_ctx->queue_decongestion_ctx[i] = 0;
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530343 }
344
345 spin_lock_init(&(nss_ctx->decongest_cb_lock));
346 nss_ctx->magic = NSS_CTX_MAGIC;
347
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530348 nss_info("%p: Reseting NSS core %d now", nss_ctx, nss_ctx->id);
349
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530350 /*
351 * Enable clocks and bring NSS core out of reset
352 */
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530353 nss_hal_core_reset(nss_dev->id, nss_ctx->nmap, nss_ctx->load, nss_top->clk_src);
354
355 /*
356 * Enable interrupts for NSS core
357 */
358 nss_hal_enable_interrupt(nss_ctx->nmap, nss_ctx->int_ctx[0].irq,
359 nss_ctx->int_ctx[0].shift_factor, NSS_HAL_SUPPORTED_INTERRUPTS);
360
361 if (npd->num_irq > 1) {
362 nss_hal_enable_interrupt(nss_ctx->nmap, nss_ctx->int_ctx[1].irq,
363 nss_ctx->int_ctx[1].shift_factor, NSS_HAL_SUPPORTED_INTERRUPTS);
364 }
365
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530366 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 +0530367 goto err_init_0;
368
369err_init_5:
370 unregister_netdev(nss_ctx->int_ctx[1].ndev);
371err_init_4:
372 free_netdev(nss_ctx->int_ctx[1].ndev);
373err_init_3:
374 free_irq(npd->irq[0], &nss_ctx->int_ctx[0]);
375err_init_2:
376 unregister_netdev(nss_ctx->int_ctx[0].ndev);
377err_init_1:
378 free_netdev(nss_ctx->int_ctx[0].ndev);
379err_init_0:
380 return err;
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530381}
382
383/*
384 * nss_remove()
385 * HLOS device remove callback
386 */
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530387static int __devexit nss_remove(struct platform_device *nss_dev)
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530388{
389 struct nss_top_instance *nss_top = &nss_top_main;
390 struct nss_ctx_instance *nss_ctx = &nss_top->nss[nss_dev->id];
391
392 /*
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530393 * Clean-up debugfs
394 */
395 nss_stats_clean();
396
397 /*
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530398 * Disable interrupts and bottom halves in HLOS
399 * Disable interrupts from NSS to HLOS
400 */
401 nss_hal_disable_interrupt(nss_ctx->nmap, nss_ctx->int_ctx[0].irq,
402 nss_ctx->int_ctx[0].shift_factor, NSS_HAL_SUPPORTED_INTERRUPTS);
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530403
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530404 free_irq(nss_ctx->int_ctx[0].irq, &nss_ctx->int_ctx[0]);
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530405 unregister_netdev(nss_ctx->int_ctx[0].ndev);
406 free_netdev(nss_ctx->int_ctx[0].ndev);
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530407
408 /*
409 * Check if second interrupt is supported
410 * If so then clear resources for second interrupt as well
411 */
412 if (nss_ctx->int_ctx[1].irq) {
413 nss_hal_disable_interrupt(nss_ctx->nmap, nss_ctx->int_ctx[1].irq,
414 nss_ctx->int_ctx[1].shift_factor, NSS_HAL_SUPPORTED_INTERRUPTS);
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530415 free_irq(nss_ctx->int_ctx[1].irq, &nss_ctx->int_ctx[1]);
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530416 unregister_netdev(nss_ctx->int_ctx[1].ndev);
417 free_netdev(nss_ctx->int_ctx[1].ndev);
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530418 }
419
420 nss_info("%p: All resources freed for nss core%d", nss_ctx, nss_dev->id);
421 return 0;
422}
423
424/*
425 * nss_driver
426 * Platform driver structure for NSS
427 */
428struct platform_driver nss_driver = {
429 .probe = nss_probe,
430 .remove = __devexit_p(nss_remove),
431 .driver = {
432 .name = "qca-nss",
433 .owner = THIS_MODULE,
434 },
435};
436
437/*
wthomas626147f2013-09-18 13:12:40 -0700438 ***************************************************************************************************
Thomas Wufb6a6842013-10-23 13:14:27 -0700439 * nss_wq_function() is used to queue up requests to change NSS frequencies.
440 * The function will take care of NSS notices and also control clock.
441 * The auto rate algorithmn will queue up requests or the procfs may also queue up these requests.
wthomas626147f2013-09-18 13:12:40 -0700442 ***************************************************************************************************
443 */
444
445/*
446 * nss_wq_function()
447 * Added to Handle BH requests to kernel
448 */
449void nss_wq_function (struct work_struct *work)
450{
451 nss_work_t *my_work = (nss_work_t *)work;
452
Thomas Wufb6a6842013-10-23 13:14:27 -0700453 nss_freq_change(nss_freq_change_context, my_work->frequency, 0);
454 clk_set_rate(nss_core0_clk, my_work->frequency);
455 nss_freq_change(nss_freq_change_context, my_work->frequency, 1);
wthomas626147f2013-09-18 13:12:40 -0700456
Pamidipati, Vijay5d27d812013-11-22 16:48:11 +0530457 if(!pm_client) {
458 goto out;
459 }
460
461 if (my_work->frequency == NSS_FREQ_733) {
462 nss_pm_set_perf_level(pm_client, NSS_PM_PERF_LEVEL_TURBO);
463 } else if ((my_work->frequency == NSS_FREQ_275) || (my_work->frequency == NSS_FREQ_550)) {
464 nss_pm_set_perf_level(pm_client, NSS_PM_PERF_LEVEL_NOMINAL);
465 } else {
466 nss_pm_set_perf_level(pm_client, NSS_PM_PERF_LEVEL_IDLE);
467 }
468out:
wthomas626147f2013-09-18 13:12:40 -0700469 kfree((void *)work);
470}
471
472/*
wthomas442c7972013-08-05 14:28:17 -0700473 * nss_current_freq_handler()
474 * Handle Userspace Frequency Change Requests
475 */
476static int nss_current_freq_handler (ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos)
477{
wthomas442c7972013-08-05 14:28:17 -0700478 int ret;
wthomas626147f2013-09-18 13:12:40 -0700479
480 BUG_ON(!nss_wq);
wthomas442c7972013-08-05 14:28:17 -0700481
482 ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
483
wthomasd39fa822013-08-22 16:44:23 -0700484 if (!write) {
wthomas626147f2013-09-18 13:12:40 -0700485 printk("Frequency Set to %d\n", nss_cmd_buf.current_freq);
wthomasd39fa822013-08-22 16:44:23 -0700486 return ret;
wthomas442c7972013-08-05 14:28:17 -0700487 }
wthomasd39fa822013-08-22 16:44:23 -0700488
wthomas626147f2013-09-18 13:12:40 -0700489 /* Turn off Auto Scale */
490 nss_cmd_buf.auto_scale = 0;
491 nss_runtime_samples.freq_scale_ready = 0;
wthomasd39fa822013-08-22 16:44:23 -0700492
493 /* If support NSS freq is in the table send the new frequency request to NSS */
Thomas Wufb6a6842013-10-23 13:14:27 -0700494 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)) {
495 printk("Frequency not found. Please check Frequency Table\n");
wthomas626147f2013-09-18 13:12:40 -0700496 return ret;
wthomasd39fa822013-08-22 16:44:23 -0700497 }
498
wthomas626147f2013-09-18 13:12:40 -0700499 nss_work = (nss_work_t *)kmalloc(sizeof(nss_work_t), GFP_KERNEL);
500 if (!nss_work) {
501 nss_info("NSS Freq WQ kmalloc fail");
502 return ret;
503 }
504 INIT_WORK((struct work_struct *)nss_work, nss_wq_function);
505 nss_work->frequency = nss_cmd_buf.current_freq;
wthomas626147f2013-09-18 13:12:40 -0700506 queue_work(nss_wq, (struct work_struct *)nss_work);
507
wthomas442c7972013-08-05 14:28:17 -0700508 return ret;
509}
510
511/*
512 * nss_auto_scale_handler()
513 * Enables or Disable Auto Scaling
514 */
515static int nss_auto_scale_handler (ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos)
516{
517 int ret;
518
519 ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
520
wthomas626147f2013-09-18 13:12:40 -0700521 if (!write) {
522 return ret;
523 }
524
Thomas Wufb6a6842013-10-23 13:14:27 -0700525 if (nss_cmd_buf.auto_scale != 1) {
wthomas626147f2013-09-18 13:12:40 -0700526 /*
527 * Auto Scaling is already disabled
528 */
wthomas626147f2013-09-18 13:12:40 -0700529 nss_runtime_samples.freq_scale_ready = 0;
Thomas Wufb6a6842013-10-23 13:14:27 -0700530 return ret;
wthomas626147f2013-09-18 13:12:40 -0700531 }
wthomas442c7972013-08-05 14:28:17 -0700532
Thomas Wufb6a6842013-10-23 13:14:27 -0700533 /*
534 * Auto Scaling is already being done
535 */
536 if (nss_runtime_samples.freq_scale_ready == 1) {
537 return ret;
538 }
539
540 /*
541 * Setup default values - Middle of Freq Scale Band
542 */
543 nss_runtime_samples.freq_scale_index = 1;
544 nss_cmd_buf.current_freq = nss_runtime_samples.freq_scale[nss_runtime_samples.freq_scale_index].frequency;
545
546 nss_work = (nss_work_t *)kmalloc(sizeof(nss_work_t), GFP_KERNEL);
547 if (!nss_work) {
548 nss_info("NSS Freq WQ kmalloc fail");
549 return ret;
550 }
551 INIT_WORK((struct work_struct *)nss_work, nss_wq_function);
552 nss_work->frequency = nss_cmd_buf.current_freq;
553 queue_work(nss_wq, (struct work_struct *)nss_work);
554
555 nss_runtime_samples.freq_scale_ready = 1;
556
wthomas442c7972013-08-05 14:28:17 -0700557 return ret;
558}
559
560/*
561 * nss_get_freq_table_handler()
562 * Display Support Freq and Ex how to Change.
563 */
564static int nss_get_freq_table_handler (ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos)
565{
566 int ret;
567
568 ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
569
wthomas626147f2013-09-18 13:12:40 -0700570 printk("Frequency Supported - 110Mhz 275Mhz 550Mhz 733Mhz \n");
wthomas442c7972013-08-05 14:28:17 -0700571 printk("Ex. To Change Frequency - echo 110000000 > current_freq \n");
572
573 return ret;
574}
575
576/*
Abhishek Rastogi1626a902013-11-21 17:09:49 +0530577 * nss_debug_handler()
578 * Enable NSS debug output
579 */
580static int nss_debug_handler(ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos)
581{
582 int ret;
583
584 ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
585 if (!ret) {
586 if ((write) && (nss_ctl_debug != 0)) {
587 printk("Enabling NSS SPI Debug\n");
588 nss_hal_debug_enable();
589 }
590 }
591
592 return ret;
593}
594
595/*
wthomas442c7972013-08-05 14:28:17 -0700596 * sysctl-tuning infrastructure.
597 */
598static ctl_table nss_freq_table[] = {
599 {
600 .procname = "current_freq",
601 .data = &nss_cmd_buf.current_freq,
602 .maxlen = sizeof(int),
603 .mode = 0644,
604 .proc_handler = &nss_current_freq_handler,
605 },
606 {
607 .procname = "freq_table",
608 .data = &nss_cmd_buf.max_freq,
609 .maxlen = sizeof(int),
610 .mode = 0644,
611 .proc_handler = &nss_get_freq_table_handler,
612 },
613 {
614 .procname = "auto_scale",
615 .data = &nss_cmd_buf.auto_scale,
616 .maxlen = sizeof(int),
617 .mode = 0644,
618 .proc_handler = &nss_auto_scale_handler,
619 },
620 { }
621};
622
Abhishek Rastogi5cd2e4c2013-11-13 18:09:08 +0530623static ctl_table nss_general_table[] = {
624 {
625 .procname = "redirect",
626 .data = &nss_ctl_redirect,
627 .maxlen = sizeof(int),
628 .mode = 0644,
629 .proc_handler = proc_dointvec,
630 },
Abhishek Rastogi1626a902013-11-21 17:09:49 +0530631 {
632 .procname = "debug",
633 .data = &nss_ctl_debug,
634 .maxlen = sizeof(int),
635 .mode = 0644,
636 .proc_handler = &nss_debug_handler,
637 },
Abhishek Rastogi5cd2e4c2013-11-13 18:09:08 +0530638 { }
639};
640
wthomas442c7972013-08-05 14:28:17 -0700641static ctl_table nss_clock_dir[] = {
642 {
Abhishek Rastogi5cd2e4c2013-11-13 18:09:08 +0530643 .procname = "clock",
644 .mode = 0555,
645 .child = nss_freq_table,
646 },
647 {
648 .procname = "general",
649 .mode = 0555,
650 .child = nss_general_table,
wthomas442c7972013-08-05 14:28:17 -0700651 },
652 { }
653};
654
655static ctl_table nss_root_dir[] = {
656 {
657 .procname = "nss",
658 .mode = 0555,
659 .child = nss_clock_dir,
660 },
661 { }
662};
663
664static ctl_table nss_root[] = {
665 {
666 .procname = "dev",
667 .mode = 0555,
668 .child = nss_root_dir,
669 },
670 { }
671};
672
673static struct ctl_table_header *nss_dev_header;
674
675/*
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530676 * nss_init()
677 * Registers nss driver
678 */
679static int __init nss_init(void)
680{
681 nss_info("Init NSS driver");
682
wthomas626147f2013-09-18 13:12:40 -0700683 nss_freq_change_context = nss_get_frequency_mgr();
684
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530685 /*
686 * Perform clock init common to all NSS cores
687 */
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530688 nss_hal_common_reset(&(nss_top_main.clk_src));
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530689
690 /*
691 * Enable spin locks
692 */
693 spin_lock_init(&(nss_top_main.lock));
694 spin_lock_init(&(nss_top_main.stats_lock));
695
696 /*
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530697 * Enable NSS statistics
698 */
699 nss_stats_init();
700
701 /*
702 * Store load addresses
703 */
704 nss_top_main.nss[0].load = (uint32_t)load0;
705 nss_top_main.nss[1].load = (uint32_t)load1;
706
707 /*
wthomas442c7972013-08-05 14:28:17 -0700708 * Register sysctl table.
709 */
710 nss_dev_header = register_sysctl_table(nss_root);
711
712 /*
wthomas626147f2013-09-18 13:12:40 -0700713 * Setup Runtime Sample values
714 */
715 nss_runtime_samples.freq_scale[0].frequency = NSS_FREQ_110;
wthomas626147f2013-09-18 13:12:40 -0700716 nss_runtime_samples.freq_scale[0].minimum = NSS_FREQ_110_MIN;
717 nss_runtime_samples.freq_scale[0].maximum = NSS_FREQ_110_MAX;
wthomas626147f2013-09-18 13:12:40 -0700718 nss_runtime_samples.freq_scale[1].frequency = NSS_FREQ_550;
wthomas626147f2013-09-18 13:12:40 -0700719 nss_runtime_samples.freq_scale[1].minimum = NSS_FREQ_550_MIN;
720 nss_runtime_samples.freq_scale[1].maximum = NSS_FREQ_550_MAX;
wthomas626147f2013-09-18 13:12:40 -0700721 nss_runtime_samples.freq_scale[2].frequency = NSS_FREQ_733;
wthomas626147f2013-09-18 13:12:40 -0700722 nss_runtime_samples.freq_scale[2].minimum = NSS_FREQ_733_MIN;
723 nss_runtime_samples.freq_scale[2].maximum = NSS_FREQ_733_MAX;
wthomas626147f2013-09-18 13:12:40 -0700724 nss_runtime_samples.freq_scale_index = 1;
725 nss_runtime_samples.freq_scale_ready = 0;
Thomas Wu9681f7e2013-11-06 13:12:57 -0800726 nss_runtime_samples.freq_scale_rate_limit_up = 0;
727 nss_runtime_samples.freq_scale_rate_limit_down = 0;
wthomas626147f2013-09-18 13:12:40 -0700728 nss_runtime_samples.buffer_index = 0;
729 nss_runtime_samples.sum = 0;
730 nss_runtime_samples.sample_count = 0;
731 nss_runtime_samples.average = 0;
732 nss_runtime_samples.message_rate_limit = 0;
733
734 /*
735 * Initial Workqueue
736 */
737 nss_wq = create_workqueue("nss_freq_queue");
738
739 /*
Pamidipati, Vijay7f413b52013-09-24 19:07:12 +0530740 * Initialize NSS Bus PM module
741 */
742 nss_pm_init();
743
744 /*
Pamidipati, Vijay5d27d812013-11-22 16:48:11 +0530745 * Register with Bus driver
746 */
747 pm_client = nss_pm_client_register(NSS_PM_CLIENT_NETAP);
748 if (!pm_client) {
749 nss_warning("Error registering with PM driver");
750 }
751
752 /*
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530753 * Register platform_driver
754 */
755 return platform_driver_register(&nss_driver);
756}
757
758/*
759 * nss_cleanup()
760 * Unregisters nss driver
761 */
762static void __exit nss_cleanup(void)
763{
764 nss_info("Exit NSS driver");
wthomas442c7972013-08-05 14:28:17 -0700765
766 if (nss_dev_header)
767 unregister_sysctl_table(nss_dev_header);
768
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530769 platform_driver_unregister(&nss_driver);
770}
771
772module_init(nss_init);
773module_exit(nss_cleanup);
774
775MODULE_DESCRIPTION("QCA NSS Driver");
776MODULE_AUTHOR("Qualcomm Atheros Inc");
777MODULE_LICENSE("Dual BSD/GPL");