blob: a5161d8670ed92b25a6489ccb0351af1e358b8b1 [file] [log] [blame]
Abhishek Rastogibc74e432013-04-02 10:28:22 +05301/* * Copyright (c) 2013 Qualcomm Atheros, Inc. * */
2
3/*
4 * nss_init.c
5 * NSS init APIs
6 *
7 */
8
9#include "nss_core.h"
10#include <nss_hal.h>
11
12#include <linux/module.h>
13#include <linux/platform_device.h>
14#include <mach/msm_nss.h>
15
16/*
Abhishek Rastogi38cffff2013-06-02 11:25:47 +053017 * Declare module parameters
18 */
19static int load0 = 0x40000000;
20module_param(load0, int, S_IRUSR | S_IWUSR);
21MODULE_PARM_DESC(load0, "NSS Core 0 load address");
22
23static int entry0 = 0x40000000;
24module_param(entry0, int, S_IRUSR | S_IWUSR);
25MODULE_PARM_DESC(load0, "NSS Core 0 entry address");
26
27static char *string0 = "nss0";
28module_param(string0, charp, 0);
29MODULE_PARM_DESC(string0, "NSS Core 0 identification string");
30
31static int load1 = 0x40100000;
32module_param(load1, int, S_IRUSR | S_IWUSR);
33MODULE_PARM_DESC(load0, "NSS Core 1 load address");
34
35static int entry1 = 0x40100000;
36module_param(entry1, int, S_IRUSR | S_IWUSR);
37MODULE_PARM_DESC(load0, "NSS Core 1 entry address");
38
39static char *string1 = "nss1";
40module_param(string1, charp, 0);
41MODULE_PARM_DESC(string1, "NSS Core 1 identification string");
42
43
44/*
Abhishek Rastogibc74e432013-04-02 10:28:22 +053045 * Global declarations
46 */
47
48/*
49 * Top level nss context structure
50 */
51struct nss_top_instance nss_top_main;
52
53/*
54 * File local/Static variables/functions
55 */
56
Abhishek Rastogi271eee72013-07-29 21:08:36 +053057static const struct net_device_ops nss_netdev_ops;
58static const struct ethtool_ops nss_ethtool_ops;
59
60/*
61 * nss_dummy_netdev_setup()
62 * Dummy setup for net_device handler
63 */
64static void nss_dummy_netdev_setup(struct net_device *ndev)
65{
66 return;
67}
68
Abhishek Rastogibc74e432013-04-02 10:28:22 +053069/*
70 * nss_handle_irq()
71 * HLOS interrupt handler for nss interrupts
72 */
73static irqreturn_t nss_handle_irq (int irq, void *ctx)
74{
75 struct int_ctx_instance *int_ctx = (struct int_ctx_instance *) ctx;
76
77 /*
78 * Disable IRQ until our bottom half re-enables it
79 */
80 disable_irq_nosync(irq);
81
82 /*
83 * Schedule tasklet to process interrupt cause
84 */
Abhishek Rastogi271eee72013-07-29 21:08:36 +053085 napi_schedule(&int_ctx->napi);
Abhishek Rastogibc74e432013-04-02 10:28:22 +053086 return IRQ_HANDLED;
87}
88
89/*
90 * nss_probe()
91 * HLOS device probe callback
92 */
Abhishek Rastogi271eee72013-07-29 21:08:36 +053093static int __devinit nss_probe(struct platform_device *nss_dev)
Abhishek Rastogibc74e432013-04-02 10:28:22 +053094{
95 struct nss_top_instance *nss_top = &nss_top_main;
96 struct nss_ctx_instance *nss_ctx = &nss_top->nss[nss_dev->id];
97 struct nss_platform_data *npd = (struct nss_platform_data *) nss_dev->dev.platform_data;
Abhishek Rastogi271eee72013-07-29 21:08:36 +053098 struct netdev_priv_instance *ndev_priv;
99 int i, err = 0;
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530100
101 nss_ctx->nss_top = nss_top;
102 nss_ctx->id = nss_dev->id;
103
104 /*
105 * Get virtual and physical memory addresses for nss logical/hardware address maps
106 */
107
108 /*
109 * Virtual address of CSM space
110 */
111 nss_ctx->nmap = npd->nmap;
112 nss_assert(nss_ctx->nmap);
113
114 /*
115 * Physical address of CSM space
116 */
117 nss_ctx->nphys = npd->nphys;
118 nss_assert(nss_ctx->nphys);
119
120 /*
121 * Virtual address of logical registers space
122 */
123 nss_ctx->vmap = npd->vmap;
124 nss_assert(nss_ctx->vmap);
125
126 /*
127 * Physical address of logical registers space
128 */
129 nss_ctx->vphys = npd->vphys;
130 nss_assert(nss_ctx->vphys);
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530131 nss_info("%d:ctx=%p, vphys=%x, vmap=%x, nphys=%x, nmap=%x",
132 nss_dev->id, nss_ctx, nss_ctx->vphys, nss_ctx->vmap, nss_ctx->nphys, nss_ctx->nmap);
133
134 /*
135 * Register netdevice handlers
136 */
137 nss_ctx->int_ctx[0].ndev = alloc_netdev(sizeof(struct netdev_priv_instance),
138 "qca-nss-dev%d", nss_dummy_netdev_setup);
139 if (nss_ctx->int_ctx[0].ndev == NULL) {
140 nss_warning("%p: Could not allocate net_device #0", nss_ctx);
141 err = -ENOMEM;
142 goto err_init_0;
143 }
144
145 nss_ctx->int_ctx[0].ndev->netdev_ops = &nss_netdev_ops;
146 nss_ctx->int_ctx[0].ndev->ethtool_ops = &nss_ethtool_ops;
147 err = register_netdev(nss_ctx->int_ctx[0].ndev);
148 if (err) {
149 nss_warning("%p: Could not register net_device #0", nss_ctx);
150 goto err_init_1;
151 }
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530152
153 /*
154 * request for IRQs
155 *
156 * WARNING: CPU affinities should be set using OS supported methods
157 */
158 nss_ctx->int_ctx[0].nss_ctx = nss_ctx;
159 nss_ctx->int_ctx[0].shift_factor = 0;
160 nss_ctx->int_ctx[0].irq = npd->irq[0];
161 err = request_irq(npd->irq[0], nss_handle_irq, IRQF_DISABLED, "nss", &nss_ctx->int_ctx[0]);
162 if (err) {
163 nss_warning("%d: IRQ0 request failed", nss_dev->id);
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530164 goto err_init_2;
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530165 }
166
167 /*
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530168 * Register NAPI for NSS core interrupt #0
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530169 */
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530170 ndev_priv = netdev_priv(nss_ctx->int_ctx[0].ndev);
171 ndev_priv->int_ctx = &nss_ctx->int_ctx[0];
172 netif_napi_add(nss_ctx->int_ctx[0].ndev, &nss_ctx->int_ctx[0].napi, nss_core_handle_napi, 64);
173 napi_enable(&nss_ctx->int_ctx[0].napi);
174 nss_ctx->int_ctx[0].napi_active = true;
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530175
176 /*
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530177 * Check if second interrupt is supported on this nss core
178 */
179 if (npd->num_irq > 1) {
180 nss_info("%d: This NSS core supports two interrupts", nss_dev->id);
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530181
182 /*
183 * Register netdevice handlers
184 */
185 nss_ctx->int_ctx[1].ndev = alloc_netdev(sizeof(struct netdev_priv_instance),
186 "qca-nss-dev%d", nss_dummy_netdev_setup);
187 if (nss_ctx->int_ctx[1].ndev == NULL) {
188 nss_warning("%p: Could not allocate net_device #1", nss_ctx);
189 err = -ENOMEM;
190 goto err_init_3;
191 }
192
193 nss_ctx->int_ctx[1].ndev->netdev_ops = &nss_netdev_ops;
194 nss_ctx->int_ctx[1].ndev->ethtool_ops = &nss_ethtool_ops;
195 err = register_netdev(nss_ctx->int_ctx[1].ndev);
196 if (err) {
197 nss_warning("%p: Could not register net_device #1", nss_ctx);
198 goto err_init_4;
199 }
200
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530201 nss_ctx->int_ctx[1].nss_ctx = nss_ctx;
202 nss_ctx->int_ctx[1].shift_factor = 15;
203 nss_ctx->int_ctx[1].irq = npd->irq[1];
204 err = request_irq(npd->irq[1], nss_handle_irq, IRQF_DISABLED, "nss", &nss_ctx->int_ctx[1]);
205 if (err) {
206 nss_warning("%d: IRQ1 request failed for nss", nss_dev->id);
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530207 goto err_init_5;
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530208 }
209
210 /*
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530211 * Register NAPI for NSS core interrupt #1
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530212 */
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530213 ndev_priv = netdev_priv(nss_ctx->int_ctx[1].ndev);
214 ndev_priv->int_ctx = &nss_ctx->int_ctx[1];
215 netif_napi_add(nss_ctx->int_ctx[1].ndev, &nss_ctx->int_ctx[1].napi, nss_core_handle_napi, 64);
216 napi_enable(&nss_ctx->int_ctx[1].napi);
217 nss_ctx->int_ctx[1].napi_active = true;
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530218 }
219
220 spin_lock_bh(&(nss_top->lock));
221
222 /*
223 * Check functionalities are supported by this NSS core
224 */
225 if (npd->ipv4_enabled == NSS_FEATURE_ENABLED) {
226 nss_top->ipv4_handler_id = nss_dev->id;
227 }
228
229 if (npd->ipv6_enabled == NSS_FEATURE_ENABLED) {
230 nss_top->ipv6_handler_id = nss_dev->id;
231 }
232
233 if (npd->l2switch_enabled == NSS_FEATURE_ENABLED) {
234 nss_top->l2switch_handler_id = nss_dev->id;
235 }
236
237 if (npd->crypto_enabled == NSS_FEATURE_ENABLED) {
238 nss_top->crypto_handler_id = nss_dev->id;
239 }
240
241 if (npd->ipsec_enabled == NSS_FEATURE_ENABLED) {
242 nss_top->ipsec_handler_id = nss_dev->id;
243 }
244
245 if (npd->wlan_enabled == NSS_FEATURE_ENABLED) {
246 nss_top->wlan_handler_id = nss_dev->id;
247 }
248
249 if (npd->gmac_enabled[0] == NSS_FEATURE_ENABLED) {
250 nss_top->phys_if_handler_id[0] = nss_dev->id;
251 }
252
253 if (npd->gmac_enabled[1] == NSS_FEATURE_ENABLED) {
254 nss_top->phys_if_handler_id[1] = nss_dev->id;
255 }
256
257 if (npd->gmac_enabled[2] == NSS_FEATURE_ENABLED) {
258 nss_top->phys_if_handler_id[2] = nss_dev->id;
259 }
260
261 if (npd->gmac_enabled[3] == NSS_FEATURE_ENABLED) {
262 nss_top->phys_if_handler_id[3] = nss_dev->id;
263 }
264
265 spin_unlock_bh(&(nss_top->lock));
266
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530267 /*
268 * Initialize decongestion callbacks to NULL
269 */
270 for (i = 0; i< NSS_MAX_CLIENTS; i++) {
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530271 nss_ctx->queue_decongestion_callback[i] = 0;
272 nss_ctx->queue_decongestion_ctx[i] = 0;
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530273 }
274
275 spin_lock_init(&(nss_ctx->decongest_cb_lock));
276 nss_ctx->magic = NSS_CTX_MAGIC;
277
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530278 nss_info("%p: Reseting NSS core %d now", nss_ctx, nss_ctx->id);
279
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530280 /*
281 * Enable clocks and bring NSS core out of reset
282 */
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530283 nss_hal_core_reset(nss_dev->id, nss_ctx->nmap, nss_ctx->load, nss_top->clk_src);
284
285 /*
286 * Enable interrupts for NSS core
287 */
288 nss_hal_enable_interrupt(nss_ctx->nmap, nss_ctx->int_ctx[0].irq,
289 nss_ctx->int_ctx[0].shift_factor, NSS_HAL_SUPPORTED_INTERRUPTS);
290
291 if (npd->num_irq > 1) {
292 nss_hal_enable_interrupt(nss_ctx->nmap, nss_ctx->int_ctx[1].irq,
293 nss_ctx->int_ctx[1].shift_factor, NSS_HAL_SUPPORTED_INTERRUPTS);
294 }
295
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530296 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 +0530297 goto err_init_0;
298
299err_init_5:
300 unregister_netdev(nss_ctx->int_ctx[1].ndev);
301err_init_4:
302 free_netdev(nss_ctx->int_ctx[1].ndev);
303err_init_3:
304 free_irq(npd->irq[0], &nss_ctx->int_ctx[0]);
305err_init_2:
306 unregister_netdev(nss_ctx->int_ctx[0].ndev);
307err_init_1:
308 free_netdev(nss_ctx->int_ctx[0].ndev);
309err_init_0:
310 return err;
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530311}
312
313/*
314 * nss_remove()
315 * HLOS device remove callback
316 */
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530317static int __devexit nss_remove(struct platform_device *nss_dev)
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530318{
319 struct nss_top_instance *nss_top = &nss_top_main;
320 struct nss_ctx_instance *nss_ctx = &nss_top->nss[nss_dev->id];
321
322 /*
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530323 * Clean-up debugfs
324 */
325 nss_stats_clean();
326
327 /*
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530328 * Disable interrupts and bottom halves in HLOS
329 * Disable interrupts from NSS to HLOS
330 */
331 nss_hal_disable_interrupt(nss_ctx->nmap, nss_ctx->int_ctx[0].irq,
332 nss_ctx->int_ctx[0].shift_factor, NSS_HAL_SUPPORTED_INTERRUPTS);
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530333
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530334 free_irq(nss_ctx->int_ctx[0].irq, &nss_ctx->int_ctx[0]);
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530335 unregister_netdev(nss_ctx->int_ctx[0].ndev);
336 free_netdev(nss_ctx->int_ctx[0].ndev);
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530337
338 /*
339 * Check if second interrupt is supported
340 * If so then clear resources for second interrupt as well
341 */
342 if (nss_ctx->int_ctx[1].irq) {
343 nss_hal_disable_interrupt(nss_ctx->nmap, nss_ctx->int_ctx[1].irq,
344 nss_ctx->int_ctx[1].shift_factor, NSS_HAL_SUPPORTED_INTERRUPTS);
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530345 free_irq(nss_ctx->int_ctx[1].irq, &nss_ctx->int_ctx[1]);
Abhishek Rastogi271eee72013-07-29 21:08:36 +0530346 unregister_netdev(nss_ctx->int_ctx[1].ndev);
347 free_netdev(nss_ctx->int_ctx[1].ndev);
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530348 }
349
350 nss_info("%p: All resources freed for nss core%d", nss_ctx, nss_dev->id);
351 return 0;
352}
353
354/*
355 * nss_driver
356 * Platform driver structure for NSS
357 */
358struct platform_driver nss_driver = {
359 .probe = nss_probe,
360 .remove = __devexit_p(nss_remove),
361 .driver = {
362 .name = "qca-nss",
363 .owner = THIS_MODULE,
364 },
365};
366
367/*
368 * nss_init()
369 * Registers nss driver
370 */
371static int __init nss_init(void)
372{
373 nss_info("Init NSS driver");
374
375 /*
376 * Perform clock init common to all NSS cores
377 */
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530378 nss_hal_common_reset(&(nss_top_main.clk_src));
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530379
380 /*
381 * Enable spin locks
382 */
383 spin_lock_init(&(nss_top_main.lock));
384 spin_lock_init(&(nss_top_main.stats_lock));
385
386 /*
Abhishek Rastogi38cffff2013-06-02 11:25:47 +0530387 * Enable NSS statistics
388 */
389 nss_stats_init();
390
391 /*
392 * Store load addresses
393 */
394 nss_top_main.nss[0].load = (uint32_t)load0;
395 nss_top_main.nss[1].load = (uint32_t)load1;
396
397 /*
Abhishek Rastogibc74e432013-04-02 10:28:22 +0530398 * Register platform_driver
399 */
400 return platform_driver_register(&nss_driver);
401}
402
403/*
404 * nss_cleanup()
405 * Unregisters nss driver
406 */
407static void __exit nss_cleanup(void)
408{
409 nss_info("Exit NSS driver");
410 platform_driver_unregister(&nss_driver);
411}
412
413module_init(nss_init);
414module_exit(nss_cleanup);
415
416MODULE_DESCRIPTION("QCA NSS Driver");
417MODULE_AUTHOR("Qualcomm Atheros Inc");
418MODULE_LICENSE("Dual BSD/GPL");