blob: 5df53833d5d73bd38c792f288bbae3693a5472dd [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);
Thomas Wu0a0a9c92013-11-21 15:28:19 -0800166
167 /*
168 * Check if turbo is supported
169 */
170 if (npd->turbo_frequency) {
171 /*
172 * Turbo is supported
173 */
174 printk("nss_driver - Turbo Support %d\n", npd->turbo_frequency);
175 nss_runtime_samples.freq_scale_sup_max = NSS_MAX_CPU_SCALES;
176 } else {
177 printk("nss_driver - Turbo No Support %d\n", npd->turbo_frequency);
178 nss_runtime_samples.freq_scale_sup_max = NSS_MAX_CPU_SCALES - 1;
179 }
wthomas442c7972013-08-05 14:28:17 -0700180 }
181
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530182 /*
183 * Get virtual and physical memory addresses for nss logical/hardware address maps
184 */
185
186 /*
187 * Virtual address of CSM space
188 */
189 nss_ctx->nmap = npd->nmap;
190 nss_assert(nss_ctx->nmap);
191
192 /*
193 * Physical address of CSM space
194 */
195 nss_ctx->nphys = npd->nphys;
196 nss_assert(nss_ctx->nphys);
197
198 /*
199 * Virtual address of logical registers space
200 */
201 nss_ctx->vmap = npd->vmap;
202 nss_assert(nss_ctx->vmap);
203
204 /*
205 * Physical address of logical registers space
206 */
207 nss_ctx->vphys = npd->vphys;
208 nss_assert(nss_ctx->vphys);
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530209 nss_info("%d:ctx=%p, vphys=%x, vmap=%x, nphys=%x, nmap=%x",
210 nss_dev->id, nss_ctx, nss_ctx->vphys, nss_ctx->vmap, nss_ctx->nphys, nss_ctx->nmap);
211
212 /*
213 * Register netdevice handlers
214 */
215 nss_ctx->int_ctx[0].ndev = alloc_netdev(sizeof(struct netdev_priv_instance),
216 "qca-nss-dev%d", nss_dummy_netdev_setup);
217 if (nss_ctx->int_ctx[0].ndev == NULL) {
218 nss_warning("%p: Could not allocate net_device #0", nss_ctx);
219 err = -ENOMEM;
220 goto err_init_0;
221 }
222
223 nss_ctx->int_ctx[0].ndev->netdev_ops = &nss_netdev_ops;
224 nss_ctx->int_ctx[0].ndev->ethtool_ops = &nss_ethtool_ops;
225 err = register_netdev(nss_ctx->int_ctx[0].ndev);
226 if (err) {
227 nss_warning("%p: Could not register net_device #0", nss_ctx);
228 goto err_init_1;
229 }
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530230
231 /*
232 * request for IRQs
233 *
234 * WARNING: CPU affinities should be set using OS supported methods
235 */
236 nss_ctx->int_ctx[0].nss_ctx = nss_ctx;
237 nss_ctx->int_ctx[0].shift_factor = 0;
238 nss_ctx->int_ctx[0].irq = npd->irq[0];
239 err = request_irq(npd->irq[0], nss_handle_irq, IRQF_DISABLED, "nss", &nss_ctx->int_ctx[0]);
240 if (err) {
241 nss_warning("%d: IRQ0 request failed", nss_dev->id);
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530242 goto err_init_2;
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530243 }
244
245 /*
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530246 * Register NAPI for NSS core interrupt #0
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530247 */
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530248 ndev_priv = netdev_priv(nss_ctx->int_ctx[0].ndev);
249 ndev_priv->int_ctx = &nss_ctx->int_ctx[0];
250 netif_napi_add(nss_ctx->int_ctx[0].ndev, &nss_ctx->int_ctx[0].napi, nss_core_handle_napi, 64);
251 napi_enable(&nss_ctx->int_ctx[0].napi);
252 nss_ctx->int_ctx[0].napi_active = true;
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530253
254 /*
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530255 * Check if second interrupt is supported on this nss core
256 */
257 if (npd->num_irq > 1) {
258 nss_info("%d: This NSS core supports two interrupts", nss_dev->id);
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530259
260 /*
261 * Register netdevice handlers
262 */
263 nss_ctx->int_ctx[1].ndev = alloc_netdev(sizeof(struct netdev_priv_instance),
264 "qca-nss-dev%d", nss_dummy_netdev_setup);
265 if (nss_ctx->int_ctx[1].ndev == NULL) {
266 nss_warning("%p: Could not allocate net_device #1", nss_ctx);
267 err = -ENOMEM;
268 goto err_init_3;
269 }
270
271 nss_ctx->int_ctx[1].ndev->netdev_ops = &nss_netdev_ops;
272 nss_ctx->int_ctx[1].ndev->ethtool_ops = &nss_ethtool_ops;
273 err = register_netdev(nss_ctx->int_ctx[1].ndev);
274 if (err) {
275 nss_warning("%p: Could not register net_device #1", nss_ctx);
276 goto err_init_4;
277 }
278
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530279 nss_ctx->int_ctx[1].nss_ctx = nss_ctx;
280 nss_ctx->int_ctx[1].shift_factor = 15;
281 nss_ctx->int_ctx[1].irq = npd->irq[1];
282 err = request_irq(npd->irq[1], nss_handle_irq, IRQF_DISABLED, "nss", &nss_ctx->int_ctx[1]);
283 if (err) {
284 nss_warning("%d: IRQ1 request failed for nss", nss_dev->id);
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530285 goto err_init_5;
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530286 }
287
288 /*
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530289 * Register NAPI for NSS core interrupt #1
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530290 */
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530291 ndev_priv = netdev_priv(nss_ctx->int_ctx[1].ndev);
292 ndev_priv->int_ctx = &nss_ctx->int_ctx[1];
293 netif_napi_add(nss_ctx->int_ctx[1].ndev, &nss_ctx->int_ctx[1].napi, nss_core_handle_napi, 64);
294 napi_enable(&nss_ctx->int_ctx[1].napi);
295 nss_ctx->int_ctx[1].napi_active = true;
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530296 }
297
298 spin_lock_bh(&(nss_top->lock));
299
300 /*
301 * Check functionalities are supported by this NSS core
302 */
303 if (npd->ipv4_enabled == NSS_FEATURE_ENABLED) {
304 nss_top->ipv4_handler_id = nss_dev->id;
305 }
306
307 if (npd->ipv6_enabled == NSS_FEATURE_ENABLED) {
308 nss_top->ipv6_handler_id = nss_dev->id;
309 }
310
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530311 if (npd->crypto_enabled == NSS_FEATURE_ENABLED) {
312 nss_top->crypto_handler_id = nss_dev->id;
313 }
314
315 if (npd->ipsec_enabled == NSS_FEATURE_ENABLED) {
316 nss_top->ipsec_handler_id = nss_dev->id;
317 }
318
319 if (npd->wlan_enabled == NSS_FEATURE_ENABLED) {
320 nss_top->wlan_handler_id = nss_dev->id;
321 }
322
Bharath M Kumar0d87e912013-08-12 18:32:57 +0530323 if (npd->tun6rd_enabled == NSS_FEATURE_ENABLED) {
324 nss_top->tun6rd_handler_id = nss_dev->id;
325 }
326
Bharath M Kumar614bbf82013-08-31 20:18:44 +0530327 if (npd->tunipip6_enabled == NSS_FEATURE_ENABLED) {
328 nss_top->tunipip6_handler_id = nss_dev->id;
329 }
330
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530331 if (npd->gmac_enabled[0] == NSS_FEATURE_ENABLED) {
332 nss_top->phys_if_handler_id[0] = nss_dev->id;
333 }
334
335 if (npd->gmac_enabled[1] == NSS_FEATURE_ENABLED) {
336 nss_top->phys_if_handler_id[1] = nss_dev->id;
337 }
338
339 if (npd->gmac_enabled[2] == NSS_FEATURE_ENABLED) {
340 nss_top->phys_if_handler_id[2] = nss_dev->id;
341 }
342
343 if (npd->gmac_enabled[3] == NSS_FEATURE_ENABLED) {
344 nss_top->phys_if_handler_id[3] = nss_dev->id;
345 }
346
wthomas626147f2013-09-18 13:12:40 -0700347 nss_top->frequency_handler_id = nss_dev->id;
348
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530349 spin_unlock_bh(&(nss_top->lock));
350
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530351 /*
352 * Initialize decongestion callbacks to NULL
353 */
354 for (i = 0; i< NSS_MAX_CLIENTS; i++) {
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530355 nss_ctx->queue_decongestion_callback[i] = 0;
356 nss_ctx->queue_decongestion_ctx[i] = 0;
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530357 }
358
359 spin_lock_init(&(nss_ctx->decongest_cb_lock));
360 nss_ctx->magic = NSS_CTX_MAGIC;
361
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530362 nss_info("%p: Reseting NSS core %d now", nss_ctx, nss_ctx->id);
363
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530364 /*
365 * Enable clocks and bring NSS core out of reset
366 */
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530367 nss_hal_core_reset(nss_dev->id, nss_ctx->nmap, nss_ctx->load, nss_top->clk_src);
368
369 /*
370 * Enable interrupts for NSS core
371 */
372 nss_hal_enable_interrupt(nss_ctx->nmap, nss_ctx->int_ctx[0].irq,
373 nss_ctx->int_ctx[0].shift_factor, NSS_HAL_SUPPORTED_INTERRUPTS);
374
375 if (npd->num_irq > 1) {
376 nss_hal_enable_interrupt(nss_ctx->nmap, nss_ctx->int_ctx[1].irq,
377 nss_ctx->int_ctx[1].shift_factor, NSS_HAL_SUPPORTED_INTERRUPTS);
378 }
379
Radhakrishna Jigurub7346cf2013-12-16 13:08:43 +0530380 /*
381 * Initialize max buffer size for NSS core
382 */
383 nss_ctx->max_buf_size = NSS_NBUF_PAYLOAD_SIZE;
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530384 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 +0530385 goto err_init_0;
386
387err_init_5:
388 unregister_netdev(nss_ctx->int_ctx[1].ndev);
389err_init_4:
390 free_netdev(nss_ctx->int_ctx[1].ndev);
391err_init_3:
392 free_irq(npd->irq[0], &nss_ctx->int_ctx[0]);
393err_init_2:
394 unregister_netdev(nss_ctx->int_ctx[0].ndev);
395err_init_1:
396 free_netdev(nss_ctx->int_ctx[0].ndev);
397err_init_0:
398 return err;
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530399}
400
401/*
402 * nss_remove()
403 * HLOS device remove callback
404 */
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530405static int __devexit nss_remove(struct platform_device *nss_dev)
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530406{
407 struct nss_top_instance *nss_top = &nss_top_main;
408 struct nss_ctx_instance *nss_ctx = &nss_top->nss[nss_dev->id];
409
410 /*
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530411 * Clean-up debugfs
412 */
413 nss_stats_clean();
414
415 /*
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530416 * Disable interrupts and bottom halves in HLOS
417 * Disable interrupts from NSS to HLOS
418 */
419 nss_hal_disable_interrupt(nss_ctx->nmap, nss_ctx->int_ctx[0].irq,
420 nss_ctx->int_ctx[0].shift_factor, NSS_HAL_SUPPORTED_INTERRUPTS);
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530421
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530422 free_irq(nss_ctx->int_ctx[0].irq, &nss_ctx->int_ctx[0]);
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530423 unregister_netdev(nss_ctx->int_ctx[0].ndev);
424 free_netdev(nss_ctx->int_ctx[0].ndev);
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530425
426 /*
427 * Check if second interrupt is supported
428 * If so then clear resources for second interrupt as well
429 */
430 if (nss_ctx->int_ctx[1].irq) {
431 nss_hal_disable_interrupt(nss_ctx->nmap, nss_ctx->int_ctx[1].irq,
432 nss_ctx->int_ctx[1].shift_factor, NSS_HAL_SUPPORTED_INTERRUPTS);
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530433 free_irq(nss_ctx->int_ctx[1].irq, &nss_ctx->int_ctx[1]);
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530434 unregister_netdev(nss_ctx->int_ctx[1].ndev);
435 free_netdev(nss_ctx->int_ctx[1].ndev);
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530436 }
437
438 nss_info("%p: All resources freed for nss core%d", nss_ctx, nss_dev->id);
439 return 0;
440}
441
442/*
443 * nss_driver
444 * Platform driver structure for NSS
445 */
446struct platform_driver nss_driver = {
447 .probe = nss_probe,
448 .remove = __devexit_p(nss_remove),
449 .driver = {
450 .name = "qca-nss",
451 .owner = THIS_MODULE,
452 },
453};
454
455/*
wthomas626147f2013-09-18 13:12:40 -0700456 ***************************************************************************************************
Thomas Wufb6a6842013-10-23 13:14:27 -0700457 * nss_wq_function() is used to queue up requests to change NSS frequencies.
458 * The function will take care of NSS notices and also control clock.
459 * The auto rate algorithmn will queue up requests or the procfs may also queue up these requests.
wthomas626147f2013-09-18 13:12:40 -0700460 ***************************************************************************************************
461 */
462
463/*
464 * nss_wq_function()
465 * Added to Handle BH requests to kernel
466 */
467void nss_wq_function (struct work_struct *work)
468{
469 nss_work_t *my_work = (nss_work_t *)work;
470
Thomas Wufb6a6842013-10-23 13:14:27 -0700471 nss_freq_change(nss_freq_change_context, my_work->frequency, 0);
472 clk_set_rate(nss_core0_clk, my_work->frequency);
473 nss_freq_change(nss_freq_change_context, my_work->frequency, 1);
wthomas626147f2013-09-18 13:12:40 -0700474
Pamidipati, Vijay5d27d812013-11-22 16:48:11 +0530475 if(!pm_client) {
476 goto out;
477 }
478
479 if (my_work->frequency == NSS_FREQ_733) {
480 nss_pm_set_perf_level(pm_client, NSS_PM_PERF_LEVEL_TURBO);
481 } else if ((my_work->frequency == NSS_FREQ_275) || (my_work->frequency == NSS_FREQ_550)) {
482 nss_pm_set_perf_level(pm_client, NSS_PM_PERF_LEVEL_NOMINAL);
483 } else {
484 nss_pm_set_perf_level(pm_client, NSS_PM_PERF_LEVEL_IDLE);
485 }
486out:
wthomas626147f2013-09-18 13:12:40 -0700487 kfree((void *)work);
488}
489
490/*
wthomas442c7972013-08-05 14:28:17 -0700491 * nss_current_freq_handler()
492 * Handle Userspace Frequency Change Requests
493 */
494static int nss_current_freq_handler (ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos)
495{
wthomas442c7972013-08-05 14:28:17 -0700496 int ret;
wthomas626147f2013-09-18 13:12:40 -0700497
498 BUG_ON(!nss_wq);
wthomas442c7972013-08-05 14:28:17 -0700499
500 ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
501
wthomasd39fa822013-08-22 16:44:23 -0700502 if (!write) {
wthomas626147f2013-09-18 13:12:40 -0700503 printk("Frequency Set to %d\n", nss_cmd_buf.current_freq);
wthomasd39fa822013-08-22 16:44:23 -0700504 return ret;
wthomas442c7972013-08-05 14:28:17 -0700505 }
wthomasd39fa822013-08-22 16:44:23 -0700506
wthomas626147f2013-09-18 13:12:40 -0700507 /* Turn off Auto Scale */
508 nss_cmd_buf.auto_scale = 0;
509 nss_runtime_samples.freq_scale_ready = 0;
wthomasd39fa822013-08-22 16:44:23 -0700510
Thomas Wu0a0a9c92013-11-21 15:28:19 -0800511 /* If support NSS freq is in the table send the new frequency request to NSS or If No Turbo and ask for turbo freq */
512 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)) || ((nss_runtime_samples.freq_scale_sup_max != NSS_MAX_CPU_SCALES) && (nss_cmd_buf.current_freq == NSS_FREQ_733))) {
Thomas Wufb6a6842013-10-23 13:14:27 -0700513 printk("Frequency not found. Please check Frequency Table\n");
wthomas626147f2013-09-18 13:12:40 -0700514 return ret;
wthomasd39fa822013-08-22 16:44:23 -0700515 }
516
wthomas626147f2013-09-18 13:12:40 -0700517 nss_work = (nss_work_t *)kmalloc(sizeof(nss_work_t), GFP_KERNEL);
518 if (!nss_work) {
519 nss_info("NSS Freq WQ kmalloc fail");
520 return ret;
521 }
522 INIT_WORK((struct work_struct *)nss_work, nss_wq_function);
523 nss_work->frequency = nss_cmd_buf.current_freq;
wthomas626147f2013-09-18 13:12:40 -0700524 queue_work(nss_wq, (struct work_struct *)nss_work);
525
wthomas442c7972013-08-05 14:28:17 -0700526 return ret;
527}
528
529/*
530 * nss_auto_scale_handler()
531 * Enables or Disable Auto Scaling
532 */
533static int nss_auto_scale_handler (ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos)
534{
535 int ret;
536
537 ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
538
wthomas626147f2013-09-18 13:12:40 -0700539 if (!write) {
540 return ret;
541 }
542
Thomas Wufb6a6842013-10-23 13:14:27 -0700543 if (nss_cmd_buf.auto_scale != 1) {
wthomas626147f2013-09-18 13:12:40 -0700544 /*
545 * Auto Scaling is already disabled
546 */
wthomas626147f2013-09-18 13:12:40 -0700547 nss_runtime_samples.freq_scale_ready = 0;
Thomas Wufb6a6842013-10-23 13:14:27 -0700548 return ret;
wthomas626147f2013-09-18 13:12:40 -0700549 }
wthomas442c7972013-08-05 14:28:17 -0700550
Thomas Wufb6a6842013-10-23 13:14:27 -0700551 /*
552 * Auto Scaling is already being done
553 */
554 if (nss_runtime_samples.freq_scale_ready == 1) {
555 return ret;
556 }
557
558 /*
559 * Setup default values - Middle of Freq Scale Band
560 */
561 nss_runtime_samples.freq_scale_index = 1;
562 nss_cmd_buf.current_freq = nss_runtime_samples.freq_scale[nss_runtime_samples.freq_scale_index].frequency;
563
564 nss_work = (nss_work_t *)kmalloc(sizeof(nss_work_t), GFP_KERNEL);
565 if (!nss_work) {
566 nss_info("NSS Freq WQ kmalloc fail");
567 return ret;
568 }
569 INIT_WORK((struct work_struct *)nss_work, nss_wq_function);
570 nss_work->frequency = nss_cmd_buf.current_freq;
571 queue_work(nss_wq, (struct work_struct *)nss_work);
572
573 nss_runtime_samples.freq_scale_ready = 1;
574
wthomas442c7972013-08-05 14:28:17 -0700575 return ret;
576}
577
578/*
579 * nss_get_freq_table_handler()
580 * Display Support Freq and Ex how to Change.
581 */
582static int nss_get_freq_table_handler (ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos)
583{
584 int ret;
585
586 ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
587
Thomas Wu0a0a9c92013-11-21 15:28:19 -0800588 if (nss_runtime_samples.freq_scale_sup_max != NSS_MAX_CPU_SCALES) {
589 printk("Frequency Supported - 110Mhz 275Mhz 550Mhz\n");
590 printk("Ex. To Change Frequency - echo 110000000 > current_freq \n");
591
592 return ret;
593 }
594
wthomas626147f2013-09-18 13:12:40 -0700595 printk("Frequency Supported - 110Mhz 275Mhz 550Mhz 733Mhz \n");
wthomas442c7972013-08-05 14:28:17 -0700596 printk("Ex. To Change Frequency - echo 110000000 > current_freq \n");
597
598 return ret;
599}
600
601/*
Abhishek Rastogi1626a902013-11-21 17:09:49 +0530602 * nss_debug_handler()
603 * Enable NSS debug output
604 */
605static int nss_debug_handler(ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos)
606{
607 int ret;
608
609 ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
610 if (!ret) {
611 if ((write) && (nss_ctl_debug != 0)) {
612 printk("Enabling NSS SPI Debug\n");
613 nss_hal_debug_enable();
614 }
615 }
616
617 return ret;
618}
619
620/*
wthomas442c7972013-08-05 14:28:17 -0700621 * sysctl-tuning infrastructure.
622 */
623static ctl_table nss_freq_table[] = {
624 {
625 .procname = "current_freq",
626 .data = &nss_cmd_buf.current_freq,
627 .maxlen = sizeof(int),
628 .mode = 0644,
629 .proc_handler = &nss_current_freq_handler,
630 },
631 {
632 .procname = "freq_table",
633 .data = &nss_cmd_buf.max_freq,
634 .maxlen = sizeof(int),
635 .mode = 0644,
636 .proc_handler = &nss_get_freq_table_handler,
637 },
638 {
639 .procname = "auto_scale",
640 .data = &nss_cmd_buf.auto_scale,
641 .maxlen = sizeof(int),
642 .mode = 0644,
643 .proc_handler = &nss_auto_scale_handler,
644 },
645 { }
646};
647
Abhishek Rastogi5cd2e4c2013-11-13 18:09:08 +0530648static ctl_table nss_general_table[] = {
649 {
650 .procname = "redirect",
651 .data = &nss_ctl_redirect,
652 .maxlen = sizeof(int),
653 .mode = 0644,
654 .proc_handler = proc_dointvec,
655 },
Abhishek Rastogi1626a902013-11-21 17:09:49 +0530656 {
657 .procname = "debug",
658 .data = &nss_ctl_debug,
659 .maxlen = sizeof(int),
660 .mode = 0644,
661 .proc_handler = &nss_debug_handler,
662 },
Abhishek Rastogi5cd2e4c2013-11-13 18:09:08 +0530663 { }
664};
665
wthomas442c7972013-08-05 14:28:17 -0700666static ctl_table nss_clock_dir[] = {
667 {
Abhishek Rastogi5cd2e4c2013-11-13 18:09:08 +0530668 .procname = "clock",
669 .mode = 0555,
670 .child = nss_freq_table,
671 },
672 {
673 .procname = "general",
674 .mode = 0555,
675 .child = nss_general_table,
wthomas442c7972013-08-05 14:28:17 -0700676 },
677 { }
678};
679
680static ctl_table nss_root_dir[] = {
681 {
682 .procname = "nss",
683 .mode = 0555,
684 .child = nss_clock_dir,
685 },
686 { }
687};
688
689static ctl_table nss_root[] = {
690 {
691 .procname = "dev",
692 .mode = 0555,
693 .child = nss_root_dir,
694 },
695 { }
696};
697
698static struct ctl_table_header *nss_dev_header;
699
700/*
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530701 * nss_init()
702 * Registers nss driver
703 */
704static int __init nss_init(void)
705{
706 nss_info("Init NSS driver");
707
wthomas626147f2013-09-18 13:12:40 -0700708 nss_freq_change_context = nss_get_frequency_mgr();
709
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530710 /*
711 * Perform clock init common to all NSS cores
712 */
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530713 nss_hal_common_reset(&(nss_top_main.clk_src));
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530714
715 /*
716 * Enable spin locks
717 */
718 spin_lock_init(&(nss_top_main.lock));
719 spin_lock_init(&(nss_top_main.stats_lock));
720
721 /*
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530722 * Enable NSS statistics
723 */
724 nss_stats_init();
725
726 /*
727 * Store load addresses
728 */
729 nss_top_main.nss[0].load = (uint32_t)load0;
730 nss_top_main.nss[1].load = (uint32_t)load1;
731
732 /*
wthomas442c7972013-08-05 14:28:17 -0700733 * Register sysctl table.
734 */
735 nss_dev_header = register_sysctl_table(nss_root);
736
737 /*
wthomas626147f2013-09-18 13:12:40 -0700738 * Setup Runtime Sample values
739 */
740 nss_runtime_samples.freq_scale[0].frequency = NSS_FREQ_110;
wthomas626147f2013-09-18 13:12:40 -0700741 nss_runtime_samples.freq_scale[0].minimum = NSS_FREQ_110_MIN;
742 nss_runtime_samples.freq_scale[0].maximum = NSS_FREQ_110_MAX;
wthomas626147f2013-09-18 13:12:40 -0700743 nss_runtime_samples.freq_scale[1].frequency = NSS_FREQ_550;
wthomas626147f2013-09-18 13:12:40 -0700744 nss_runtime_samples.freq_scale[1].minimum = NSS_FREQ_550_MIN;
745 nss_runtime_samples.freq_scale[1].maximum = NSS_FREQ_550_MAX;
wthomas626147f2013-09-18 13:12:40 -0700746 nss_runtime_samples.freq_scale[2].frequency = NSS_FREQ_733;
wthomas626147f2013-09-18 13:12:40 -0700747 nss_runtime_samples.freq_scale[2].minimum = NSS_FREQ_733_MIN;
748 nss_runtime_samples.freq_scale[2].maximum = NSS_FREQ_733_MAX;
wthomas626147f2013-09-18 13:12:40 -0700749 nss_runtime_samples.freq_scale_index = 1;
750 nss_runtime_samples.freq_scale_ready = 0;
Thomas Wu9681f7e2013-11-06 13:12:57 -0800751 nss_runtime_samples.freq_scale_rate_limit_up = 0;
752 nss_runtime_samples.freq_scale_rate_limit_down = 0;
wthomas626147f2013-09-18 13:12:40 -0700753 nss_runtime_samples.buffer_index = 0;
754 nss_runtime_samples.sum = 0;
755 nss_runtime_samples.sample_count = 0;
756 nss_runtime_samples.average = 0;
757 nss_runtime_samples.message_rate_limit = 0;
758
759 /*
760 * Initial Workqueue
761 */
762 nss_wq = create_workqueue("nss_freq_queue");
763
764 /*
Pamidipati, Vijay7f413b52013-09-24 19:07:12 +0530765 * Initialize NSS Bus PM module
766 */
767 nss_pm_init();
768
769 /*
Pamidipati, Vijay5d27d812013-11-22 16:48:11 +0530770 * Register with Bus driver
771 */
772 pm_client = nss_pm_client_register(NSS_PM_CLIENT_NETAP);
773 if (!pm_client) {
774 nss_warning("Error registering with PM driver");
775 }
776
777 /*
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530778 * Register platform_driver
779 */
780 return platform_driver_register(&nss_driver);
781}
782
783/*
784 * nss_cleanup()
785 * Unregisters nss driver
786 */
787static void __exit nss_cleanup(void)
788{
789 nss_info("Exit NSS driver");
wthomas442c7972013-08-05 14:28:17 -0700790
791 if (nss_dev_header)
792 unregister_sysctl_table(nss_dev_header);
793
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530794 platform_driver_unregister(&nss_driver);
795}
796
797module_init(nss_init);
798module_exit(nss_cleanup);
799
800MODULE_DESCRIPTION("QCA NSS Driver");
801MODULE_AUTHOR("Qualcomm Atheros Inc");
802MODULE_LICENSE("Dual BSD/GPL");