blob: c8746eda44a8ec57091ff716d44f2a77538db09e [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/*
39 * Global declarations
40 */
Abhishek Rastogi5cd2e4c2013-11-13 18:09:08 +053041int nss_ctl_redirect __read_mostly = 0;
Abhishek Rastogi1626a902013-11-21 17:09:49 +053042int nss_ctl_debug __read_mostly = 0;
Abhishek Rastogibc74e432013-04-02 10:28:22 +053043
44/*
Pamidipati, Vijay5d27d812013-11-22 16:48:11 +053045 * PM client handle
46 */
47static void *pm_client;
48
49/*
wthomas626147f2013-09-18 13:12:40 -070050 * Handler to send NSS messages
51 */
52void *nss_freq_change_context;
Thomas Wufb6a6842013-10-23 13:14:27 -070053struct clk *nss_core0_clk;
wthomas626147f2013-09-18 13:12:40 -070054
55/*
Abhishek Rastogibc74e432013-04-02 10:28:22 +053056 * Top level nss context structure
57 */
58struct nss_top_instance nss_top_main;
wthomas442c7972013-08-05 14:28:17 -070059struct nss_cmd_buffer nss_cmd_buf;
wthomas626147f2013-09-18 13:12:40 -070060struct nss_runtime_sampling nss_runtime_samples;
61struct workqueue_struct *nss_wq;
62
63/*
64 * Work Queue to handle messages to Kernel
65 */
66nss_work_t *nss_work;
Abhishek Rastogibc74e432013-04-02 10:28:22 +053067
68/*
69 * File local/Static variables/functions
70 */
71
Abhishek Rastogi271eee72013-07-29 21:08:36 +053072static const struct net_device_ops nss_netdev_ops;
73static const struct ethtool_ops nss_ethtool_ops;
74
75/*
76 * nss_dummy_netdev_setup()
77 * Dummy setup for net_device handler
78 */
79static void nss_dummy_netdev_setup(struct net_device *ndev)
80{
wthomas626147f2013-09-18 13:12:40 -070081
Abhishek Rastogi271eee72013-07-29 21:08:36 +053082}
83
Abhishek Rastogibc74e432013-04-02 10:28:22 +053084/*
85 * nss_handle_irq()
86 * HLOS interrupt handler for nss interrupts
87 */
88static irqreturn_t nss_handle_irq (int irq, void *ctx)
89{
90 struct int_ctx_instance *int_ctx = (struct int_ctx_instance *) ctx;
Abhishek Rastogi80f4eb12013-09-24 14:31:21 +053091 struct nss_ctx_instance *nss_ctx = int_ctx->nss_ctx;
Abhishek Rastogibc74e432013-04-02 10:28:22 +053092
93 /*
Abhishek Rastogi80f4eb12013-09-24 14:31:21 +053094 * Mask interrupt until our bottom half re-enables it
Abhishek Rastogibc74e432013-04-02 10:28:22 +053095 */
Abhishek Rastogi80f4eb12013-09-24 14:31:21 +053096 nss_hal_disable_interrupt(nss_ctx->nmap, int_ctx->irq,
97 int_ctx->shift_factor, NSS_HAL_SUPPORTED_INTERRUPTS);
Abhishek Rastogibc74e432013-04-02 10:28:22 +053098
99 /*
100 * Schedule tasklet to process interrupt cause
101 */
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530102 napi_schedule(&int_ctx->napi);
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530103 return IRQ_HANDLED;
104}
105
106/*
107 * nss_probe()
108 * HLOS device probe callback
109 */
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530110static int __devinit nss_probe(struct platform_device *nss_dev)
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530111{
112 struct nss_top_instance *nss_top = &nss_top_main;
113 struct nss_ctx_instance *nss_ctx = &nss_top->nss[nss_dev->id];
114 struct nss_platform_data *npd = (struct nss_platform_data *) nss_dev->dev.platform_data;
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530115 struct netdev_priv_instance *ndev_priv;
116 int i, err = 0;
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530117
118 nss_ctx->nss_top = nss_top;
119 nss_ctx->id = nss_dev->id;
120
wthomas442c7972013-08-05 14:28:17 -0700121 nss_info("%p: NSS_DEV_ID %s \n", nss_ctx, dev_name(&nss_dev->dev));
122
123 /*
124 * Both NSS cores controlled by same regulator, Hook only Once
125 */
126 if (!nss_dev->id) {
Thomas Wufb6a6842013-10-23 13:14:27 -0700127 nss_core0_clk = clk_get(&nss_dev->dev, "nss_core_clk");
128 if (IS_ERR(nss_core0_clk)) {
wthomas442c7972013-08-05 14:28:17 -0700129
Thomas Wufb6a6842013-10-23 13:14:27 -0700130 err = PTR_ERR(nss_core0_clk);
wthomas442c7972013-08-05 14:28:17 -0700131 nss_info("%p: Regulator %s get failed, err=%d\n", nss_ctx, dev_name(&nss_dev->dev), err);
132 return err;
133
wthomas442c7972013-08-05 14:28:17 -0700134 }
Thomas Wufb6a6842013-10-23 13:14:27 -0700135 clk_set_rate(nss_core0_clk, NSS_FREQ_550);
136 clk_prepare(nss_core0_clk);
137 clk_enable(nss_core0_clk);
Thomas Wu0a0a9c92013-11-21 15:28:19 -0800138
139 /*
140 * Check if turbo is supported
141 */
142 if (npd->turbo_frequency) {
143 /*
144 * Turbo is supported
145 */
146 printk("nss_driver - Turbo Support %d\n", npd->turbo_frequency);
147 nss_runtime_samples.freq_scale_sup_max = NSS_MAX_CPU_SCALES;
148 } else {
149 printk("nss_driver - Turbo No Support %d\n", npd->turbo_frequency);
150 nss_runtime_samples.freq_scale_sup_max = NSS_MAX_CPU_SCALES - 1;
151 }
wthomas442c7972013-08-05 14:28:17 -0700152 }
153
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530154 /*
Sakthi Vignesh Radhakrishnand923e342013-12-09 11:53:03 -0800155 * Get load address of NSS firmware
156 */
157 nss_info("%p: Setting NSS%d Firmware load address to %x\n", nss_ctx, nss_dev->id, npd->load_addr);
158 nss_top->nss[nss_dev->id].load = npd->load_addr;
159
160 /*
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530161 * 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
Radhakrishna Jigurub7346cf2013-12-16 13:08:43 +0530358 /*
359 * Initialize max buffer size for NSS core
360 */
361 nss_ctx->max_buf_size = NSS_NBUF_PAYLOAD_SIZE;
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530362 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 +0530363 goto err_init_0;
364
365err_init_5:
366 unregister_netdev(nss_ctx->int_ctx[1].ndev);
367err_init_4:
368 free_netdev(nss_ctx->int_ctx[1].ndev);
369err_init_3:
370 free_irq(npd->irq[0], &nss_ctx->int_ctx[0]);
371err_init_2:
372 unregister_netdev(nss_ctx->int_ctx[0].ndev);
373err_init_1:
374 free_netdev(nss_ctx->int_ctx[0].ndev);
375err_init_0:
376 return err;
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530377}
378
379/*
380 * nss_remove()
381 * HLOS device remove callback
382 */
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530383static int __devexit nss_remove(struct platform_device *nss_dev)
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530384{
385 struct nss_top_instance *nss_top = &nss_top_main;
386 struct nss_ctx_instance *nss_ctx = &nss_top->nss[nss_dev->id];
387
388 /*
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530389 * Clean-up debugfs
390 */
391 nss_stats_clean();
392
393 /*
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530394 * Disable interrupts and bottom halves in HLOS
395 * Disable interrupts from NSS to HLOS
396 */
397 nss_hal_disable_interrupt(nss_ctx->nmap, nss_ctx->int_ctx[0].irq,
398 nss_ctx->int_ctx[0].shift_factor, NSS_HAL_SUPPORTED_INTERRUPTS);
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530399
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530400 free_irq(nss_ctx->int_ctx[0].irq, &nss_ctx->int_ctx[0]);
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530401 unregister_netdev(nss_ctx->int_ctx[0].ndev);
402 free_netdev(nss_ctx->int_ctx[0].ndev);
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530403
404 /*
405 * Check if second interrupt is supported
406 * If so then clear resources for second interrupt as well
407 */
408 if (nss_ctx->int_ctx[1].irq) {
409 nss_hal_disable_interrupt(nss_ctx->nmap, nss_ctx->int_ctx[1].irq,
410 nss_ctx->int_ctx[1].shift_factor, NSS_HAL_SUPPORTED_INTERRUPTS);
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530411 free_irq(nss_ctx->int_ctx[1].irq, &nss_ctx->int_ctx[1]);
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530412 unregister_netdev(nss_ctx->int_ctx[1].ndev);
413 free_netdev(nss_ctx->int_ctx[1].ndev);
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530414 }
415
416 nss_info("%p: All resources freed for nss core%d", nss_ctx, nss_dev->id);
417 return 0;
418}
419
420/*
421 * nss_driver
422 * Platform driver structure for NSS
423 */
424struct platform_driver nss_driver = {
425 .probe = nss_probe,
426 .remove = __devexit_p(nss_remove),
427 .driver = {
428 .name = "qca-nss",
429 .owner = THIS_MODULE,
430 },
431};
432
433/*
wthomas626147f2013-09-18 13:12:40 -0700434 ***************************************************************************************************
Thomas Wufb6a6842013-10-23 13:14:27 -0700435 * nss_wq_function() is used to queue up requests to change NSS frequencies.
436 * The function will take care of NSS notices and also control clock.
437 * The auto rate algorithmn will queue up requests or the procfs may also queue up these requests.
wthomas626147f2013-09-18 13:12:40 -0700438 ***************************************************************************************************
439 */
440
441/*
442 * nss_wq_function()
443 * Added to Handle BH requests to kernel
444 */
445void nss_wq_function (struct work_struct *work)
446{
447 nss_work_t *my_work = (nss_work_t *)work;
448
Thomas Wufb6a6842013-10-23 13:14:27 -0700449 nss_freq_change(nss_freq_change_context, my_work->frequency, 0);
450 clk_set_rate(nss_core0_clk, my_work->frequency);
451 nss_freq_change(nss_freq_change_context, my_work->frequency, 1);
wthomas626147f2013-09-18 13:12:40 -0700452
Pamidipati, Vijay5d27d812013-11-22 16:48:11 +0530453 if(!pm_client) {
454 goto out;
455 }
456
457 if (my_work->frequency == NSS_FREQ_733) {
458 nss_pm_set_perf_level(pm_client, NSS_PM_PERF_LEVEL_TURBO);
459 } else if ((my_work->frequency == NSS_FREQ_275) || (my_work->frequency == NSS_FREQ_550)) {
460 nss_pm_set_perf_level(pm_client, NSS_PM_PERF_LEVEL_NOMINAL);
461 } else {
462 nss_pm_set_perf_level(pm_client, NSS_PM_PERF_LEVEL_IDLE);
463 }
464out:
wthomas626147f2013-09-18 13:12:40 -0700465 kfree((void *)work);
466}
467
468/*
wthomas442c7972013-08-05 14:28:17 -0700469 * nss_current_freq_handler()
470 * Handle Userspace Frequency Change Requests
471 */
472static int nss_current_freq_handler (ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos)
473{
wthomas442c7972013-08-05 14:28:17 -0700474 int ret;
wthomas626147f2013-09-18 13:12:40 -0700475
476 BUG_ON(!nss_wq);
wthomas442c7972013-08-05 14:28:17 -0700477
478 ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
479
wthomasd39fa822013-08-22 16:44:23 -0700480 if (!write) {
wthomas626147f2013-09-18 13:12:40 -0700481 printk("Frequency Set to %d\n", nss_cmd_buf.current_freq);
wthomasd39fa822013-08-22 16:44:23 -0700482 return ret;
wthomas442c7972013-08-05 14:28:17 -0700483 }
wthomasd39fa822013-08-22 16:44:23 -0700484
wthomas626147f2013-09-18 13:12:40 -0700485 /* Turn off Auto Scale */
486 nss_cmd_buf.auto_scale = 0;
487 nss_runtime_samples.freq_scale_ready = 0;
wthomasd39fa822013-08-22 16:44:23 -0700488
Thomas Wu0a0a9c92013-11-21 15:28:19 -0800489 /* If support NSS freq is in the table send the new frequency request to NSS or If No Turbo and ask for turbo freq */
490 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 -0700491 printk("Frequency not found. Please check Frequency Table\n");
wthomas626147f2013-09-18 13:12:40 -0700492 return ret;
wthomasd39fa822013-08-22 16:44:23 -0700493 }
494
wthomas626147f2013-09-18 13:12:40 -0700495 nss_work = (nss_work_t *)kmalloc(sizeof(nss_work_t), GFP_KERNEL);
496 if (!nss_work) {
497 nss_info("NSS Freq WQ kmalloc fail");
498 return ret;
499 }
500 INIT_WORK((struct work_struct *)nss_work, nss_wq_function);
501 nss_work->frequency = nss_cmd_buf.current_freq;
wthomas626147f2013-09-18 13:12:40 -0700502 queue_work(nss_wq, (struct work_struct *)nss_work);
503
wthomas442c7972013-08-05 14:28:17 -0700504 return ret;
505}
506
507/*
508 * nss_auto_scale_handler()
509 * Enables or Disable Auto Scaling
510 */
511static int nss_auto_scale_handler (ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos)
512{
513 int ret;
514
515 ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
516
wthomas626147f2013-09-18 13:12:40 -0700517 if (!write) {
518 return ret;
519 }
520
Thomas Wufb6a6842013-10-23 13:14:27 -0700521 if (nss_cmd_buf.auto_scale != 1) {
wthomas626147f2013-09-18 13:12:40 -0700522 /*
523 * Auto Scaling is already disabled
524 */
wthomas626147f2013-09-18 13:12:40 -0700525 nss_runtime_samples.freq_scale_ready = 0;
Thomas Wufb6a6842013-10-23 13:14:27 -0700526 return ret;
wthomas626147f2013-09-18 13:12:40 -0700527 }
wthomas442c7972013-08-05 14:28:17 -0700528
Thomas Wufb6a6842013-10-23 13:14:27 -0700529 /*
530 * Auto Scaling is already being done
531 */
532 if (nss_runtime_samples.freq_scale_ready == 1) {
533 return ret;
534 }
535
536 /*
537 * Setup default values - Middle of Freq Scale Band
538 */
539 nss_runtime_samples.freq_scale_index = 1;
540 nss_cmd_buf.current_freq = nss_runtime_samples.freq_scale[nss_runtime_samples.freq_scale_index].frequency;
541
542 nss_work = (nss_work_t *)kmalloc(sizeof(nss_work_t), GFP_KERNEL);
543 if (!nss_work) {
544 nss_info("NSS Freq WQ kmalloc fail");
545 return ret;
546 }
547 INIT_WORK((struct work_struct *)nss_work, nss_wq_function);
548 nss_work->frequency = nss_cmd_buf.current_freq;
549 queue_work(nss_wq, (struct work_struct *)nss_work);
550
551 nss_runtime_samples.freq_scale_ready = 1;
552
wthomas442c7972013-08-05 14:28:17 -0700553 return ret;
554}
555
556/*
557 * nss_get_freq_table_handler()
558 * Display Support Freq and Ex how to Change.
559 */
Thomas Wu05495be2013-12-19 14:24:24 -0800560static int nss_get_freq_table_handler(ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos)
wthomas442c7972013-08-05 14:28:17 -0700561{
562 int ret;
563
564 ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
565
Thomas Wu0a0a9c92013-11-21 15:28:19 -0800566 if (nss_runtime_samples.freq_scale_sup_max != NSS_MAX_CPU_SCALES) {
567 printk("Frequency Supported - 110Mhz 275Mhz 550Mhz\n");
568 printk("Ex. To Change Frequency - echo 110000000 > current_freq \n");
569
570 return ret;
571 }
572
wthomas626147f2013-09-18 13:12:40 -0700573 printk("Frequency Supported - 110Mhz 275Mhz 550Mhz 733Mhz \n");
wthomas442c7972013-08-05 14:28:17 -0700574 printk("Ex. To Change Frequency - echo 110000000 > current_freq \n");
575
576 return ret;
577}
578
579/*
Thomas Wu05495be2013-12-19 14:24:24 -0800580 * nss_get_average_inst_handler()
581 * Display AVG Inst Per Ms.
582 */
583static int nss_get_average_inst_handler(ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos)
584{
585 int ret;
586
587 ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
588
589 if (!ret && !write) {
590 printk("Current Inst Per Ms %x\n", nss_runtime_samples.average);
591 }
592
593 return ret;
594}
595
596/*
Abhishek Rastogi1626a902013-11-21 17:09:49 +0530597 * nss_debug_handler()
598 * Enable NSS debug output
599 */
600static int nss_debug_handler(ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos)
601{
602 int ret;
603
604 ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
605 if (!ret) {
606 if ((write) && (nss_ctl_debug != 0)) {
607 printk("Enabling NSS SPI Debug\n");
608 nss_hal_debug_enable();
609 }
610 }
611
612 return ret;
613}
614
615/*
wthomas442c7972013-08-05 14:28:17 -0700616 * sysctl-tuning infrastructure.
617 */
618static ctl_table nss_freq_table[] = {
619 {
620 .procname = "current_freq",
621 .data = &nss_cmd_buf.current_freq,
622 .maxlen = sizeof(int),
623 .mode = 0644,
624 .proc_handler = &nss_current_freq_handler,
625 },
626 {
627 .procname = "freq_table",
628 .data = &nss_cmd_buf.max_freq,
629 .maxlen = sizeof(int),
630 .mode = 0644,
631 .proc_handler = &nss_get_freq_table_handler,
632 },
633 {
634 .procname = "auto_scale",
635 .data = &nss_cmd_buf.auto_scale,
636 .maxlen = sizeof(int),
637 .mode = 0644,
638 .proc_handler = &nss_auto_scale_handler,
639 },
Thomas Wu05495be2013-12-19 14:24:24 -0800640 {
641 .procname = "inst_per_sec",
642 .data = &nss_cmd_buf.average_inst,
643 .maxlen = sizeof(int),
644 .mode = 0644,
645 .proc_handler = &nss_get_average_inst_handler,
646 },
wthomas442c7972013-08-05 14:28:17 -0700647 { }
648};
649
Abhishek Rastogi5cd2e4c2013-11-13 18:09:08 +0530650static ctl_table nss_general_table[] = {
651 {
652 .procname = "redirect",
653 .data = &nss_ctl_redirect,
654 .maxlen = sizeof(int),
655 .mode = 0644,
656 .proc_handler = proc_dointvec,
657 },
Abhishek Rastogi1626a902013-11-21 17:09:49 +0530658 {
659 .procname = "debug",
660 .data = &nss_ctl_debug,
661 .maxlen = sizeof(int),
662 .mode = 0644,
663 .proc_handler = &nss_debug_handler,
664 },
Abhishek Rastogi5cd2e4c2013-11-13 18:09:08 +0530665 { }
666};
667
wthomas442c7972013-08-05 14:28:17 -0700668static ctl_table nss_clock_dir[] = {
669 {
Abhishek Rastogi5cd2e4c2013-11-13 18:09:08 +0530670 .procname = "clock",
671 .mode = 0555,
672 .child = nss_freq_table,
673 },
674 {
675 .procname = "general",
676 .mode = 0555,
677 .child = nss_general_table,
wthomas442c7972013-08-05 14:28:17 -0700678 },
679 { }
680};
681
682static ctl_table nss_root_dir[] = {
683 {
684 .procname = "nss",
685 .mode = 0555,
686 .child = nss_clock_dir,
687 },
688 { }
689};
690
691static ctl_table nss_root[] = {
692 {
693 .procname = "dev",
694 .mode = 0555,
695 .child = nss_root_dir,
696 },
697 { }
698};
699
700static struct ctl_table_header *nss_dev_header;
701
702/*
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530703 * nss_init()
704 * Registers nss driver
705 */
706static int __init nss_init(void)
707{
708 nss_info("Init NSS driver");
709
wthomas626147f2013-09-18 13:12:40 -0700710 nss_freq_change_context = nss_get_frequency_mgr();
711
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530712 /*
713 * Perform clock init common to all NSS cores
714 */
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530715 nss_hal_common_reset(&(nss_top_main.clk_src));
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530716
717 /*
718 * Enable spin locks
719 */
720 spin_lock_init(&(nss_top_main.lock));
721 spin_lock_init(&(nss_top_main.stats_lock));
722
723 /*
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530724 * Enable NSS statistics
725 */
726 nss_stats_init();
727
728 /*
wthomas442c7972013-08-05 14:28:17 -0700729 * Register sysctl table.
730 */
731 nss_dev_header = register_sysctl_table(nss_root);
732
733 /*
wthomas626147f2013-09-18 13:12:40 -0700734 * Setup Runtime Sample values
735 */
736 nss_runtime_samples.freq_scale[0].frequency = NSS_FREQ_110;
wthomas626147f2013-09-18 13:12:40 -0700737 nss_runtime_samples.freq_scale[0].minimum = NSS_FREQ_110_MIN;
738 nss_runtime_samples.freq_scale[0].maximum = NSS_FREQ_110_MAX;
wthomas626147f2013-09-18 13:12:40 -0700739 nss_runtime_samples.freq_scale[1].frequency = NSS_FREQ_550;
wthomas626147f2013-09-18 13:12:40 -0700740 nss_runtime_samples.freq_scale[1].minimum = NSS_FREQ_550_MIN;
741 nss_runtime_samples.freq_scale[1].maximum = NSS_FREQ_550_MAX;
wthomas626147f2013-09-18 13:12:40 -0700742 nss_runtime_samples.freq_scale[2].frequency = NSS_FREQ_733;
wthomas626147f2013-09-18 13:12:40 -0700743 nss_runtime_samples.freq_scale[2].minimum = NSS_FREQ_733_MIN;
744 nss_runtime_samples.freq_scale[2].maximum = NSS_FREQ_733_MAX;
wthomas626147f2013-09-18 13:12:40 -0700745 nss_runtime_samples.freq_scale_index = 1;
746 nss_runtime_samples.freq_scale_ready = 0;
Thomas Wu9681f7e2013-11-06 13:12:57 -0800747 nss_runtime_samples.freq_scale_rate_limit_up = 0;
748 nss_runtime_samples.freq_scale_rate_limit_down = 0;
wthomas626147f2013-09-18 13:12:40 -0700749 nss_runtime_samples.buffer_index = 0;
750 nss_runtime_samples.sum = 0;
751 nss_runtime_samples.sample_count = 0;
752 nss_runtime_samples.average = 0;
753 nss_runtime_samples.message_rate_limit = 0;
754
Thomas Wu05495be2013-12-19 14:24:24 -0800755 nss_cmd_buf.current_freq = nss_runtime_samples.freq_scale[nss_runtime_samples.freq_scale_index].frequency;
756
wthomas626147f2013-09-18 13:12:40 -0700757 /*
758 * Initial Workqueue
759 */
760 nss_wq = create_workqueue("nss_freq_queue");
761
762 /*
Pamidipati, Vijay7f413b52013-09-24 19:07:12 +0530763 * Initialize NSS Bus PM module
764 */
765 nss_pm_init();
766
767 /*
Pamidipati, Vijay5d27d812013-11-22 16:48:11 +0530768 * Register with Bus driver
769 */
770 pm_client = nss_pm_client_register(NSS_PM_CLIENT_NETAP);
771 if (!pm_client) {
772 nss_warning("Error registering with PM driver");
773 }
774
775 /*
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530776 * Register platform_driver
777 */
778 return platform_driver_register(&nss_driver);
779}
780
781/*
782 * nss_cleanup()
783 * Unregisters nss driver
784 */
785static void __exit nss_cleanup(void)
786{
787 nss_info("Exit NSS driver");
wthomas442c7972013-08-05 14:28:17 -0700788
789 if (nss_dev_header)
790 unregister_sysctl_table(nss_dev_header);
791
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530792 platform_driver_unregister(&nss_driver);
793}
794
795module_init(nss_init);
796module_exit(nss_cleanup);
797
798MODULE_DESCRIPTION("QCA NSS Driver");
799MODULE_AUTHOR("Qualcomm Atheros Inc");
800MODULE_LICENSE("Dual BSD/GPL");