blob: e5695fc55e0fc0bac52d9c75a4c7bbc53b32439a [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;
Pamidipati, Vijayf9b5a272014-01-22 14:24:10 +0530148 nss_pm_set_turbo();
Thomas Wu0a0a9c92013-11-21 15:28:19 -0800149 } else {
150 printk("nss_driver - Turbo No Support %d\n", npd->turbo_frequency);
151 nss_runtime_samples.freq_scale_sup_max = NSS_MAX_CPU_SCALES - 1;
152 }
wthomas442c7972013-08-05 14:28:17 -0700153 }
154
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530155 /*
Sakthi Vignesh Radhakrishnand923e342013-12-09 11:53:03 -0800156 * Get load address of NSS firmware
157 */
158 nss_info("%p: Setting NSS%d Firmware load address to %x\n", nss_ctx, nss_dev->id, npd->load_addr);
159 nss_top->nss[nss_dev->id].load = npd->load_addr;
160
161 /*
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530162 * Get virtual and physical memory addresses for nss logical/hardware address maps
163 */
164
165 /*
166 * Virtual address of CSM space
167 */
168 nss_ctx->nmap = npd->nmap;
169 nss_assert(nss_ctx->nmap);
170
171 /*
172 * Physical address of CSM space
173 */
174 nss_ctx->nphys = npd->nphys;
175 nss_assert(nss_ctx->nphys);
176
177 /*
178 * Virtual address of logical registers space
179 */
180 nss_ctx->vmap = npd->vmap;
181 nss_assert(nss_ctx->vmap);
182
183 /*
184 * Physical address of logical registers space
185 */
186 nss_ctx->vphys = npd->vphys;
187 nss_assert(nss_ctx->vphys);
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530188 nss_info("%d:ctx=%p, vphys=%x, vmap=%x, nphys=%x, nmap=%x",
189 nss_dev->id, nss_ctx, nss_ctx->vphys, nss_ctx->vmap, nss_ctx->nphys, nss_ctx->nmap);
190
191 /*
192 * Register netdevice handlers
193 */
194 nss_ctx->int_ctx[0].ndev = alloc_netdev(sizeof(struct netdev_priv_instance),
195 "qca-nss-dev%d", nss_dummy_netdev_setup);
196 if (nss_ctx->int_ctx[0].ndev == NULL) {
197 nss_warning("%p: Could not allocate net_device #0", nss_ctx);
198 err = -ENOMEM;
199 goto err_init_0;
200 }
201
202 nss_ctx->int_ctx[0].ndev->netdev_ops = &nss_netdev_ops;
203 nss_ctx->int_ctx[0].ndev->ethtool_ops = &nss_ethtool_ops;
204 err = register_netdev(nss_ctx->int_ctx[0].ndev);
205 if (err) {
206 nss_warning("%p: Could not register net_device #0", nss_ctx);
207 goto err_init_1;
208 }
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530209
210 /*
211 * request for IRQs
212 *
213 * WARNING: CPU affinities should be set using OS supported methods
214 */
215 nss_ctx->int_ctx[0].nss_ctx = nss_ctx;
216 nss_ctx->int_ctx[0].shift_factor = 0;
217 nss_ctx->int_ctx[0].irq = npd->irq[0];
218 err = request_irq(npd->irq[0], nss_handle_irq, IRQF_DISABLED, "nss", &nss_ctx->int_ctx[0]);
219 if (err) {
220 nss_warning("%d: IRQ0 request failed", nss_dev->id);
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530221 goto err_init_2;
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530222 }
223
224 /*
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530225 * Register NAPI for NSS core interrupt #0
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530226 */
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530227 ndev_priv = netdev_priv(nss_ctx->int_ctx[0].ndev);
228 ndev_priv->int_ctx = &nss_ctx->int_ctx[0];
229 netif_napi_add(nss_ctx->int_ctx[0].ndev, &nss_ctx->int_ctx[0].napi, nss_core_handle_napi, 64);
230 napi_enable(&nss_ctx->int_ctx[0].napi);
231 nss_ctx->int_ctx[0].napi_active = true;
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530232
233 /*
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530234 * Check if second interrupt is supported on this nss core
235 */
236 if (npd->num_irq > 1) {
237 nss_info("%d: This NSS core supports two interrupts", nss_dev->id);
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530238
239 /*
240 * Register netdevice handlers
241 */
242 nss_ctx->int_ctx[1].ndev = alloc_netdev(sizeof(struct netdev_priv_instance),
243 "qca-nss-dev%d", nss_dummy_netdev_setup);
244 if (nss_ctx->int_ctx[1].ndev == NULL) {
245 nss_warning("%p: Could not allocate net_device #1", nss_ctx);
246 err = -ENOMEM;
247 goto err_init_3;
248 }
249
250 nss_ctx->int_ctx[1].ndev->netdev_ops = &nss_netdev_ops;
251 nss_ctx->int_ctx[1].ndev->ethtool_ops = &nss_ethtool_ops;
252 err = register_netdev(nss_ctx->int_ctx[1].ndev);
253 if (err) {
254 nss_warning("%p: Could not register net_device #1", nss_ctx);
255 goto err_init_4;
256 }
257
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530258 nss_ctx->int_ctx[1].nss_ctx = nss_ctx;
259 nss_ctx->int_ctx[1].shift_factor = 15;
260 nss_ctx->int_ctx[1].irq = npd->irq[1];
261 err = request_irq(npd->irq[1], nss_handle_irq, IRQF_DISABLED, "nss", &nss_ctx->int_ctx[1]);
262 if (err) {
263 nss_warning("%d: IRQ1 request failed for nss", nss_dev->id);
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530264 goto err_init_5;
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530265 }
266
267 /*
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530268 * Register NAPI for NSS core interrupt #1
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530269 */
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530270 ndev_priv = netdev_priv(nss_ctx->int_ctx[1].ndev);
271 ndev_priv->int_ctx = &nss_ctx->int_ctx[1];
272 netif_napi_add(nss_ctx->int_ctx[1].ndev, &nss_ctx->int_ctx[1].napi, nss_core_handle_napi, 64);
273 napi_enable(&nss_ctx->int_ctx[1].napi);
274 nss_ctx->int_ctx[1].napi_active = true;
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530275 }
276
277 spin_lock_bh(&(nss_top->lock));
278
279 /*
280 * Check functionalities are supported by this NSS core
281 */
Murat Sezgin7a705422014-01-30 16:09:22 -0800282 if (npd->shaping_enabled == NSS_FEATURE_ENABLED) {
283 nss_top->shaping_handler_id = nss_dev->id;
284 printk(KERN_INFO "%p: NSS Shaping is enabled, handler id: %u", __func__, nss_top->shaping_handler_id);
285 }
286
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530287 if (npd->ipv4_enabled == NSS_FEATURE_ENABLED) {
288 nss_top->ipv4_handler_id = nss_dev->id;
289 }
290
291 if (npd->ipv6_enabled == NSS_FEATURE_ENABLED) {
292 nss_top->ipv6_handler_id = nss_dev->id;
293 }
294
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530295 if (npd->crypto_enabled == NSS_FEATURE_ENABLED) {
296 nss_top->crypto_handler_id = nss_dev->id;
297 }
298
299 if (npd->ipsec_enabled == NSS_FEATURE_ENABLED) {
300 nss_top->ipsec_handler_id = nss_dev->id;
301 }
302
303 if (npd->wlan_enabled == NSS_FEATURE_ENABLED) {
304 nss_top->wlan_handler_id = nss_dev->id;
305 }
306
Bharath M Kumar0d87e912013-08-12 18:32:57 +0530307 if (npd->tun6rd_enabled == NSS_FEATURE_ENABLED) {
308 nss_top->tun6rd_handler_id = nss_dev->id;
309 }
310
Bharath M Kumar614bbf82013-08-31 20:18:44 +0530311 if (npd->tunipip6_enabled == NSS_FEATURE_ENABLED) {
312 nss_top->tunipip6_handler_id = nss_dev->id;
313 }
314
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530315 if (npd->gmac_enabled[0] == NSS_FEATURE_ENABLED) {
316 nss_top->phys_if_handler_id[0] = nss_dev->id;
317 }
318
319 if (npd->gmac_enabled[1] == NSS_FEATURE_ENABLED) {
320 nss_top->phys_if_handler_id[1] = nss_dev->id;
321 }
322
323 if (npd->gmac_enabled[2] == NSS_FEATURE_ENABLED) {
324 nss_top->phys_if_handler_id[2] = nss_dev->id;
325 }
326
327 if (npd->gmac_enabled[3] == NSS_FEATURE_ENABLED) {
328 nss_top->phys_if_handler_id[3] = nss_dev->id;
329 }
330
wthomas626147f2013-09-18 13:12:40 -0700331 nss_top->frequency_handler_id = nss_dev->id;
332
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530333 spin_unlock_bh(&(nss_top->lock));
334
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530335 /*
336 * Initialize decongestion callbacks to NULL
337 */
338 for (i = 0; i< NSS_MAX_CLIENTS; i++) {
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530339 nss_ctx->queue_decongestion_callback[i] = 0;
340 nss_ctx->queue_decongestion_ctx[i] = 0;
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530341 }
342
343 spin_lock_init(&(nss_ctx->decongest_cb_lock));
344 nss_ctx->magic = NSS_CTX_MAGIC;
345
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530346 nss_info("%p: Reseting NSS core %d now", nss_ctx, nss_ctx->id);
347
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530348 /*
349 * Enable clocks and bring NSS core out of reset
350 */
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530351 nss_hal_core_reset(nss_dev->id, nss_ctx->nmap, nss_ctx->load, nss_top->clk_src);
352
353 /*
354 * Enable interrupts for NSS core
355 */
356 nss_hal_enable_interrupt(nss_ctx->nmap, nss_ctx->int_ctx[0].irq,
357 nss_ctx->int_ctx[0].shift_factor, NSS_HAL_SUPPORTED_INTERRUPTS);
358
359 if (npd->num_irq > 1) {
360 nss_hal_enable_interrupt(nss_ctx->nmap, nss_ctx->int_ctx[1].irq,
361 nss_ctx->int_ctx[1].shift_factor, NSS_HAL_SUPPORTED_INTERRUPTS);
362 }
363
Radhakrishna Jigurub7346cf2013-12-16 13:08:43 +0530364 /*
365 * Initialize max buffer size for NSS core
366 */
367 nss_ctx->max_buf_size = NSS_NBUF_PAYLOAD_SIZE;
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530368 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 +0530369 goto err_init_0;
370
371err_init_5:
372 unregister_netdev(nss_ctx->int_ctx[1].ndev);
373err_init_4:
374 free_netdev(nss_ctx->int_ctx[1].ndev);
375err_init_3:
376 free_irq(npd->irq[0], &nss_ctx->int_ctx[0]);
377err_init_2:
378 unregister_netdev(nss_ctx->int_ctx[0].ndev);
379err_init_1:
380 free_netdev(nss_ctx->int_ctx[0].ndev);
381err_init_0:
382 return err;
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530383}
384
385/*
386 * nss_remove()
387 * HLOS device remove callback
388 */
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530389static int __devexit nss_remove(struct platform_device *nss_dev)
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530390{
391 struct nss_top_instance *nss_top = &nss_top_main;
392 struct nss_ctx_instance *nss_ctx = &nss_top->nss[nss_dev->id];
393
394 /*
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530395 * Clean-up debugfs
396 */
397 nss_stats_clean();
398
399 /*
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530400 * Disable interrupts and bottom halves in HLOS
401 * Disable interrupts from NSS to HLOS
402 */
403 nss_hal_disable_interrupt(nss_ctx->nmap, nss_ctx->int_ctx[0].irq,
404 nss_ctx->int_ctx[0].shift_factor, NSS_HAL_SUPPORTED_INTERRUPTS);
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530405
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530406 free_irq(nss_ctx->int_ctx[0].irq, &nss_ctx->int_ctx[0]);
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530407 unregister_netdev(nss_ctx->int_ctx[0].ndev);
408 free_netdev(nss_ctx->int_ctx[0].ndev);
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530409
410 /*
411 * Check if second interrupt is supported
412 * If so then clear resources for second interrupt as well
413 */
414 if (nss_ctx->int_ctx[1].irq) {
415 nss_hal_disable_interrupt(nss_ctx->nmap, nss_ctx->int_ctx[1].irq,
416 nss_ctx->int_ctx[1].shift_factor, NSS_HAL_SUPPORTED_INTERRUPTS);
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530417 free_irq(nss_ctx->int_ctx[1].irq, &nss_ctx->int_ctx[1]);
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530418 unregister_netdev(nss_ctx->int_ctx[1].ndev);
419 free_netdev(nss_ctx->int_ctx[1].ndev);
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530420 }
421
422 nss_info("%p: All resources freed for nss core%d", nss_ctx, nss_dev->id);
423 return 0;
424}
425
426/*
427 * nss_driver
428 * Platform driver structure for NSS
429 */
430struct platform_driver nss_driver = {
431 .probe = nss_probe,
432 .remove = __devexit_p(nss_remove),
433 .driver = {
434 .name = "qca-nss",
435 .owner = THIS_MODULE,
436 },
437};
438
439/*
Kiran Kumar C.S.K69fd5992014-01-06 20:58:14 +0530440 * nss_reset_frequency_stats_samples()
441 * Reset all frequency sampling state when auto scaling is turned off.
442 */
443static void nss_reset_frequency_stats_samples (void)
444{
445 nss_runtime_samples.buffer_index = 0;
446 nss_runtime_samples.sum = 0;
447 nss_runtime_samples.average = 0;
448 nss_runtime_samples.sample_count = 0;
449 nss_runtime_samples.message_rate_limit = 0;
450 nss_runtime_samples.freq_scale_rate_limit_up = 0;
451 nss_runtime_samples.freq_scale_rate_limit_down = 0;
452}
453
454/*
wthomas626147f2013-09-18 13:12:40 -0700455 ***************************************************************************************************
Thomas Wufb6a6842013-10-23 13:14:27 -0700456 * nss_wq_function() is used to queue up requests to change NSS frequencies.
457 * The function will take care of NSS notices and also control clock.
458 * The auto rate algorithmn will queue up requests or the procfs may also queue up these requests.
wthomas626147f2013-09-18 13:12:40 -0700459 ***************************************************************************************************
460 */
461
462/*
463 * nss_wq_function()
464 * Added to Handle BH requests to kernel
465 */
466void nss_wq_function (struct work_struct *work)
467{
468 nss_work_t *my_work = (nss_work_t *)work;
469
Kiran Kumar C.S.K69fd5992014-01-06 20:58:14 +0530470 nss_freq_change(nss_freq_change_context, my_work->frequency, my_work->stats_enable, 0);
Thomas Wufb6a6842013-10-23 13:14:27 -0700471 clk_set_rate(nss_core0_clk, my_work->frequency);
Kiran Kumar C.S.K69fd5992014-01-06 20:58:14 +0530472 nss_freq_change(nss_freq_change_context, my_work->frequency, my_work->stats_enable, 1);
wthomas626147f2013-09-18 13:12:40 -0700473
Pamidipati, Vijay5d27d812013-11-22 16:48:11 +0530474 if(!pm_client) {
475 goto out;
476 }
477
478 if (my_work->frequency == NSS_FREQ_733) {
479 nss_pm_set_perf_level(pm_client, NSS_PM_PERF_LEVEL_TURBO);
480 } else if ((my_work->frequency == NSS_FREQ_275) || (my_work->frequency == NSS_FREQ_550)) {
481 nss_pm_set_perf_level(pm_client, NSS_PM_PERF_LEVEL_NOMINAL);
482 } else {
483 nss_pm_set_perf_level(pm_client, NSS_PM_PERF_LEVEL_IDLE);
484 }
485out:
wthomas626147f2013-09-18 13:12:40 -0700486 kfree((void *)work);
487}
488
489/*
wthomas442c7972013-08-05 14:28:17 -0700490 * nss_current_freq_handler()
491 * Handle Userspace Frequency Change Requests
492 */
493static int nss_current_freq_handler (ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos)
494{
wthomas442c7972013-08-05 14:28:17 -0700495 int ret;
wthomas626147f2013-09-18 13:12:40 -0700496
497 BUG_ON(!nss_wq);
wthomas442c7972013-08-05 14:28:17 -0700498
499 ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
500
wthomasd39fa822013-08-22 16:44:23 -0700501 if (!write) {
wthomas626147f2013-09-18 13:12:40 -0700502 printk("Frequency Set to %d\n", nss_cmd_buf.current_freq);
wthomasd39fa822013-08-22 16:44:23 -0700503 return ret;
wthomas442c7972013-08-05 14:28:17 -0700504 }
wthomasd39fa822013-08-22 16:44:23 -0700505
wthomas626147f2013-09-18 13:12:40 -0700506 /* Turn off Auto Scale */
507 nss_cmd_buf.auto_scale = 0;
508 nss_runtime_samples.freq_scale_ready = 0;
wthomasd39fa822013-08-22 16:44:23 -0700509
Thomas Wu0a0a9c92013-11-21 15:28:19 -0800510 /* If support NSS freq is in the table send the new frequency request to NSS or If No Turbo and ask for turbo freq */
511 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 -0700512 printk("Frequency not found. Please check Frequency Table\n");
wthomas626147f2013-09-18 13:12:40 -0700513 return ret;
wthomasd39fa822013-08-22 16:44:23 -0700514 }
515
wthomas626147f2013-09-18 13:12:40 -0700516 nss_work = (nss_work_t *)kmalloc(sizeof(nss_work_t), GFP_KERNEL);
517 if (!nss_work) {
518 nss_info("NSS Freq WQ kmalloc fail");
519 return ret;
520 }
521 INIT_WORK((struct work_struct *)nss_work, nss_wq_function);
522 nss_work->frequency = nss_cmd_buf.current_freq;
Kiran Kumar C.S.K69fd5992014-01-06 20:58:14 +0530523 nss_work->stats_enable = 0;
524
525 /* Ensure we start with a fresh set of samples later */
526 nss_reset_frequency_stats_samples();
527
wthomas626147f2013-09-18 13:12:40 -0700528 queue_work(nss_wq, (struct work_struct *)nss_work);
529
wthomas442c7972013-08-05 14:28:17 -0700530 return ret;
531}
532
533/*
534 * nss_auto_scale_handler()
535 * Enables or Disable Auto Scaling
536 */
537static int nss_auto_scale_handler (ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos)
538{
539 int ret;
540
541 ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
542
wthomas626147f2013-09-18 13:12:40 -0700543 if (!write) {
544 return ret;
545 }
546
Thomas Wufb6a6842013-10-23 13:14:27 -0700547 if (nss_cmd_buf.auto_scale != 1) {
wthomas626147f2013-09-18 13:12:40 -0700548 /*
Kiran Kumar C.S.K69fd5992014-01-06 20:58:14 +0530549 * Is auto scaling currently enabled? If so, send the command to
550 * disable stats reporting to NSS
wthomas626147f2013-09-18 13:12:40 -0700551 */
Kiran Kumar C.S.K69fd5992014-01-06 20:58:14 +0530552 if (nss_runtime_samples.freq_scale_ready != 0) {
553 nss_cmd_buf.current_freq = nss_runtime_samples.freq_scale[nss_runtime_samples.freq_scale_index].frequency;
554 nss_work = (nss_work_t *)kmalloc(sizeof(nss_work_t), GFP_KERNEL);
555 if (!nss_work) {
556 nss_info("NSS Freq WQ kmalloc fail");
557 return ret;
558 }
559 INIT_WORK((struct work_struct *)nss_work, nss_wq_function);
560 nss_work->frequency = nss_cmd_buf.current_freq;
561 nss_work->stats_enable = 0;
562 queue_work(nss_wq, (struct work_struct *)nss_work);
563 nss_runtime_samples.freq_scale_ready = 0;
564
565 /*
566 * The current samples would be stale later when scaling is
567 * enabled again, hence reset them
568 */
569 nss_reset_frequency_stats_samples();
570 }
Thomas Wufb6a6842013-10-23 13:14:27 -0700571 return ret;
wthomas626147f2013-09-18 13:12:40 -0700572 }
wthomas442c7972013-08-05 14:28:17 -0700573
Thomas Wufb6a6842013-10-23 13:14:27 -0700574 /*
575 * Auto Scaling is already being done
576 */
577 if (nss_runtime_samples.freq_scale_ready == 1) {
578 return ret;
579 }
580
581 /*
582 * Setup default values - Middle of Freq Scale Band
583 */
584 nss_runtime_samples.freq_scale_index = 1;
585 nss_cmd_buf.current_freq = nss_runtime_samples.freq_scale[nss_runtime_samples.freq_scale_index].frequency;
586
587 nss_work = (nss_work_t *)kmalloc(sizeof(nss_work_t), GFP_KERNEL);
588 if (!nss_work) {
589 nss_info("NSS Freq WQ kmalloc fail");
590 return ret;
591 }
592 INIT_WORK((struct work_struct *)nss_work, nss_wq_function);
593 nss_work->frequency = nss_cmd_buf.current_freq;
Kiran Kumar C.S.K69fd5992014-01-06 20:58:14 +0530594 nss_work->stats_enable = 1;
Thomas Wufb6a6842013-10-23 13:14:27 -0700595 queue_work(nss_wq, (struct work_struct *)nss_work);
596
597 nss_runtime_samples.freq_scale_ready = 1;
598
wthomas442c7972013-08-05 14:28:17 -0700599 return ret;
600}
601
602/*
603 * nss_get_freq_table_handler()
604 * Display Support Freq and Ex how to Change.
605 */
Thomas Wu05495be2013-12-19 14:24:24 -0800606static 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 -0700607{
608 int ret;
609
610 ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
611
Thomas Wu0a0a9c92013-11-21 15:28:19 -0800612 if (nss_runtime_samples.freq_scale_sup_max != NSS_MAX_CPU_SCALES) {
613 printk("Frequency Supported - 110Mhz 275Mhz 550Mhz\n");
614 printk("Ex. To Change Frequency - echo 110000000 > current_freq \n");
615
616 return ret;
617 }
618
wthomas626147f2013-09-18 13:12:40 -0700619 printk("Frequency Supported - 110Mhz 275Mhz 550Mhz 733Mhz \n");
wthomas442c7972013-08-05 14:28:17 -0700620 printk("Ex. To Change Frequency - echo 110000000 > current_freq \n");
621
622 return ret;
623}
624
625/*
Thomas Wu05495be2013-12-19 14:24:24 -0800626 * nss_get_average_inst_handler()
627 * Display AVG Inst Per Ms.
628 */
629static int nss_get_average_inst_handler(ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos)
630{
631 int ret;
632
633 ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
634
635 if (!ret && !write) {
636 printk("Current Inst Per Ms %x\n", nss_runtime_samples.average);
637 }
638
639 return ret;
640}
641
642/*
Abhishek Rastogi1626a902013-11-21 17:09:49 +0530643 * nss_debug_handler()
644 * Enable NSS debug output
645 */
646static int nss_debug_handler(ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos)
647{
648 int ret;
649
650 ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
651 if (!ret) {
652 if ((write) && (nss_ctl_debug != 0)) {
653 printk("Enabling NSS SPI Debug\n");
654 nss_hal_debug_enable();
655 }
656 }
657
658 return ret;
659}
660
661/*
Thomas Wu52075f42014-02-06 16:32:42 -0800662 * nss_coredump_handler()
663 * Send Signal To Coredump NSS Cores
664 */
665static int nss_coredump_handler(ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos)
666{
667 struct nss_ctx_instance *nss_ctx = (struct nss_ctx_instance *) nss_freq_change_context;
668 int ret;
669
670 ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
671 if (!ret) {
672 if ((write) && (nss_ctl_debug != 0)) {
673 printk("Coredumping to DDR\n");
674 nss_hal_send_interrupt(nss_ctx->nmap, nss_ctx->h2n_desc_rings[NSS_IF_CMD_QUEUE].desc_ring.int_bit, NSS_REGS_H2N_INTR_STATUS_COREDUMP_START);
675 }
676 }
677
678 return ret;
679}
680
681/*
wthomas442c7972013-08-05 14:28:17 -0700682 * sysctl-tuning infrastructure.
683 */
684static ctl_table nss_freq_table[] = {
685 {
686 .procname = "current_freq",
687 .data = &nss_cmd_buf.current_freq,
688 .maxlen = sizeof(int),
689 .mode = 0644,
690 .proc_handler = &nss_current_freq_handler,
691 },
692 {
693 .procname = "freq_table",
694 .data = &nss_cmd_buf.max_freq,
695 .maxlen = sizeof(int),
696 .mode = 0644,
697 .proc_handler = &nss_get_freq_table_handler,
698 },
699 {
700 .procname = "auto_scale",
701 .data = &nss_cmd_buf.auto_scale,
702 .maxlen = sizeof(int),
703 .mode = 0644,
704 .proc_handler = &nss_auto_scale_handler,
705 },
Thomas Wu05495be2013-12-19 14:24:24 -0800706 {
707 .procname = "inst_per_sec",
708 .data = &nss_cmd_buf.average_inst,
709 .maxlen = sizeof(int),
710 .mode = 0644,
711 .proc_handler = &nss_get_average_inst_handler,
712 },
wthomas442c7972013-08-05 14:28:17 -0700713 { }
714};
715
Abhishek Rastogi5cd2e4c2013-11-13 18:09:08 +0530716static ctl_table nss_general_table[] = {
717 {
718 .procname = "redirect",
719 .data = &nss_ctl_redirect,
720 .maxlen = sizeof(int),
721 .mode = 0644,
722 .proc_handler = proc_dointvec,
723 },
Abhishek Rastogi1626a902013-11-21 17:09:49 +0530724 {
725 .procname = "debug",
726 .data = &nss_ctl_debug,
727 .maxlen = sizeof(int),
728 .mode = 0644,
729 .proc_handler = &nss_debug_handler,
730 },
Thomas Wu52075f42014-02-06 16:32:42 -0800731 {
732 .procname = "coredump",
733 .data = &nss_cmd_buf.coredump,
734 .maxlen = sizeof(int),
735 .mode = 0644,
736 .proc_handler = &nss_coredump_handler,
737 },
Abhishek Rastogi5cd2e4c2013-11-13 18:09:08 +0530738 { }
739};
740
wthomas442c7972013-08-05 14:28:17 -0700741static ctl_table nss_clock_dir[] = {
742 {
Abhishek Rastogi5cd2e4c2013-11-13 18:09:08 +0530743 .procname = "clock",
744 .mode = 0555,
745 .child = nss_freq_table,
746 },
747 {
748 .procname = "general",
749 .mode = 0555,
750 .child = nss_general_table,
wthomas442c7972013-08-05 14:28:17 -0700751 },
752 { }
753};
754
755static ctl_table nss_root_dir[] = {
756 {
757 .procname = "nss",
758 .mode = 0555,
759 .child = nss_clock_dir,
760 },
761 { }
762};
763
764static ctl_table nss_root[] = {
765 {
766 .procname = "dev",
767 .mode = 0555,
768 .child = nss_root_dir,
769 },
770 { }
771};
772
773static struct ctl_table_header *nss_dev_header;
774
775/*
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530776 * nss_init()
777 * Registers nss driver
778 */
779static int __init nss_init(void)
780{
781 nss_info("Init NSS driver");
782
wthomas626147f2013-09-18 13:12:40 -0700783 nss_freq_change_context = nss_get_frequency_mgr();
784
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530785 /*
786 * Perform clock init common to all NSS cores
787 */
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530788 nss_hal_common_reset(&(nss_top_main.clk_src));
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530789
790 /*
791 * Enable spin locks
792 */
793 spin_lock_init(&(nss_top_main.lock));
794 spin_lock_init(&(nss_top_main.stats_lock));
795
796 /*
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530797 * Enable NSS statistics
798 */
799 nss_stats_init();
800
801 /*
wthomas442c7972013-08-05 14:28:17 -0700802 * Register sysctl table.
803 */
804 nss_dev_header = register_sysctl_table(nss_root);
805
806 /*
wthomas626147f2013-09-18 13:12:40 -0700807 * Setup Runtime Sample values
808 */
809 nss_runtime_samples.freq_scale[0].frequency = NSS_FREQ_110;
wthomas626147f2013-09-18 13:12:40 -0700810 nss_runtime_samples.freq_scale[0].minimum = NSS_FREQ_110_MIN;
811 nss_runtime_samples.freq_scale[0].maximum = NSS_FREQ_110_MAX;
wthomas626147f2013-09-18 13:12:40 -0700812 nss_runtime_samples.freq_scale[1].frequency = NSS_FREQ_550;
wthomas626147f2013-09-18 13:12:40 -0700813 nss_runtime_samples.freq_scale[1].minimum = NSS_FREQ_550_MIN;
814 nss_runtime_samples.freq_scale[1].maximum = NSS_FREQ_550_MAX;
wthomas626147f2013-09-18 13:12:40 -0700815 nss_runtime_samples.freq_scale[2].frequency = NSS_FREQ_733;
wthomas626147f2013-09-18 13:12:40 -0700816 nss_runtime_samples.freq_scale[2].minimum = NSS_FREQ_733_MIN;
817 nss_runtime_samples.freq_scale[2].maximum = NSS_FREQ_733_MAX;
wthomas626147f2013-09-18 13:12:40 -0700818 nss_runtime_samples.freq_scale_index = 1;
819 nss_runtime_samples.freq_scale_ready = 0;
Thomas Wu9681f7e2013-11-06 13:12:57 -0800820 nss_runtime_samples.freq_scale_rate_limit_up = 0;
821 nss_runtime_samples.freq_scale_rate_limit_down = 0;
wthomas626147f2013-09-18 13:12:40 -0700822 nss_runtime_samples.buffer_index = 0;
823 nss_runtime_samples.sum = 0;
824 nss_runtime_samples.sample_count = 0;
825 nss_runtime_samples.average = 0;
826 nss_runtime_samples.message_rate_limit = 0;
Kiran Kumar C.S.K69fd5992014-01-06 20:58:14 +0530827 nss_runtime_samples.initialized = 0;
wthomas626147f2013-09-18 13:12:40 -0700828
Thomas Wu05495be2013-12-19 14:24:24 -0800829 nss_cmd_buf.current_freq = nss_runtime_samples.freq_scale[nss_runtime_samples.freq_scale_index].frequency;
830
wthomas626147f2013-09-18 13:12:40 -0700831 /*
832 * Initial Workqueue
833 */
834 nss_wq = create_workqueue("nss_freq_queue");
835
836 /*
Pamidipati, Vijay7f413b52013-09-24 19:07:12 +0530837 * Initialize NSS Bus PM module
838 */
839 nss_pm_init();
840
841 /*
Pamidipati, Vijay5d27d812013-11-22 16:48:11 +0530842 * Register with Bus driver
843 */
844 pm_client = nss_pm_client_register(NSS_PM_CLIENT_NETAP);
845 if (!pm_client) {
846 nss_warning("Error registering with PM driver");
847 }
848
849 /*
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530850 * Register platform_driver
851 */
852 return platform_driver_register(&nss_driver);
853}
854
855/*
856 * nss_cleanup()
857 * Unregisters nss driver
858 */
859static void __exit nss_cleanup(void)
860{
861 nss_info("Exit NSS driver");
wthomas442c7972013-08-05 14:28:17 -0700862
863 if (nss_dev_header)
864 unregister_sysctl_table(nss_dev_header);
865
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530866 platform_driver_unregister(&nss_driver);
867}
868
869module_init(nss_init);
870module_exit(nss_cleanup);
871
872MODULE_DESCRIPTION("QCA NSS Driver");
873MODULE_AUTHOR("Qualcomm Atheros Inc");
874MODULE_LICENSE("Dual BSD/GPL");