blob: 67f355e25cd9c1f5af5b7204b15f44674ce77cf7 [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"
Abhishek Rastogi9da47472014-03-18 19:46:15 +053024#include "nss_tx_rx_common.h"
Pamidipati, Vijay7f413b52013-09-24 19:07:12 +053025
Abhishek Rastogibc74e432013-04-02 10:28:22 +053026#include <nss_hal.h>
Thomas Wufb6a6842013-10-23 13:14:27 -070027#include <nss_clocks.h>
Abhishek Rastogibc74e432013-04-02 10:28:22 +053028
29#include <linux/module.h>
30#include <linux/platform_device.h>
wthomas442c7972013-08-05 14:28:17 -070031#include <linux/proc_fs.h>
32#include <linux/device.h>
Abhishek Rastogibc74e432013-04-02 10:28:22 +053033#include <mach/msm_nss.h>
34
wthomas442c7972013-08-05 14:28:17 -070035#include <linux/sysctl.h>
36#include <linux/regulator/consumer.h>
Thomas Wufb6a6842013-10-23 13:14:27 -070037#include <linux/clk.h>
wthomas442c7972013-08-05 14:28:17 -070038
Abhishek Rastogibc74e432013-04-02 10:28:22 +053039/*
40 * Global declarations
41 */
Abhishek Rastogi5cd2e4c2013-11-13 18:09:08 +053042int nss_ctl_redirect __read_mostly = 0;
Abhishek Rastogi1626a902013-11-21 17:09:49 +053043int nss_ctl_debug __read_mostly = 0;
Abhishek Rastogibc74e432013-04-02 10:28:22 +053044
45/*
Pamidipati, Vijay5d27d812013-11-22 16:48:11 +053046 * PM client handle
47 */
48static void *pm_client;
49
50/*
wthomas626147f2013-09-18 13:12:40 -070051 * Handler to send NSS messages
52 */
53void *nss_freq_change_context;
Thomas Wufb6a6842013-10-23 13:14:27 -070054struct clk *nss_core0_clk;
wthomas626147f2013-09-18 13:12:40 -070055
56/*
Abhishek Rastogibc74e432013-04-02 10:28:22 +053057 * Top level nss context structure
58 */
59struct nss_top_instance nss_top_main;
wthomas442c7972013-08-05 14:28:17 -070060struct nss_cmd_buffer nss_cmd_buf;
wthomas626147f2013-09-18 13:12:40 -070061struct nss_runtime_sampling nss_runtime_samples;
62struct workqueue_struct *nss_wq;
63
64/*
65 * Work Queue to handle messages to Kernel
66 */
67nss_work_t *nss_work;
Abhishek Rastogibc74e432013-04-02 10:28:22 +053068
69/*
70 * File local/Static variables/functions
71 */
72
Abhishek Rastogi271eee72013-07-29 21:08:36 +053073static const struct net_device_ops nss_netdev_ops;
74static const struct ethtool_ops nss_ethtool_ops;
75
76/*
77 * nss_dummy_netdev_setup()
78 * Dummy setup for net_device handler
79 */
80static void nss_dummy_netdev_setup(struct net_device *ndev)
81{
wthomas626147f2013-09-18 13:12:40 -070082
Abhishek Rastogi271eee72013-07-29 21:08:36 +053083}
84
Abhishek Rastogibc74e432013-04-02 10:28:22 +053085/*
86 * nss_handle_irq()
87 * HLOS interrupt handler for nss interrupts
88 */
89static irqreturn_t nss_handle_irq (int irq, void *ctx)
90{
91 struct int_ctx_instance *int_ctx = (struct int_ctx_instance *) ctx;
Abhishek Rastogi80f4eb12013-09-24 14:31:21 +053092 struct nss_ctx_instance *nss_ctx = int_ctx->nss_ctx;
Abhishek Rastogibc74e432013-04-02 10:28:22 +053093
94 /*
Abhishek Rastogi80f4eb12013-09-24 14:31:21 +053095 * Mask interrupt until our bottom half re-enables it
Abhishek Rastogibc74e432013-04-02 10:28:22 +053096 */
Abhishek Rastogi80f4eb12013-09-24 14:31:21 +053097 nss_hal_disable_interrupt(nss_ctx->nmap, int_ctx->irq,
98 int_ctx->shift_factor, NSS_HAL_SUPPORTED_INTERRUPTS);
Abhishek Rastogibc74e432013-04-02 10:28:22 +053099
100 /*
101 * Schedule tasklet to process interrupt cause
102 */
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530103 napi_schedule(&int_ctx->napi);
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530104 return IRQ_HANDLED;
105}
106
107/*
108 * nss_probe()
109 * HLOS device probe callback
110 */
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530111static int __devinit nss_probe(struct platform_device *nss_dev)
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530112{
113 struct nss_top_instance *nss_top = &nss_top_main;
114 struct nss_ctx_instance *nss_ctx = &nss_top->nss[nss_dev->id];
115 struct nss_platform_data *npd = (struct nss_platform_data *) nss_dev->dev.platform_data;
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530116 struct netdev_priv_instance *ndev_priv;
117 int i, err = 0;
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530118
119 nss_ctx->nss_top = nss_top;
120 nss_ctx->id = nss_dev->id;
121
wthomas442c7972013-08-05 14:28:17 -0700122 nss_info("%p: NSS_DEV_ID %s \n", nss_ctx, dev_name(&nss_dev->dev));
123
124 /*
125 * Both NSS cores controlled by same regulator, Hook only Once
126 */
127 if (!nss_dev->id) {
Thomas Wufb6a6842013-10-23 13:14:27 -0700128 nss_core0_clk = clk_get(&nss_dev->dev, "nss_core_clk");
129 if (IS_ERR(nss_core0_clk)) {
wthomas442c7972013-08-05 14:28:17 -0700130
Thomas Wufb6a6842013-10-23 13:14:27 -0700131 err = PTR_ERR(nss_core0_clk);
wthomas442c7972013-08-05 14:28:17 -0700132 nss_info("%p: Regulator %s get failed, err=%d\n", nss_ctx, dev_name(&nss_dev->dev), err);
133 return err;
134
wthomas442c7972013-08-05 14:28:17 -0700135 }
Thomas Wufb6a6842013-10-23 13:14:27 -0700136 clk_set_rate(nss_core0_clk, NSS_FREQ_550);
137 clk_prepare(nss_core0_clk);
138 clk_enable(nss_core0_clk);
Thomas Wu0a0a9c92013-11-21 15:28:19 -0800139
140 /*
141 * Check if turbo is supported
142 */
143 if (npd->turbo_frequency) {
144 /*
145 * Turbo is supported
146 */
147 printk("nss_driver - Turbo Support %d\n", npd->turbo_frequency);
148 nss_runtime_samples.freq_scale_sup_max = NSS_MAX_CPU_SCALES;
Pamidipati, Vijayf9b5a272014-01-22 14:24:10 +0530149 nss_pm_set_turbo();
Thomas Wu0a0a9c92013-11-21 15:28:19 -0800150 } else {
151 printk("nss_driver - Turbo No Support %d\n", npd->turbo_frequency);
152 nss_runtime_samples.freq_scale_sup_max = NSS_MAX_CPU_SCALES - 1;
153 }
wthomas442c7972013-08-05 14:28:17 -0700154 }
155
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530156 /*
Sakthi Vignesh Radhakrishnand923e342013-12-09 11:53:03 -0800157 * Get load address of NSS firmware
158 */
159 nss_info("%p: Setting NSS%d Firmware load address to %x\n", nss_ctx, nss_dev->id, npd->load_addr);
160 nss_top->nss[nss_dev->id].load = npd->load_addr;
161
162 /*
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530163 * Get virtual and physical memory addresses for nss logical/hardware address maps
164 */
165
166 /*
167 * Virtual address of CSM space
168 */
169 nss_ctx->nmap = npd->nmap;
170 nss_assert(nss_ctx->nmap);
171
172 /*
173 * Physical address of CSM space
174 */
175 nss_ctx->nphys = npd->nphys;
176 nss_assert(nss_ctx->nphys);
177
178 /*
179 * Virtual address of logical registers space
180 */
181 nss_ctx->vmap = npd->vmap;
182 nss_assert(nss_ctx->vmap);
183
184 /*
185 * Physical address of logical registers space
186 */
187 nss_ctx->vphys = npd->vphys;
188 nss_assert(nss_ctx->vphys);
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530189 nss_info("%d:ctx=%p, vphys=%x, vmap=%x, nphys=%x, nmap=%x",
190 nss_dev->id, nss_ctx, nss_ctx->vphys, nss_ctx->vmap, nss_ctx->nphys, nss_ctx->nmap);
191
192 /*
193 * Register netdevice handlers
194 */
195 nss_ctx->int_ctx[0].ndev = alloc_netdev(sizeof(struct netdev_priv_instance),
196 "qca-nss-dev%d", nss_dummy_netdev_setup);
197 if (nss_ctx->int_ctx[0].ndev == NULL) {
198 nss_warning("%p: Could not allocate net_device #0", nss_ctx);
199 err = -ENOMEM;
200 goto err_init_0;
201 }
202
203 nss_ctx->int_ctx[0].ndev->netdev_ops = &nss_netdev_ops;
204 nss_ctx->int_ctx[0].ndev->ethtool_ops = &nss_ethtool_ops;
205 err = register_netdev(nss_ctx->int_ctx[0].ndev);
206 if (err) {
207 nss_warning("%p: Could not register net_device #0", nss_ctx);
208 goto err_init_1;
209 }
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530210
211 /*
212 * request for IRQs
213 *
214 * WARNING: CPU affinities should be set using OS supported methods
215 */
216 nss_ctx->int_ctx[0].nss_ctx = nss_ctx;
217 nss_ctx->int_ctx[0].shift_factor = 0;
218 nss_ctx->int_ctx[0].irq = npd->irq[0];
219 err = request_irq(npd->irq[0], nss_handle_irq, IRQF_DISABLED, "nss", &nss_ctx->int_ctx[0]);
220 if (err) {
221 nss_warning("%d: IRQ0 request failed", nss_dev->id);
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530222 goto err_init_2;
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530223 }
224
225 /*
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530226 * Register NAPI for NSS core interrupt #0
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530227 */
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530228 ndev_priv = netdev_priv(nss_ctx->int_ctx[0].ndev);
229 ndev_priv->int_ctx = &nss_ctx->int_ctx[0];
230 netif_napi_add(nss_ctx->int_ctx[0].ndev, &nss_ctx->int_ctx[0].napi, nss_core_handle_napi, 64);
231 napi_enable(&nss_ctx->int_ctx[0].napi);
232 nss_ctx->int_ctx[0].napi_active = true;
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530233
234 /*
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530235 * Check if second interrupt is supported on this nss core
236 */
237 if (npd->num_irq > 1) {
238 nss_info("%d: This NSS core supports two interrupts", nss_dev->id);
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530239
240 /*
241 * Register netdevice handlers
242 */
243 nss_ctx->int_ctx[1].ndev = alloc_netdev(sizeof(struct netdev_priv_instance),
244 "qca-nss-dev%d", nss_dummy_netdev_setup);
245 if (nss_ctx->int_ctx[1].ndev == NULL) {
246 nss_warning("%p: Could not allocate net_device #1", nss_ctx);
247 err = -ENOMEM;
248 goto err_init_3;
249 }
250
251 nss_ctx->int_ctx[1].ndev->netdev_ops = &nss_netdev_ops;
252 nss_ctx->int_ctx[1].ndev->ethtool_ops = &nss_ethtool_ops;
253 err = register_netdev(nss_ctx->int_ctx[1].ndev);
254 if (err) {
255 nss_warning("%p: Could not register net_device #1", nss_ctx);
256 goto err_init_4;
257 }
258
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530259 nss_ctx->int_ctx[1].nss_ctx = nss_ctx;
260 nss_ctx->int_ctx[1].shift_factor = 15;
261 nss_ctx->int_ctx[1].irq = npd->irq[1];
262 err = request_irq(npd->irq[1], nss_handle_irq, IRQF_DISABLED, "nss", &nss_ctx->int_ctx[1]);
263 if (err) {
264 nss_warning("%d: IRQ1 request failed for nss", nss_dev->id);
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530265 goto err_init_5;
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530266 }
267
268 /*
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530269 * Register NAPI for NSS core interrupt #1
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530270 */
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530271 ndev_priv = netdev_priv(nss_ctx->int_ctx[1].ndev);
272 ndev_priv->int_ctx = &nss_ctx->int_ctx[1];
273 netif_napi_add(nss_ctx->int_ctx[1].ndev, &nss_ctx->int_ctx[1].napi, nss_core_handle_napi, 64);
274 napi_enable(&nss_ctx->int_ctx[1].napi);
275 nss_ctx->int_ctx[1].napi_active = true;
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530276 }
277
278 spin_lock_bh(&(nss_top->lock));
279
280 /*
281 * Check functionalities are supported by this NSS core
282 */
Murat Sezgin7a705422014-01-30 16:09:22 -0800283 if (npd->shaping_enabled == NSS_FEATURE_ENABLED) {
284 nss_top->shaping_handler_id = nss_dev->id;
285 printk(KERN_INFO "%p: NSS Shaping is enabled, handler id: %u", __func__, nss_top->shaping_handler_id);
286 }
287
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530288 if (npd->ipv4_enabled == NSS_FEATURE_ENABLED) {
289 nss_top->ipv4_handler_id = nss_dev->id;
Abhishek Rastogi9da47472014-03-18 19:46:15 +0530290 nss_ipv4_register_handler();
291 nss_pppoe_register_handler();
Abhishek Rastogi84d95d02014-03-26 19:31:31 +0530292 nss_eth_rx_register_handler();
293 nss_n2h_register_handler();
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530294 }
295
296 if (npd->ipv6_enabled == NSS_FEATURE_ENABLED) {
297 nss_top->ipv6_handler_id = nss_dev->id;
Abhishek Rastogi9da47472014-03-18 19:46:15 +0530298 nss_ipv6_register_handler();
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530299 }
300
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530301 if (npd->crypto_enabled == NSS_FEATURE_ENABLED) {
302 nss_top->crypto_handler_id = nss_dev->id;
Abhishek Rastogi9da47472014-03-18 19:46:15 +0530303 nss_crypto_register_handler();
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530304 }
305
306 if (npd->ipsec_enabled == NSS_FEATURE_ENABLED) {
307 nss_top->ipsec_handler_id = nss_dev->id;
Abhishek Rastogi9da47472014-03-18 19:46:15 +0530308 nss_ipsec_register_handler();
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530309 }
310
311 if (npd->wlan_enabled == NSS_FEATURE_ENABLED) {
312 nss_top->wlan_handler_id = nss_dev->id;
313 }
314
Bharath M Kumar0d87e912013-08-12 18:32:57 +0530315 if (npd->tun6rd_enabled == NSS_FEATURE_ENABLED) {
316 nss_top->tun6rd_handler_id = nss_dev->id;
Abhishek Rastogi9da47472014-03-18 19:46:15 +0530317 nss_tun6rd_register_handler();
Bharath M Kumar0d87e912013-08-12 18:32:57 +0530318 }
319
Bharath M Kumar614bbf82013-08-31 20:18:44 +0530320 if (npd->tunipip6_enabled == NSS_FEATURE_ENABLED) {
321 nss_top->tunipip6_handler_id = nss_dev->id;
Abhishek Rastogi9da47472014-03-18 19:46:15 +0530322 nss_tunipip6_register_handler();
Bharath M Kumar614bbf82013-08-31 20:18:44 +0530323 }
324
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530325 if (npd->gmac_enabled[0] == NSS_FEATURE_ENABLED) {
326 nss_top->phys_if_handler_id[0] = nss_dev->id;
Abhishek Rastogi9da47472014-03-18 19:46:15 +0530327 nss_phys_if_register_handler(0);
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530328 }
329
330 if (npd->gmac_enabled[1] == NSS_FEATURE_ENABLED) {
331 nss_top->phys_if_handler_id[1] = nss_dev->id;
Abhishek Rastogi9da47472014-03-18 19:46:15 +0530332 nss_phys_if_register_handler(1);
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530333 }
334
335 if (npd->gmac_enabled[2] == NSS_FEATURE_ENABLED) {
336 nss_top->phys_if_handler_id[2] = nss_dev->id;
Abhishek Rastogi9da47472014-03-18 19:46:15 +0530337 nss_phys_if_register_handler(2);
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530338 }
339
340 if (npd->gmac_enabled[3] == NSS_FEATURE_ENABLED) {
341 nss_top->phys_if_handler_id[3] = nss_dev->id;
Abhishek Rastogi9da47472014-03-18 19:46:15 +0530342 nss_phys_if_register_handler(3);
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530343 }
344
Thomas Wu168ca262014-03-21 16:20:27 -0700345 nss_core_freq_register_handler();
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/*
Kiran Kumar C.S.K69fd5992014-01-06 20:58:14 +0530456 * nss_reset_frequency_stats_samples()
457 * Reset all frequency sampling state when auto scaling is turned off.
458 */
459static void nss_reset_frequency_stats_samples (void)
460{
461 nss_runtime_samples.buffer_index = 0;
462 nss_runtime_samples.sum = 0;
463 nss_runtime_samples.average = 0;
464 nss_runtime_samples.sample_count = 0;
465 nss_runtime_samples.message_rate_limit = 0;
466 nss_runtime_samples.freq_scale_rate_limit_up = 0;
467 nss_runtime_samples.freq_scale_rate_limit_down = 0;
468}
469
470/*
wthomas626147f2013-09-18 13:12:40 -0700471 ***************************************************************************************************
Thomas Wufb6a6842013-10-23 13:14:27 -0700472 * nss_wq_function() is used to queue up requests to change NSS frequencies.
473 * The function will take care of NSS notices and also control clock.
474 * The auto rate algorithmn will queue up requests or the procfs may also queue up these requests.
wthomas626147f2013-09-18 13:12:40 -0700475 ***************************************************************************************************
476 */
477
478/*
479 * nss_wq_function()
480 * Added to Handle BH requests to kernel
481 */
482void nss_wq_function (struct work_struct *work)
483{
484 nss_work_t *my_work = (nss_work_t *)work;
485
Kiran Kumar C.S.K69fd5992014-01-06 20:58:14 +0530486 nss_freq_change(nss_freq_change_context, my_work->frequency, my_work->stats_enable, 0);
Thomas Wufb6a6842013-10-23 13:14:27 -0700487 clk_set_rate(nss_core0_clk, my_work->frequency);
Kiran Kumar C.S.K69fd5992014-01-06 20:58:14 +0530488 nss_freq_change(nss_freq_change_context, my_work->frequency, my_work->stats_enable, 1);
wthomas626147f2013-09-18 13:12:40 -0700489
Pamidipati, Vijay5d27d812013-11-22 16:48:11 +0530490 if(!pm_client) {
491 goto out;
492 }
493
494 if (my_work->frequency == NSS_FREQ_733) {
495 nss_pm_set_perf_level(pm_client, NSS_PM_PERF_LEVEL_TURBO);
496 } else if ((my_work->frequency == NSS_FREQ_275) || (my_work->frequency == NSS_FREQ_550)) {
497 nss_pm_set_perf_level(pm_client, NSS_PM_PERF_LEVEL_NOMINAL);
498 } else {
499 nss_pm_set_perf_level(pm_client, NSS_PM_PERF_LEVEL_IDLE);
500 }
501out:
wthomas626147f2013-09-18 13:12:40 -0700502 kfree((void *)work);
503}
504
505/*
wthomas442c7972013-08-05 14:28:17 -0700506 * nss_current_freq_handler()
507 * Handle Userspace Frequency Change Requests
508 */
509static int nss_current_freq_handler (ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos)
510{
wthomas442c7972013-08-05 14:28:17 -0700511 int ret;
wthomas626147f2013-09-18 13:12:40 -0700512
513 BUG_ON(!nss_wq);
wthomas442c7972013-08-05 14:28:17 -0700514
515 ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
516
wthomasd39fa822013-08-22 16:44:23 -0700517 if (!write) {
wthomas626147f2013-09-18 13:12:40 -0700518 printk("Frequency Set to %d\n", nss_cmd_buf.current_freq);
wthomasd39fa822013-08-22 16:44:23 -0700519 return ret;
wthomas442c7972013-08-05 14:28:17 -0700520 }
wthomasd39fa822013-08-22 16:44:23 -0700521
wthomas626147f2013-09-18 13:12:40 -0700522 /* Turn off Auto Scale */
523 nss_cmd_buf.auto_scale = 0;
524 nss_runtime_samples.freq_scale_ready = 0;
wthomasd39fa822013-08-22 16:44:23 -0700525
Thomas Wu0a0a9c92013-11-21 15:28:19 -0800526 /* If support NSS freq is in the table send the new frequency request to NSS or If No Turbo and ask for turbo freq */
527 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 -0700528 printk("Frequency not found. Please check Frequency Table\n");
wthomas626147f2013-09-18 13:12:40 -0700529 return ret;
wthomasd39fa822013-08-22 16:44:23 -0700530 }
531
wthomas626147f2013-09-18 13:12:40 -0700532 nss_work = (nss_work_t *)kmalloc(sizeof(nss_work_t), GFP_KERNEL);
533 if (!nss_work) {
534 nss_info("NSS Freq WQ kmalloc fail");
535 return ret;
536 }
537 INIT_WORK((struct work_struct *)nss_work, nss_wq_function);
538 nss_work->frequency = nss_cmd_buf.current_freq;
Kiran Kumar C.S.K69fd5992014-01-06 20:58:14 +0530539 nss_work->stats_enable = 0;
540
541 /* Ensure we start with a fresh set of samples later */
542 nss_reset_frequency_stats_samples();
543
wthomas626147f2013-09-18 13:12:40 -0700544 queue_work(nss_wq, (struct work_struct *)nss_work);
545
wthomas442c7972013-08-05 14:28:17 -0700546 return ret;
547}
548
549/*
550 * nss_auto_scale_handler()
551 * Enables or Disable Auto Scaling
552 */
553static int nss_auto_scale_handler (ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos)
554{
555 int ret;
556
557 ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
558
wthomas626147f2013-09-18 13:12:40 -0700559 if (!write) {
560 return ret;
561 }
562
Thomas Wufb6a6842013-10-23 13:14:27 -0700563 if (nss_cmd_buf.auto_scale != 1) {
wthomas626147f2013-09-18 13:12:40 -0700564 /*
Kiran Kumar C.S.K69fd5992014-01-06 20:58:14 +0530565 * Is auto scaling currently enabled? If so, send the command to
566 * disable stats reporting to NSS
wthomas626147f2013-09-18 13:12:40 -0700567 */
Kiran Kumar C.S.K69fd5992014-01-06 20:58:14 +0530568 if (nss_runtime_samples.freq_scale_ready != 0) {
569 nss_cmd_buf.current_freq = nss_runtime_samples.freq_scale[nss_runtime_samples.freq_scale_index].frequency;
570 nss_work = (nss_work_t *)kmalloc(sizeof(nss_work_t), GFP_KERNEL);
571 if (!nss_work) {
572 nss_info("NSS Freq WQ kmalloc fail");
573 return ret;
574 }
575 INIT_WORK((struct work_struct *)nss_work, nss_wq_function);
576 nss_work->frequency = nss_cmd_buf.current_freq;
577 nss_work->stats_enable = 0;
578 queue_work(nss_wq, (struct work_struct *)nss_work);
579 nss_runtime_samples.freq_scale_ready = 0;
580
581 /*
582 * The current samples would be stale later when scaling is
583 * enabled again, hence reset them
584 */
585 nss_reset_frequency_stats_samples();
586 }
Thomas Wufb6a6842013-10-23 13:14:27 -0700587 return ret;
wthomas626147f2013-09-18 13:12:40 -0700588 }
wthomas442c7972013-08-05 14:28:17 -0700589
Thomas Wufb6a6842013-10-23 13:14:27 -0700590 /*
591 * Auto Scaling is already being done
592 */
593 if (nss_runtime_samples.freq_scale_ready == 1) {
594 return ret;
595 }
596
597 /*
598 * Setup default values - Middle of Freq Scale Band
599 */
600 nss_runtime_samples.freq_scale_index = 1;
601 nss_cmd_buf.current_freq = nss_runtime_samples.freq_scale[nss_runtime_samples.freq_scale_index].frequency;
602
603 nss_work = (nss_work_t *)kmalloc(sizeof(nss_work_t), GFP_KERNEL);
604 if (!nss_work) {
605 nss_info("NSS Freq WQ kmalloc fail");
606 return ret;
607 }
608 INIT_WORK((struct work_struct *)nss_work, nss_wq_function);
609 nss_work->frequency = nss_cmd_buf.current_freq;
Kiran Kumar C.S.K69fd5992014-01-06 20:58:14 +0530610 nss_work->stats_enable = 1;
Thomas Wufb6a6842013-10-23 13:14:27 -0700611 queue_work(nss_wq, (struct work_struct *)nss_work);
612
613 nss_runtime_samples.freq_scale_ready = 1;
614
wthomas442c7972013-08-05 14:28:17 -0700615 return ret;
616}
617
618/*
619 * nss_get_freq_table_handler()
620 * Display Support Freq and Ex how to Change.
621 */
Thomas Wu05495be2013-12-19 14:24:24 -0800622static 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 -0700623{
624 int ret;
625
626 ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
627
Thomas Wu0a0a9c92013-11-21 15:28:19 -0800628 if (nss_runtime_samples.freq_scale_sup_max != NSS_MAX_CPU_SCALES) {
629 printk("Frequency Supported - 110Mhz 275Mhz 550Mhz\n");
630 printk("Ex. To Change Frequency - echo 110000000 > current_freq \n");
631
632 return ret;
633 }
634
wthomas626147f2013-09-18 13:12:40 -0700635 printk("Frequency Supported - 110Mhz 275Mhz 550Mhz 733Mhz \n");
wthomas442c7972013-08-05 14:28:17 -0700636 printk("Ex. To Change Frequency - echo 110000000 > current_freq \n");
637
638 return ret;
639}
640
641/*
Thomas Wu05495be2013-12-19 14:24:24 -0800642 * nss_get_average_inst_handler()
643 * Display AVG Inst Per Ms.
644 */
645static int nss_get_average_inst_handler(ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos)
646{
647 int ret;
648
649 ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
650
651 if (!ret && !write) {
652 printk("Current Inst Per Ms %x\n", nss_runtime_samples.average);
653 }
654
655 return ret;
656}
657
658/*
Abhishek Rastogi1626a902013-11-21 17:09:49 +0530659 * nss_debug_handler()
660 * Enable NSS debug output
661 */
662static int nss_debug_handler(ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos)
663{
664 int ret;
665
666 ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
667 if (!ret) {
668 if ((write) && (nss_ctl_debug != 0)) {
669 printk("Enabling NSS SPI Debug\n");
670 nss_hal_debug_enable();
671 }
672 }
673
674 return ret;
675}
676
677/*
Thomas Wu52075f42014-02-06 16:32:42 -0800678 * nss_coredump_handler()
679 * Send Signal To Coredump NSS Cores
680 */
681static int nss_coredump_handler(ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos)
682{
683 struct nss_ctx_instance *nss_ctx = (struct nss_ctx_instance *) nss_freq_change_context;
684 int ret;
685
686 ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
687 if (!ret) {
688 if ((write) && (nss_ctl_debug != 0)) {
689 printk("Coredumping to DDR\n");
690 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);
691 }
692 }
693
694 return ret;
695}
696
697/*
wthomas442c7972013-08-05 14:28:17 -0700698 * sysctl-tuning infrastructure.
699 */
700static ctl_table nss_freq_table[] = {
701 {
702 .procname = "current_freq",
703 .data = &nss_cmd_buf.current_freq,
704 .maxlen = sizeof(int),
705 .mode = 0644,
706 .proc_handler = &nss_current_freq_handler,
707 },
708 {
709 .procname = "freq_table",
710 .data = &nss_cmd_buf.max_freq,
711 .maxlen = sizeof(int),
712 .mode = 0644,
713 .proc_handler = &nss_get_freq_table_handler,
714 },
715 {
716 .procname = "auto_scale",
717 .data = &nss_cmd_buf.auto_scale,
718 .maxlen = sizeof(int),
719 .mode = 0644,
720 .proc_handler = &nss_auto_scale_handler,
721 },
Thomas Wu05495be2013-12-19 14:24:24 -0800722 {
723 .procname = "inst_per_sec",
724 .data = &nss_cmd_buf.average_inst,
725 .maxlen = sizeof(int),
726 .mode = 0644,
727 .proc_handler = &nss_get_average_inst_handler,
728 },
wthomas442c7972013-08-05 14:28:17 -0700729 { }
730};
731
Abhishek Rastogi5cd2e4c2013-11-13 18:09:08 +0530732static ctl_table nss_general_table[] = {
733 {
734 .procname = "redirect",
735 .data = &nss_ctl_redirect,
736 .maxlen = sizeof(int),
737 .mode = 0644,
738 .proc_handler = proc_dointvec,
739 },
Abhishek Rastogi1626a902013-11-21 17:09:49 +0530740 {
741 .procname = "debug",
742 .data = &nss_ctl_debug,
743 .maxlen = sizeof(int),
744 .mode = 0644,
745 .proc_handler = &nss_debug_handler,
746 },
Thomas Wu52075f42014-02-06 16:32:42 -0800747 {
748 .procname = "coredump",
749 .data = &nss_cmd_buf.coredump,
750 .maxlen = sizeof(int),
751 .mode = 0644,
752 .proc_handler = &nss_coredump_handler,
753 },
Abhishek Rastogi5cd2e4c2013-11-13 18:09:08 +0530754 { }
755};
756
wthomas442c7972013-08-05 14:28:17 -0700757static ctl_table nss_clock_dir[] = {
758 {
Abhishek Rastogi5cd2e4c2013-11-13 18:09:08 +0530759 .procname = "clock",
760 .mode = 0555,
761 .child = nss_freq_table,
762 },
763 {
764 .procname = "general",
765 .mode = 0555,
766 .child = nss_general_table,
wthomas442c7972013-08-05 14:28:17 -0700767 },
768 { }
769};
770
771static ctl_table nss_root_dir[] = {
772 {
773 .procname = "nss",
774 .mode = 0555,
775 .child = nss_clock_dir,
776 },
777 { }
778};
779
780static ctl_table nss_root[] = {
781 {
782 .procname = "dev",
783 .mode = 0555,
784 .child = nss_root_dir,
785 },
786 { }
787};
788
789static struct ctl_table_header *nss_dev_header;
790
791/*
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530792 * nss_init()
793 * Registers nss driver
794 */
795static int __init nss_init(void)
796{
797 nss_info("Init NSS driver");
798
wthomas626147f2013-09-18 13:12:40 -0700799 nss_freq_change_context = nss_get_frequency_mgr();
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530800 /*
801 * Perform clock init common to all NSS cores
802 */
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530803 nss_hal_common_reset(&(nss_top_main.clk_src));
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530804
805 /*
806 * Enable spin locks
807 */
808 spin_lock_init(&(nss_top_main.lock));
809 spin_lock_init(&(nss_top_main.stats_lock));
810
811 /*
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530812 * Enable NSS statistics
813 */
814 nss_stats_init();
815
816 /*
wthomas442c7972013-08-05 14:28:17 -0700817 * Register sysctl table.
818 */
819 nss_dev_header = register_sysctl_table(nss_root);
820
821 /*
wthomas626147f2013-09-18 13:12:40 -0700822 * Setup Runtime Sample values
823 */
824 nss_runtime_samples.freq_scale[0].frequency = NSS_FREQ_110;
wthomas626147f2013-09-18 13:12:40 -0700825 nss_runtime_samples.freq_scale[0].minimum = NSS_FREQ_110_MIN;
826 nss_runtime_samples.freq_scale[0].maximum = NSS_FREQ_110_MAX;
wthomas626147f2013-09-18 13:12:40 -0700827 nss_runtime_samples.freq_scale[1].frequency = NSS_FREQ_550;
wthomas626147f2013-09-18 13:12:40 -0700828 nss_runtime_samples.freq_scale[1].minimum = NSS_FREQ_550_MIN;
829 nss_runtime_samples.freq_scale[1].maximum = NSS_FREQ_550_MAX;
wthomas626147f2013-09-18 13:12:40 -0700830 nss_runtime_samples.freq_scale[2].frequency = NSS_FREQ_733;
wthomas626147f2013-09-18 13:12:40 -0700831 nss_runtime_samples.freq_scale[2].minimum = NSS_FREQ_733_MIN;
832 nss_runtime_samples.freq_scale[2].maximum = NSS_FREQ_733_MAX;
wthomas626147f2013-09-18 13:12:40 -0700833 nss_runtime_samples.freq_scale_index = 1;
834 nss_runtime_samples.freq_scale_ready = 0;
Thomas Wu9681f7e2013-11-06 13:12:57 -0800835 nss_runtime_samples.freq_scale_rate_limit_up = 0;
836 nss_runtime_samples.freq_scale_rate_limit_down = 0;
wthomas626147f2013-09-18 13:12:40 -0700837 nss_runtime_samples.buffer_index = 0;
838 nss_runtime_samples.sum = 0;
839 nss_runtime_samples.sample_count = 0;
840 nss_runtime_samples.average = 0;
841 nss_runtime_samples.message_rate_limit = 0;
Kiran Kumar C.S.K69fd5992014-01-06 20:58:14 +0530842 nss_runtime_samples.initialized = 0;
wthomas626147f2013-09-18 13:12:40 -0700843
Thomas Wu05495be2013-12-19 14:24:24 -0800844 nss_cmd_buf.current_freq = nss_runtime_samples.freq_scale[nss_runtime_samples.freq_scale_index].frequency;
845
wthomas626147f2013-09-18 13:12:40 -0700846 /*
847 * Initial Workqueue
848 */
849 nss_wq = create_workqueue("nss_freq_queue");
850
851 /*
Pamidipati, Vijay7f413b52013-09-24 19:07:12 +0530852 * Initialize NSS Bus PM module
853 */
854 nss_pm_init();
855
856 /*
Pamidipati, Vijay5d27d812013-11-22 16:48:11 +0530857 * Register with Bus driver
858 */
859 pm_client = nss_pm_client_register(NSS_PM_CLIENT_NETAP);
860 if (!pm_client) {
861 nss_warning("Error registering with PM driver");
862 }
863
864 /*
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530865 * Register platform_driver
866 */
867 return platform_driver_register(&nss_driver);
868}
869
870/*
871 * nss_cleanup()
872 * Unregisters nss driver
873 */
874static void __exit nss_cleanup(void)
875{
876 nss_info("Exit NSS driver");
wthomas442c7972013-08-05 14:28:17 -0700877
878 if (nss_dev_header)
879 unregister_sysctl_table(nss_dev_header);
880
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530881 platform_driver_unregister(&nss_driver);
882}
883
884module_init(nss_init);
885module_exit(nss_cleanup);
886
887MODULE_DESCRIPTION("QCA NSS Driver");
888MODULE_AUTHOR("Qualcomm Atheros Inc");
889MODULE_LICENSE("Dual BSD/GPL");