~ubuntu-branches/ubuntu/precise/linux-ti-omap4/precise

« back to all changes in this revision

Viewing changes to drivers/dsp/syslink/notify_ducatidriver/notify_ducati.c

  • Committer: Bazaar Package Importer
  • Author(s): Paolo Pisati
  • Date: 2011-06-29 15:23:51 UTC
  • mfrom: (26.1.1 natty-proposed)
  • Revision ID: james.westby@ubuntu.com-20110629152351-xs96tm303d95rpbk
Tags: 3.0.0-1200.2
* Rebased against 3.0.0-6.7
* BSP from TI based on 3.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * notify_ducati.c
3
 
 *
4
 
 * Syslink driver support functions for TI OMAP processors.
5
 
 *
6
 
 * Copyright (C) 2008-2009 Texas Instruments, Inc.
7
 
 *
8
 
 * This package is free software; you can redistribute it and/or modify
9
 
 * it under the terms of the GNU General Public License version 2 as
10
 
 * published by the Free Software Foundation.
11
 
 *
12
 
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
13
 
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
14
 
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
15
 
 */
16
 
 
17
 
 
18
 
#include <linux/spinlock.h>
19
 
#include <linux/semaphore.h>
20
 
#include <linux/timer.h>
21
 
#include <linux/sched.h>
22
 
#include <linux/interrupt.h>
23
 
#include <linux/list.h>
24
 
#include <linux/io.h>
25
 
#include <linux/module.h>
26
 
#include <linux/slab.h>
27
 
#include <plat/mailbox.h>
28
 
 
29
 
#include <syslink/multiproc.h>
30
 
#include <syslink/atomic_linux.h>
31
 
#include <syslink/sharedregion.h>
32
 
#include <syslink/notify_driver.h>
33
 
#include <syslink/notifydefs.h>
34
 
#include <syslink/notify_driverdefs.h>
35
 
#include <syslink/notify_ducatidriver.h>
36
 
 
37
 
 
38
 
 
39
 
#define NOTIFYDUCATIDRIVER_MEM_ALIGN    0
40
 
 
41
 
#define NOTIFYDUCATIDRIVER_MAX_EVENTS   32
42
 
 
43
 
#define NOTIFYNONSHMDRV_MAX_EVENTS      1
44
 
 
45
 
#define NOTIFYNONSHMDRV_RESERVED_EVENTS 1
46
 
 
47
 
#define NOTIFYDRV_DUCATI_RECV_MBX       2
48
 
 
49
 
#define NOTIFYDRV_DUCATI_SEND_MBX       3
50
 
 
51
 
/* Get address of event entry. */
52
 
#define EVENTENTRY(event_chart, align, event_id)                        \
53
 
                        ((struct notify_ducatidrv_event_entry *)        \
54
 
                        ((u32)event_chart + (align * event_id)));
55
 
 
56
 
/* Stamp indicating that the Notify Shared Memory driver on the
57
 
 * processor has been initialized. */
58
 
#define NOTIFYDUCATIDRIVER_INIT_STAMP   0xA9C8B7D6
59
 
 
60
 
/* Flag indicating event is set. */
61
 
#define NOTIFYDUCATIDRIVER_UP           1
62
 
 
63
 
/* Flag indicating event is not set. */
64
 
#define NOTIFYDUCATIDRIVER_DOWN         0
65
 
 
66
 
/*FIX ME: Make use of Multi Proc module */
67
 
#define SELF_ID         0
68
 
 
69
 
#define OTHER_ID        1
70
 
 
71
 
#define PROC_TESLA      0
72
 
#define PROC_DUCATI     1
73
 
#define PROC_GPP        2
74
 
#define PROCSYSM3       2
75
 
#define PROCAPPM3       3
76
 
#define MAX_SUBPROC_EVENTS      15
77
 
 
78
 
/* Macro to make a correct module magic number with refCount */
79
 
#define NOTIFYDUCATIDRIVER_MAKE_MAGICSTAMP(x) \
80
 
                                ((NOTIFY_DUCATIDRIVER_MODULEID << 12u) | (x))
81
 
 
82
 
#define ROUND_UP(a, b)  (((a) + ((b) - 1)) & (~((b) - 1)))
83
 
 
84
 
static struct omap_mbox *ducati_mbox;
85
 
static struct omap_mbox *tesla_mbox;
86
 
static int notify_shmdrv_isr(struct notifier_block *, unsigned long, void *);
87
 
static bool notify_shmdrv_isr_callback(void *ref_data, void* ntfy_msg);
88
 
 
89
 
 
90
 
/* Defines the notify_ducatidrv state object, which contains all
91
 
 * the module specific information. */
92
 
struct notify_ducatidrv_module {
93
 
        atomic_t ref_count;
94
 
        /* Reference count */
95
 
        struct notify_ducatidrv_config cfg;
96
 
        /* NotifyDriverShm configuration structure */
97
 
        struct notify_ducatidrv_config def_cfg;
98
 
        /* Default module configuration */
99
 
        struct notify_ducatidrv_params def_inst_params;
100
 
        /* Default instance parameters */
101
 
        struct mutex *gate_handle;
102
 
        /* Handle to the gate for local thread safety */
103
 
        struct notify_ducatidrv_object *driver_handles
104
 
                                [MULTIPROC_MAXPROCESSORS][NOTIFY_MAX_INTLINES];
105
 
        /* Loader handle array. */
106
 
        atomic_t mbox2_ref_count;
107
 
        /* Reference count for enabling/disabling ducati mailbox interrupt */
108
 
        atomic_t mbox1_ref_count;
109
 
        /* Reference count for enabling/disabling tesla mailbox interrupt */
110
 
};
111
 
 
112
 
/* Notify ducati driver instance object. */
113
 
struct notify_ducatidrv_object {
114
 
        struct notify_ducatidrv_params params;
115
 
        /* Instance parameters (configuration values) */
116
 
        VOLATILE struct notify_ducatidrv_proc_ctrl *self_proc_ctrl;
117
 
        /* Pointer to control structure in shared memory for self processor. */
118
 
        VOLATILE struct notify_ducatidrv_proc_ctrl *other_proc_ctrl;
119
 
        /* Pointer to control structure in shared memory for remote processor.*/
120
 
        VOLATILE struct notify_ducatidrv_event_entry *self_event_chart;
121
 
        /* Pointer to event chart for local processor */
122
 
        VOLATILE struct notify_ducatidrv_event_entry *other_event_chart;
123
 
        /* Pointer to event chart for remote processor */
124
 
        u32 reg_chart[NOTIFY_MAXEVENTS];
125
 
        /* Local event registration chart for tracking registered events. */
126
 
        u16 self_id;
127
 
        /* Self ID used for identification of local control region */
128
 
        u16 other_id;
129
 
        /* Other ID used for identification of remote control region */
130
 
        u16 remote_proc_id;
131
 
        /* Processor ID of the remote processor which which this driver instance
132
 
         communicates. */
133
 
        struct notify_driver_object *drv_handle;
134
 
        /* Common NotifyDriver handle */
135
 
        u32 nesting;
136
 
        /* For disable/restore nesting */
137
 
        u32 cache_enabled;
138
 
        /* Whether to perform cache calls */
139
 
        u32 event_entry_size;
140
 
        /* Spacing between event entries   */
141
 
        u32 num_events;
142
 
        /* Number of events configured */
143
 
};
144
 
 
145
 
 
146
 
static struct notify_ducatidrv_module notify_ducatidriver_state = {
147
 
        .gate_handle = NULL,
148
 
        .def_inst_params.shared_addr = NULL,
149
 
        .def_inst_params.cache_enabled = false,
150
 
        .def_inst_params.cache_line_size = 128u,
151
 
        .def_inst_params.remote_proc_id = MULTIPROC_INVALIDID,
152
 
        .def_inst_params.line_id = 0,
153
 
        .def_inst_params.local_int_id = (u32) -1,
154
 
        .def_inst_params.remote_int_id = (u32) -1
155
 
};
156
 
 
157
 
static struct notifier_block ducati_notify_nb = {
158
 
        .notifier_call = notify_shmdrv_isr,
159
 
};
160
 
 
161
 
/* Get the default configuration for the notify_ducatidrv module. */
162
 
void notify_ducatidrv_get_config(struct notify_ducatidrv_config *cfg)
163
 
{
164
 
        int status = NOTIFY_S_SUCCESS;
165
 
 
166
 
        if (WARN_ON(unlikely(cfg == NULL))) {
167
 
                status = NOTIFY_E_INVALIDARG;
168
 
                goto exit;
169
 
        }
170
 
 
171
 
        if (atomic_cmpmask_and_lt(&(notify_ducatidriver_state.ref_count),
172
 
                                        NOTIFYDUCATIDRIVER_MAKE_MAGICSTAMP(0),
173
 
                                        NOTIFYDUCATIDRIVER_MAKE_MAGICSTAMP(1))
174
 
                                        == true)
175
 
                memcpy(cfg, &(notify_ducatidriver_state.def_cfg),
176
 
                        sizeof(struct notify_ducatidrv_config));
177
 
        else
178
 
                memcpy(cfg, &(notify_ducatidriver_state.cfg),
179
 
                        sizeof(struct notify_ducatidrv_config));
180
 
 
181
 
exit:
182
 
        if (status < 0) {
183
 
                pr_err("notify_ducatidrv_get_config failed! "
184
 
                        "status = 0x%x", status);
185
 
        }
186
 
        return;
187
 
}
188
 
EXPORT_SYMBOL(notify_ducatidrv_get_config);
189
 
 
190
 
/* Setup the notify_ducatidrv module. */
191
 
int notify_ducatidrv_setup(struct notify_ducatidrv_config *cfg)
192
 
{
193
 
        int status = 0;
194
 
        struct notify_ducatidrv_config tmp_cfg;
195
 
        u16 i;
196
 
        u16 j;
197
 
 
198
 
        /* Init the ref_count to 0 */
199
 
        atomic_cmpmask_and_set(&(notify_ducatidriver_state.ref_count),
200
 
                                        NOTIFYDUCATIDRIVER_MAKE_MAGICSTAMP(0),
201
 
                                        NOTIFYDUCATIDRIVER_MAKE_MAGICSTAMP(0));
202
 
        if (atomic_inc_return(&(notify_ducatidriver_state.ref_count)) !=
203
 
                NOTIFYDUCATIDRIVER_MAKE_MAGICSTAMP(1u)) {
204
 
                return NOTIFY_S_ALREADYSETUP;
205
 
        }
206
 
        atomic_set(&(notify_ducatidriver_state.mbox2_ref_count), 0);
207
 
        atomic_set(&(notify_ducatidriver_state.mbox1_ref_count), 0);
208
 
 
209
 
        if (cfg == NULL) {
210
 
                notify_ducatidrv_get_config(&tmp_cfg);
211
 
                cfg = &tmp_cfg;
212
 
        }
213
 
 
214
 
        /* Create a default gate handle here */
215
 
        notify_ducatidriver_state.gate_handle =
216
 
                        kmalloc(sizeof(struct mutex), GFP_KERNEL);
217
 
        if (notify_ducatidriver_state.gate_handle == NULL) {
218
 
                status = NOTIFY_E_MEMORY;
219
 
                goto error_exit;
220
 
        }
221
 
        mutex_init(notify_ducatidriver_state.gate_handle);
222
 
 
223
 
        for (i = 0 ; i < MULTIPROC_MAXPROCESSORS; i++)
224
 
                for (j = 0 ; j < NOTIFY_MAX_INTLINES; j++)
225
 
                        notify_ducatidriver_state.driver_handles[i][j] = NULL;
226
 
 
227
 
        memcpy(&notify_ducatidriver_state.cfg, cfg,
228
 
                        sizeof(struct notify_ducatidrv_config));
229
 
 
230
 
        /* Initialize the maibox module for Ducati */
231
 
        if (ducati_mbox == NULL) {
232
 
                ducati_mbox = omap_mbox_get("mailbox-2", &ducati_notify_nb);
233
 
                if (ducati_mbox == NULL) {
234
 
                        pr_err("Failed in omap_mbox_get(ducati)\n");
235
 
                        status = NOTIFY_E_INVALIDSTATE;
236
 
                        goto error_mailbox_get_failed;
237
 
                }
238
 
        }
239
 
 
240
 
        /* Initialize the maibox module for Tesla */
241
 
        if (!tesla_mbox) {
242
 
                tesla_mbox = omap_mbox_get("mailbox-1", &ducati_notify_nb);
243
 
                if (!tesla_mbox) {
244
 
                        pr_err("Failed in omap_mbox_get(tesla)\n");
245
 
                        status = NOTIFY_E_INVALIDSTATE;
246
 
                        goto error_mailbox_get_failed;
247
 
                }
248
 
        }
249
 
        return 0;
250
 
 
251
 
error_mailbox_get_failed:
252
 
        kfree(notify_ducatidriver_state.gate_handle);
253
 
error_exit:
254
 
        atomic_set(&(notify_ducatidriver_state.ref_count),
255
 
                        NOTIFYDUCATIDRIVER_MAKE_MAGICSTAMP(0));
256
 
        pr_err("notify_ducatidrv_setup failed! status = 0x%x", status);
257
 
        return status;
258
 
}
259
 
EXPORT_SYMBOL(notify_ducatidrv_setup);
260
 
 
261
 
/* Destroy the notify_ducatidrv module. */
262
 
int notify_ducatidrv_destroy(void)
263
 
{
264
 
        int status = NOTIFY_S_SUCCESS;
265
 
        u16 i;
266
 
        u16 j;
267
 
 
268
 
        if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
269
 
                        &(notify_ducatidriver_state.ref_count),
270
 
                        NOTIFYDUCATIDRIVER_MAKE_MAGICSTAMP(0),
271
 
                        NOTIFYDUCATIDRIVER_MAKE_MAGICSTAMP(1)) == true))) {
272
 
                status = NOTIFY_E_INVALIDSTATE;
273
 
                goto exit;
274
 
        }
275
 
        if (!(atomic_dec_return(&notify_ducatidriver_state.ref_count) == \
276
 
                                NOTIFYDUCATIDRIVER_MAKE_MAGICSTAMP(0)))
277
 
                return NOTIFY_S_ALREADYSETUP;
278
 
 
279
 
        /* Temporarily increment the refcount */
280
 
        atomic_set(&(notify_ducatidriver_state.ref_count),
281
 
                                        NOTIFYDUCATIDRIVER_MAKE_MAGICSTAMP(1));
282
 
 
283
 
        for (i = 0 ; i < MULTIPROC_MAXPROCESSORS; i++) {
284
 
                for (j = 0 ; j < NOTIFY_MAX_INTLINES; j++) {
285
 
                        if (notify_ducatidriver_state.driver_handles[i][j] != \
286
 
                                NULL) {
287
 
                                notify_ducatidrv_delete(
288
 
                                        &notify_ducatidriver_state.\
289
 
                                                driver_handles[i][j]);
290
 
                        }
291
 
                }
292
 
        }
293
 
 
294
 
        if (notify_ducatidriver_state.gate_handle != NULL)
295
 
                kfree(notify_ducatidriver_state.gate_handle);
296
 
 
297
 
        atomic_set(&(notify_ducatidriver_state.ref_count),
298
 
                NOTIFYDUCATIDRIVER_MAKE_MAGICSTAMP(0));
299
 
 
300
 
        /* Finalize the maibox module for Ducati */
301
 
        omap_mbox_put(ducati_mbox, &ducati_notify_nb);
302
 
        ducati_mbox = NULL;
303
 
 
304
 
        /* Finalize the maibox module for Tesla */
305
 
        omap_mbox_put(tesla_mbox, &ducati_notify_nb);
306
 
        tesla_mbox = NULL;
307
 
 
308
 
exit:
309
 
        if (status < 0) {
310
 
                pr_err("notify_ducatidrv_destroy failed! "
311
 
                        "status = 0x%x", status);
312
 
        }
313
 
        return status;
314
 
}
315
 
EXPORT_SYMBOL(notify_ducatidrv_destroy);
316
 
 
317
 
/* Function to initialize the parameters for this notify_ducatidrv instance. */
318
 
void notify_ducatidrv_params_init(struct notify_ducatidrv_params *params)
319
 
{
320
 
        int status = NOTIFY_S_SUCCESS;
321
 
 
322
 
        if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
323
 
                        &(notify_ducatidriver_state.ref_count),
324
 
                        NOTIFYDUCATIDRIVER_MAKE_MAGICSTAMP(0),
325
 
                        NOTIFYDUCATIDRIVER_MAKE_MAGICSTAMP(1)) == true))) {
326
 
                status = NOTIFY_E_INVALIDSTATE;
327
 
                goto exit;
328
 
        }
329
 
        if (WARN_ON(unlikely(params == NULL))) {
330
 
                status = NOTIFY_E_INVALIDARG;
331
 
                goto exit;
332
 
        }
333
 
 
334
 
        /*Return updated notify_ducatidrv instance specific parameters*/
335
 
        memcpy(params, &(notify_ducatidriver_state.def_inst_params),
336
 
                sizeof(struct notify_ducatidrv_params));
337
 
 
338
 
exit:
339
 
        if (status < 0) {
340
 
                pr_err("notify_ducatidrv_params_init failed! "
341
 
                        "status = 0x%x", status);
342
 
        }
343
 
        return;
344
 
}
345
 
EXPORT_SYMBOL(notify_ducatidrv_params_init);
346
 
 
347
 
/* Function to create an instance of this Notify ducati driver. */
348
 
struct notify_ducatidrv_object *notify_ducatidrv_create(
349
 
                                const struct notify_ducatidrv_params *params)
350
 
{
351
 
        int status = NOTIFY_S_SUCCESS;
352
 
        struct notify_ducatidrv_object *obj = NULL;
353
 
        struct notify_driver_object *drv_handle = NULL;
354
 
        struct notify_driver_fxn_table fxn_table;
355
 
        struct omap_mbox *mbox;
356
 
        atomic_t *mbx_cnt;
357
 
        u32 i;
358
 
        u16 region_id;
359
 
        uint region_cache_size;
360
 
        uint min_align;
361
 
        struct notify_ducatidrv_event_entry *event_entry;
362
 
        u32 proc_ctrl_size;
363
 
 
364
 
        if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
365
 
                        &(notify_ducatidriver_state.ref_count),
366
 
                        NOTIFYDUCATIDRIVER_MAKE_MAGICSTAMP(0),
367
 
                        NOTIFYDUCATIDRIVER_MAKE_MAGICSTAMP(1)) == true))) {
368
 
                status = NOTIFY_E_INVALIDSTATE;
369
 
                goto exit;
370
 
        }
371
 
        if (WARN_ON(unlikely(params == NULL))) {
372
 
                status = NOTIFY_E_INVALIDARG;
373
 
                goto exit;
374
 
        }
375
 
        if (WARN_ON(unlikely((params->remote_proc_id == MULTIPROC_INVALIDID)
376
 
                        || (params->remote_proc_id == multiproc_self())))) {
377
 
                status = NOTIFY_E_INVALIDARG;
378
 
                goto exit;
379
 
        }
380
 
        if (WARN_ON(unlikely(params->line_id >= NOTIFY_MAX_INTLINES))) {
381
 
                status = NOTIFY_E_INVALIDARG;
382
 
                goto exit;
383
 
        }
384
 
        if (WARN_ON(unlikely(((u32)params->shared_addr % \
385
 
                (u32) params->cache_line_size)) != 0)) {
386
 
                status = NOTIFY_E_INVALIDARG;
387
 
                goto exit;
388
 
        }
389
 
 
390
 
        if (params->remote_proc_id) {
391
 
                mbox = ducati_mbox;
392
 
                mbx_cnt = &notify_ducatidriver_state.mbox2_ref_count;
393
 
        } else {
394
 
                mbox = tesla_mbox;
395
 
                mbx_cnt = &notify_ducatidriver_state.mbox1_ref_count;
396
 
        }
397
 
 
398
 
        status = mutex_lock_interruptible(
399
 
                                notify_ducatidriver_state.gate_handle);
400
 
        if (status)
401
 
                goto exit;
402
 
 
403
 
        /* Check if driver already exists. */
404
 
        drv_handle = notify_get_driver_handle(params->remote_proc_id,
405
 
                                                params->line_id);
406
 
        if (drv_handle != NULL) {
407
 
                status = NOTIFY_E_ALREADYEXISTS;
408
 
                goto error_unlock_and_return;
409
 
        }
410
 
 
411
 
        /* Function table information */
412
 
        fxn_table.register_event = (void *)&notify_ducatidrv_register_event;
413
 
        fxn_table.unregister_event = (void *)&notify_ducatidrv_unregister_event;
414
 
        fxn_table.send_event = (void *)&notify_ducatidrv_send_event;
415
 
        fxn_table.disable = (void *)&notify_ducatidrv_disable;
416
 
        fxn_table.enable = (void *)&notify_ducatidrv_enable;
417
 
        fxn_table.disable_event = (void *)&notify_ducatidrv_disable_event;
418
 
        fxn_table.enable_event = (void *)&notify_ducatidrv_enable_event;
419
 
 
420
 
        /* Register driver with the Notify module. */
421
 
        status = notify_register_driver(params->remote_proc_id,
422
 
                                        params->line_id, &fxn_table,
423
 
                                        &drv_handle);
424
 
        if (status < 0) {
425
 
                status = NOTIFY_E_FAIL;
426
 
                goto error_clean_and_exit;
427
 
        }
428
 
 
429
 
        /* Allocate memory for the notify_ducatidrv_object object. */
430
 
        obj = kzalloc(sizeof(struct notify_ducatidrv_object), GFP_ATOMIC);
431
 
        if (obj == NULL) {
432
 
                status = NOTIFY_E_MEMORY;
433
 
                goto error_clean_and_exit;
434
 
        }
435
 
        memcpy(&(obj->params), (void *) params,
436
 
                                sizeof(struct notify_ducatidrv_params));
437
 
        obj->num_events = notify_state.cfg.num_events;
438
 
        /* Set the handle in the driverHandles array. */
439
 
        notify_ducatidriver_state.driver_handles
440
 
                [params->remote_proc_id][params->line_id] = obj;
441
 
        /* Point to the generic drvHandle object from this specific
442
 
         * NotifyDriverShm object. */
443
 
        obj->drv_handle = drv_handle;
444
 
 
445
 
        /* Determine obj->cacheEnabled using params->cacheEnabled and
446
 
         * SharedRegion cache flag setting, if applicable. */
447
 
        obj->cache_enabled = params->cache_enabled;
448
 
        min_align = params->cache_line_size;
449
 
        region_id = sharedregion_get_id((void *)params->shared_addr);
450
 
        if (region_id != SHAREDREGION_INVALIDREGIONID) {
451
 
                /* Override the user cacheEnabled setting if the region
452
 
                 * cacheEnabled is FALSE. */
453
 
                if (!sharedregion_is_cache_enabled(region_id))
454
 
                        obj->cache_enabled = false;
455
 
 
456
 
                region_cache_size = sharedregion_get_cache_line_size(region_id);
457
 
 
458
 
                /* Override the user cache line size setting if the region
459
 
                 * cache line size is smaller. */
460
 
                if (region_cache_size < min_align)
461
 
                        min_align = region_cache_size;
462
 
        }
463
 
 
464
 
        if ((u32)params->shared_addr % min_align != 0) {
465
 
                status = NOTIFY_E_FAIL;
466
 
                goto error_clean_and_exit;
467
 
        }
468
 
        obj->remote_proc_id = params->remote_proc_id;
469
 
        obj->nesting = 0;
470
 
        if (params->remote_proc_id > multiproc_self()) {
471
 
                obj->self_id = SELF_ID;
472
 
                obj->other_id = OTHER_ID;
473
 
        } else {
474
 
                obj->self_id  = OTHER_ID;
475
 
                obj->other_id = SELF_ID;
476
 
        }
477
 
 
478
 
        proc_ctrl_size = ROUND_UP(sizeof(struct notify_ducatidrv_proc_ctrl),
479
 
                                min_align);
480
 
 
481
 
        /* Save the eventEntrySize in obj since we will need it at runtime to
482
 
         * index the event charts */
483
 
 
484
 
        obj->event_entry_size = ROUND_UP(
485
 
                                sizeof(struct notify_ducatidrv_event_entry),
486
 
                                min_align);
487
 
        obj->self_proc_ctrl = (struct notify_ducatidrv_proc_ctrl *)
488
 
                                        ((u32) params->shared_addr + \
489
 
                                        (obj->self_id * proc_ctrl_size));
490
 
        obj->other_proc_ctrl = (struct notify_ducatidrv_proc_ctrl *)
491
 
                                        ((u32) params->shared_addr + \
492
 
                                        (obj->other_id * proc_ctrl_size));
493
 
        obj->self_event_chart = (struct notify_ducatidrv_event_entry *)
494
 
                                        ((u32) params->shared_addr + \
495
 
                                        (2 * proc_ctrl_size) + \
496
 
                                        (obj->event_entry_size * \
497
 
                                        obj->num_events * obj->self_id));
498
 
        obj->other_event_chart  = (struct notify_ducatidrv_event_entry *)
499
 
                                        ((u32) params->shared_addr + \
500
 
                                        (2 * proc_ctrl_size) + \
501
 
                                        (obj->event_entry_size * \
502
 
                                        obj->num_events * obj->other_id));
503
 
 
504
 
        for (i = 0; i < obj->num_events; i++)
505
 
                obj->reg_chart[i] = (u32)-1;
506
 
 
507
 
        /* All events initially unflagged */
508
 
        for (i = 0; i < obj->num_events; i++) {
509
 
                event_entry = EVENTENTRY(obj->self_event_chart,
510
 
                                        obj->event_entry_size, i);
511
 
                event_entry->flag = 0;
512
 
        }
513
 
 
514
 
        /* All events initially not registered */
515
 
        obj->self_proc_ctrl->event_reg_mask = 0x0;
516
 
 
517
 
        /* Enable all events initially.*/
518
 
        obj->self_proc_ctrl->event_enable_mask = 0xFFFFFFFF;
519
 
 
520
 
 
521
 
        /*Set up the ISR on the MPU-Ducati FIFO */
522
 
        if (atomic_inc_return(mbx_cnt) == 1)
523
 
                omap_mbox_enable_irq(mbox, IRQ_RX);
524
 
        obj->self_proc_ctrl->recv_init_status = NOTIFYDUCATIDRIVER_INIT_STAMP;
525
 
        obj->self_proc_ctrl->send_init_status = NOTIFYDUCATIDRIVER_INIT_STAMP;
526
 
 
527
 
#if 0
528
 
        /* Write back our own ProcCtrl */
529
 
        if (obj->cache_enabled) {
530
 
                Cache_wbInv((void *) obj->self_proc_ctrl,
531
 
                        sizeof(struct notify_ducatidrv_proc_ctrl),
532
 
                        Cache_Type_ALL, true);
533
 
        }
534
 
#endif
535
 
 
536
 
        drv_handle->is_init = NOTIFY_DRIVERINITSTATUS_DONE;
537
 
        mutex_unlock(notify_ducatidriver_state.gate_handle);
538
 
        return obj;
539
 
 
540
 
error_clean_and_exit:
541
 
        if (obj != NULL) {
542
 
                if (obj->self_proc_ctrl != NULL) {
543
 
                        /* Clear initialization status in shared memory. */
544
 
                        obj->self_proc_ctrl->recv_init_status = 0x0;
545
 
                        obj->self_proc_ctrl->recv_init_status = 0x0;
546
 
                        obj->self_proc_ctrl = NULL;
547
 
#if 0
548
 
                        /* Write back our own ProcCtrl */
549
 
                        if (obj->cache_enabled) {
550
 
                                Cache_wbInv((void *) obj->self_proc_ctrl,
551
 
                                sizeof(struct notify_ducatidrv_proc_ctrl),
552
 
                                Cache_Type_ALL, true);
553
 
                        }
554
 
#endif
555
 
                        kfree(obj);
556
 
                        obj = NULL;
557
 
                }
558
 
        }
559
 
        if (drv_handle != NULL) {
560
 
                /* Unregister driver from the Notify module*/
561
 
                notify_unregister_driver(drv_handle);
562
 
                notify_ducatidriver_state.driver_handles
563
 
                        [params->remote_proc_id][params->line_id] = NULL;
564
 
                drv_handle = NULL;
565
 
        }
566
 
error_unlock_and_return:
567
 
        /* Leave critical section protection. */
568
 
        mutex_unlock(notify_ducatidriver_state.gate_handle);
569
 
exit:
570
 
        pr_err("notify_ducatidrv_create failed! status = 0x%x", status);
571
 
        return NULL;
572
 
}
573
 
EXPORT_SYMBOL(notify_ducatidrv_create);
574
 
 
575
 
/* Function to delete the instance of shared memory driver */
576
 
int notify_ducatidrv_delete(struct notify_ducatidrv_object **handle_ptr)
577
 
{
578
 
        int status = NOTIFY_S_SUCCESS;
579
 
        int tmp_status = NOTIFY_S_SUCCESS;
580
 
        struct notify_ducatidrv_object *obj = NULL;
581
 
        struct omap_mbox *mbox;
582
 
        atomic_t *mbx_cnt;
583
 
 
584
 
        if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
585
 
                        &(notify_ducatidriver_state.ref_count),
586
 
                        NOTIFYDUCATIDRIVER_MAKE_MAGICSTAMP(0),
587
 
                        NOTIFYDUCATIDRIVER_MAKE_MAGICSTAMP(1)) == true))) {
588
 
                status = NOTIFY_E_INVALIDSTATE;
589
 
                goto exit;
590
 
        }
591
 
 
592
 
        if (WARN_ON(unlikely(handle_ptr == NULL))) {
593
 
                status = NOTIFY_E_INVALIDARG;
594
 
                goto exit;
595
 
        }
596
 
        if (WARN_ON(unlikely(*handle_ptr == NULL))) {
597
 
                status = NOTIFY_E_INVALIDARG;
598
 
                goto exit;
599
 
        }
600
 
 
601
 
        obj = (struct notify_ducatidrv_object *)(*handle_ptr);
602
 
        if (obj != NULL) {
603
 
                if (obj->remote_proc_id) {
604
 
                        mbox = ducati_mbox;
605
 
                        mbx_cnt = &notify_ducatidriver_state.mbox2_ref_count;
606
 
                } else {
607
 
                        mbox = tesla_mbox;
608
 
                        mbx_cnt = &notify_ducatidriver_state.mbox1_ref_count;
609
 
                }
610
 
                /* Uninstall the ISRs & Disable the Mailbox interrupt.*/
611
 
                if (atomic_dec_and_test(mbx_cnt))
612
 
                        omap_mbox_disable_irq(mbox, IRQ_RX);
613
 
 
614
 
                if (obj->self_proc_ctrl != NULL) {
615
 
                        /* Clear initialization status in shared memory. */
616
 
                        obj->self_proc_ctrl->recv_init_status = 0x0;
617
 
                        obj->self_proc_ctrl->recv_init_status = 0x0;
618
 
                        obj->self_proc_ctrl = NULL;
619
 
#if 0
620
 
                        /* Write back our own ProcCtrl */
621
 
                        if (obj->cache_enabled) {
622
 
                                Cache_wbInv((void *) obj->self_proc_ctrl,
623
 
                                sizeof(struct notify_ducatidrv_proc_ctrl),
624
 
                                Cache_Type_ALL, true);
625
 
                        }
626
 
#endif
627
 
                }
628
 
 
629
 
                tmp_status = notify_unregister_driver(obj->drv_handle);
630
 
                if (status >= 0 && tmp_status < 0)
631
 
                        status = tmp_status;
632
 
 
633
 
                notify_ducatidriver_state.driver_handles
634
 
                        [obj->params.remote_proc_id][obj->params.line_id] = \
635
 
                                                                        NULL;
636
 
 
637
 
                kfree(obj);
638
 
                obj = NULL;
639
 
        }
640
 
 
641
 
exit:
642
 
        if (status < 0)
643
 
                pr_err("notify_ducatidrv_delete failed! status = 0x%x", status);
644
 
        return status;
645
 
}
646
 
EXPORT_SYMBOL(notify_ducatidrv_delete);
647
 
 
648
 
/* Register a callback for an event with the Notify driver. */
649
 
int notify_ducatidrv_register_event(struct notify_driver_object *handle,
650
 
                                        u32 event_id)
651
 
{
652
 
        int status = NOTIFY_S_SUCCESS;
653
 
        struct notify_ducatidrv_object *obj;
654
 
        VOLATILE struct notify_ducatidrv_event_entry *event_entry;
655
 
        int i;
656
 
        int j;
657
 
 
658
 
        if (WARN_ON(unlikely(handle == NULL))) {
659
 
                status = NOTIFY_E_INVALIDARG;
660
 
                goto exit;
661
 
        }
662
 
        if (WARN_ON(unlikely(handle->is_init != \
663
 
                                        NOTIFY_DRIVERINITSTATUS_DONE))) {
664
 
                status = NOTIFY_E_INVALIDARG;
665
 
                goto exit;
666
 
        }
667
 
        if (WARN_ON(unlikely(handle->notify_handle == NULL))) {
668
 
                status = NOTIFY_E_INVALIDARG;
669
 
                goto exit;
670
 
        }
671
 
        if (WARN_ON(unlikely(handle->notify_handle->driver_handle == NULL))) {
672
 
                status = NOTIFY_E_DRIVERNOTREGISTERED;
673
 
                goto exit;
674
 
        }
675
 
 
676
 
        obj = (struct notify_ducatidrv_object *)
677
 
                                handle->notify_handle->driver_handle;
678
 
        if (WARN_ON(unlikely(obj->reg_chart == NULL))) {
679
 
                status = NOTIFY_E_FAIL;
680
 
                goto exit;
681
 
        }
682
 
 
683
 
        /* This function is only called for the first register, i.e. when the
684
 
         * first callback is being registered. */
685
 
        /* Add an entry for the registered event into the Event Registration
686
 
         * Chart, in ascending order of event numbers (and decreasing
687
 
         * priorities). There is no need to make this atomic since
688
 
         * Notify_exec cannot preempt: shared memory hasn't been modified yet.
689
 
         */
690
 
        for (i = 0 ; i < obj->num_events; i++) {
691
 
                /* Find the correct slot in the registration array. */
692
 
                if (obj->reg_chart[i] == (u32) -1) {
693
 
                        for (j = (i - 1); j >= 0; j--) {
694
 
                                if (event_id < obj->reg_chart[j]) {
695
 
                                        obj->reg_chart[j + 1] = \
696
 
                                                obj->reg_chart[j];
697
 
                                        i = j;
698
 
                                } else {
699
 
                                        /* End the loop, slot found. */
700
 
                                        j = -1;
701
 
                                }
702
 
                        }
703
 
                        obj->reg_chart[i] = event_id;
704
 
                        break;
705
 
                }
706
 
        }
707
 
 
708
 
        /* Clear any pending unserviced event as there are no listeners
709
 
         * for the pending event */
710
 
        event_entry = EVENTENTRY(obj->self_event_chart, obj->event_entry_size,
711
 
                                        event_id);
712
 
        event_entry->flag = NOTIFYDUCATIDRIVER_DOWN;
713
 
 
714
 
        /* Set the registered bit in shared memory and write back */
715
 
        set_bit(event_id, (unsigned long *)
716
 
                        &(obj->self_proc_ctrl->event_reg_mask));
717
 
 
718
 
#if 0
719
 
        /* Write back both the flag and the reg mask */
720
 
        if (obj->cache_enabled) {
721
 
                /* Writeback eventRegMask */
722
 
                Cache_wbInv((void *) obj->self_proc_ctrl,
723
 
                        sizeof(struct notify_ducatidrv_proc_ctrl),
724
 
                        Cache_Type_ALL, true);
725
 
                /* Writeback event entry */
726
 
                Cache_wbInv((void *) event_entry,
727
 
                        sizeof(struct notify_ducatidrv_event_entry),
728
 
                        Cache_Type_ALL, true);
729
 
        }
730
 
#endif
731
 
 
732
 
exit:
733
 
        if (status < 0) {
734
 
                pr_err("notify_ducatidrv_register_event failed! "
735
 
                        "status = 0x%x", status);
736
 
        }
737
 
        return status;
738
 
}
739
 
 
740
 
/* Unregister a callback for an event with the Notify driver. */
741
 
int notify_ducatidrv_unregister_event(struct notify_driver_object *handle,
742
 
                                        u32 event_id)
743
 
{
744
 
        int status = NOTIFY_S_SUCCESS;
745
 
        struct notify_ducatidrv_object *obj;
746
 
        VOLATILE struct notify_ducatidrv_event_entry *event_entry;
747
 
        int i;
748
 
        int j;
749
 
 
750
 
        if (WARN_ON(unlikely(handle == NULL))) {
751
 
                status = NOTIFY_E_INVALIDARG;
752
 
                goto exit;
753
 
        }
754
 
        if (WARN_ON(unlikely(handle->is_init != \
755
 
                                        NOTIFY_DRIVERINITSTATUS_DONE))) {
756
 
                status = NOTIFY_E_INVALIDARG;
757
 
                goto exit;
758
 
        }
759
 
        if (WARN_ON(unlikely(handle->notify_handle == NULL))) {
760
 
                status = NOTIFY_E_INVALIDARG;
761
 
                goto exit;
762
 
        }
763
 
        if (WARN_ON(unlikely(handle->notify_handle->driver_handle == NULL))) {
764
 
                status = NOTIFY_E_DRIVERNOTREGISTERED;
765
 
                goto exit;
766
 
        }
767
 
 
768
 
        obj = (struct notify_ducatidrv_object *)
769
 
                                handle->notify_handle->driver_handle;
770
 
        if (WARN_ON(unlikely(obj->reg_chart == NULL))) {
771
 
                status = NOTIFY_E_FAIL;
772
 
                goto exit;
773
 
        }
774
 
 
775
 
        /* This function is only called for the last unregister, i.e. when the
776
 
         * final remaining callback is being unregistered.
777
 
         * Unset the registered bit in shared memory */
778
 
        clear_bit(event_id, (unsigned long *)
779
 
                        &(obj->self_proc_ctrl->event_reg_mask));
780
 
 
781
 
        /* Clear any pending unserviced event as there are no listeners
782
 
         * for the pending event.  This should be done only after the event
783
 
         * is unregistered from shared memory so the other processor doesn't
784
 
         * successfully send an event our way immediately after unflagging this
785
 
         * event. */
786
 
        event_entry = EVENTENTRY(obj->self_event_chart, obj->event_entry_size,
787
 
                                        event_id);
788
 
        event_entry->flag = NOTIFYDUCATIDRIVER_DOWN;
789
 
 
790
 
#if 0
791
 
        /* Write back both the flag and the reg mask */
792
 
        if (obj->cache_enabled) {
793
 
                /* Writeback event entry */
794
 
                Cache_wbInv((void *) event_entry,
795
 
                        sizeof(struct notify_ducatidrv_event_entry),
796
 
                        Cache_Type_ALL, true);
797
 
                /* Writeback eventRegMask */
798
 
                Cache_wbInv((void *) obj->self_proc_ctrl,
799
 
                        sizeof(struct notify_ducatidrv_proc_ctrl),
800
 
                        Cache_Type_ALL, true);
801
 
        }
802
 
#endif
803
 
 
804
 
        /* Re-arrange eventIds in the Event Registration Chart so there is
805
 
         * no gap caused by the removal of this eventId
806
 
         *
807
 
         * There is no need to make this atomic since Notify_exec cannot
808
 
         * preempt: the event has already been disabled in shared memory
809
 
         * (see above) */
810
 
        for (i = 0 ; i < obj->num_events; i++) {
811
 
                /* Find the correct slot in the registration array. */
812
 
                if (event_id == obj->reg_chart[i]) {
813
 
                        obj->reg_chart[i] = (u32) -1;
814
 
                        for (j = (i + 1); (j != obj->num_events) && \
815
 
                                (obj->reg_chart[j] != (u32)-1); j++) {
816
 
                                obj->reg_chart[j - 1] = obj->reg_chart[j];
817
 
                                obj->reg_chart[j] = (u32)-1;
818
 
                        }
819
 
                        break;
820
 
                }
821
 
        }
822
 
 
823
 
exit:
824
 
        if (status < 0) {
825
 
                pr_err("notify_ducatidrv_unregister_event failed! "
826
 
                        "status = 0x%x", status);
827
 
        }
828
 
        return status;
829
 
}
830
 
 
831
 
/* Send a notification event to the registered users for this
832
 
 * notification on the specified processor. */
833
 
int notify_ducatidrv_send_event(struct notify_driver_object *handle,
834
 
                                u32 event_id, u32 payload, bool wait_clear)
835
 
{
836
 
        int status = NOTIFY_S_SUCCESS;
837
 
        struct notify_ducatidrv_object *obj;
838
 
        struct omap_mbox *mbox;
839
 
        VOLATILE struct notify_ducatidrv_event_entry *event_entry;
840
 
        int max_poll_count;
841
 
        int i = 0;
842
 
        mbox_msg_t msg;
843
 
 
844
 
        if (WARN_ON(unlikely(handle == NULL))) {
845
 
                status = NOTIFY_E_INVALIDARG;
846
 
                goto exit;
847
 
        }
848
 
        if (WARN_ON(unlikely(handle->is_init != \
849
 
                                        NOTIFY_DRIVERINITSTATUS_DONE))) {
850
 
                status = NOTIFY_E_INVALIDARG;
851
 
                goto exit;
852
 
        }
853
 
        if (WARN_ON(unlikely(handle->notify_handle == NULL))) {
854
 
                status = NOTIFY_E_INVALIDARG;
855
 
                goto exit;
856
 
        }
857
 
        if (WARN_ON(unlikely(handle->notify_handle->driver_handle == NULL))) {
858
 
                status = NOTIFY_E_DRIVERNOTREGISTERED;
859
 
                goto exit;
860
 
        }
861
 
 
862
 
        obj = (struct notify_ducatidrv_object *)
863
 
                                handle->notify_handle->driver_handle;
864
 
 
865
 
        mbox = (obj->remote_proc_id) ? ducati_mbox : tesla_mbox;
866
 
        if (WARN_ON(unlikely(obj->reg_chart == NULL))) {
867
 
                status = NOTIFY_E_FAIL;
868
 
                goto exit;
869
 
        }
870
 
 
871
 
        dsb();
872
 
        event_entry = EVENTENTRY(obj->other_event_chart, obj->event_entry_size,
873
 
                                        event_id);
874
 
#if 0
875
 
        /* Invalidate cache for the other processor's procCtrl. */
876
 
        if (obj->cache_enabled) {
877
 
                Cache_wbInv((void *) obj->other_proc_ctrl,
878
 
                        sizeof(struct notify_ducatidrv_proc_ctrl),
879
 
                        Cache_Type_ALL, true);
880
 
        }
881
 
#endif
882
 
        max_poll_count = notify_state.cfg.send_event_poll_count;
883
 
 
884
 
        /* Check whether driver on other processor is initialized */
885
 
        if (obj->other_proc_ctrl->recv_init_status != \
886
 
                                        NOTIFYDUCATIDRIVER_INIT_STAMP) {
887
 
                /* This may be used for polling till other-side driver is ready,
888
 
                 * so do not set failure reason. */
889
 
                status = NOTIFY_E_NOTINITIALIZED;
890
 
                goto exit;
891
 
        }
892
 
        /* Check if other side has registered to receive this event. */
893
 
        if (!test_bit(event_id, (unsigned long *)
894
 
                                &obj->other_proc_ctrl->event_reg_mask)) {
895
 
                status = NOTIFY_E_EVTNOTREGISTERED;
896
 
                /* This may be used for polling till other-side is ready, so
897
 
                * do not set failure reason. */
898
 
                goto exit;
899
 
        }
900
 
        if (!test_bit(event_id, (unsigned long *)
901
 
                                &obj->other_proc_ctrl->event_enable_mask)) {
902
 
                status = NOTIFY_E_EVTDISABLED;
903
 
                /* This may be used for polling till other-side is ready, so
904
 
                * do not set failure reason. */
905
 
                goto exit;
906
 
        }
907
 
#if 0
908
 
        if (obj->cache_enabled) {
909
 
                Cache_inv((void *)event_entry,
910
 
                        sizeof(struct notify_ducatidrv_event_entry),
911
 
                        Cache_Type_ALL, TRUE);
912
 
        }
913
 
#endif
914
 
        dsb();
915
 
        status = mutex_lock_interruptible(
916
 
                                notify_ducatidriver_state.gate_handle);
917
 
        if (status)
918
 
                goto exit;
919
 
 
920
 
        if (wait_clear == true) {
921
 
                /*Wait for completion of prev
922
 
                event from other side*/
923
 
                while ((event_entry->flag != NOTIFYDUCATIDRIVER_DOWN) && \
924
 
                        (status >= 0)) {
925
 
                        /* Leave critical section protection. Create a window
926
 
                         * of opportunity for other interrupts to be handled.*/
927
 
                        mutex_unlock(notify_ducatidriver_state.gate_handle);
928
 
                        i++;
929
 
                        if ((max_poll_count != (u32)-1) && \
930
 
                                (i == max_poll_count)) {
931
 
                                status = NOTIFY_E_TIMEOUT;
932
 
                                break;
933
 
                        }
934
 
 
935
 
#if 0
936
 
                        if (obj->cache_enabled) {
937
 
                                Cache_inv((void *)event_entry,
938
 
                                sizeof(struct notify_ducatidrv_event_entry),
939
 
                                Cache_Type_ALL, TRUE);
940
 
                        }
941
 
#endif
942
 
                        dsb();
943
 
 
944
 
                        /* Enter critical section protection. */
945
 
                        status = mutex_lock_interruptible(
946
 
                                        notify_ducatidriver_state.gate_handle);
947
 
                }
948
 
        }
949
 
 
950
 
        if (status >= 0) {
951
 
                /* Set the event bit field and payload. */
952
 
                event_entry->payload = payload;
953
 
                event_entry->flag = NOTIFYDUCATIDRIVER_UP;
954
 
 
955
 
#if 0
956
 
                if (obj->cache_enabled) {
957
 
                        Cache_inv((void *)event_entry,
958
 
                        sizeof(struct notify_ducatidrv_event_entry),
959
 
                        Cache_Type_ALL, TRUE);
960
 
                }
961
 
#endif
962
 
                dsb();
963
 
 
964
 
                /* Send an interrupt with the event information to the
965
 
                 * remote processor */
966
 
                msg = ((obj->remote_proc_id << 16) | event_id);
967
 
                status = omap_mbox_msg_send(mbox, msg);
968
 
 
969
 
                /* Leave critical section protection. */
970
 
                mutex_unlock(notify_ducatidriver_state.gate_handle);
971
 
        }
972
 
 
973
 
exit:
974
 
        if (status < 0) {
975
 
                pr_err("notify_ducatidrv_sendevent failed! "
976
 
                        "status = 0x%x", status);
977
 
        }
978
 
        return status;
979
 
}
980
 
 
981
 
/* Disable all events for this Notify driver.*/
982
 
int notify_ducatidrv_disable(struct notify_driver_object *handle)
983
 
{
984
 
        int status = NOTIFY_S_SUCCESS;
985
 
        struct notify_ducatidrv_object *obj;
986
 
        struct omap_mbox *mbox;
987
 
 
988
 
        /* All the below parameter checking is unnecessary, but added to
989
 
         * make sure the driver object is initialized properly */
990
 
        if (WARN_ON(unlikely(handle == NULL))) {
991
 
                status = NOTIFY_E_INVALIDARG;
992
 
                goto exit;
993
 
        }
994
 
        if (WARN_ON(unlikely(handle->is_init != \
995
 
                                        NOTIFY_DRIVERINITSTATUS_DONE))) {
996
 
                status = NOTIFY_E_INVALIDARG;
997
 
                goto exit;
998
 
        }
999
 
        if (WARN_ON(unlikely(handle->notify_handle == NULL))) {
1000
 
                status = NOTIFY_E_INVALIDARG;
1001
 
                goto exit;
1002
 
        }
1003
 
        if (WARN_ON(unlikely(handle->notify_handle->driver_handle == NULL))) {
1004
 
                status = NOTIFY_E_DRIVERNOTREGISTERED;
1005
 
                goto exit;
1006
 
        }
1007
 
 
1008
 
        obj = (struct notify_ducatidrv_object *)
1009
 
                                handle->notify_handle->driver_handle;
1010
 
 
1011
 
        mbox = (obj->remote_proc_id) ? ducati_mbox : tesla_mbox;
1012
 
        if (WARN_ON(unlikely(obj->reg_chart == NULL))) {
1013
 
                status = NOTIFY_E_FAIL;
1014
 
                goto exit;
1015
 
        }
1016
 
 
1017
 
        /* Disable the mailbox interrupt associated with ducati mailbox */
1018
 
        omap_mbox_disable_irq(mbox, IRQ_RX);
1019
 
 
1020
 
exit:
1021
 
        if (status < 0) {
1022
 
                pr_err("notify_ducatidrv_disable failed! "
1023
 
                        "status = 0x%x", status);
1024
 
        }
1025
 
        /*No flags to be returned. */
1026
 
        return 0;
1027
 
}
1028
 
 
1029
 
/* Restore the notify_ducatidrv to the state before the last disable was
1030
 
 * called. */
1031
 
void notify_ducatidrv_enable(struct notify_driver_object *handle)
1032
 
{
1033
 
        int status = NOTIFY_S_SUCCESS;
1034
 
        struct notify_ducatidrv_object *obj;
1035
 
        struct omap_mbox *mbox;
1036
 
 
1037
 
        /* All the below parameter checking is unnecessary, but added to
1038
 
         * make sure the driver object is initialized properly */
1039
 
        if (WARN_ON(unlikely(handle == NULL))) {
1040
 
                status = NOTIFY_E_INVALIDARG;
1041
 
                goto exit;
1042
 
        }
1043
 
        if (WARN_ON(unlikely(handle->is_init != \
1044
 
                                        NOTIFY_DRIVERINITSTATUS_DONE))) {
1045
 
                status = NOTIFY_E_INVALIDARG;
1046
 
                goto exit;
1047
 
        }
1048
 
        if (WARN_ON(unlikely(handle->notify_handle == NULL))) {
1049
 
                status = NOTIFY_E_INVALIDARG;
1050
 
                goto exit;
1051
 
        }
1052
 
        if (WARN_ON(unlikely(handle->notify_handle->driver_handle == NULL))) {
1053
 
                status = NOTIFY_E_DRIVERNOTREGISTERED;
1054
 
                goto exit;
1055
 
        }
1056
 
 
1057
 
        obj = (struct notify_ducatidrv_object *)
1058
 
                                handle->notify_handle->driver_handle;
1059
 
 
1060
 
        mbox = (obj->remote_proc_id) ? ducati_mbox : tesla_mbox;
1061
 
        if (WARN_ON(unlikely(obj->reg_chart == NULL))) {
1062
 
                status = NOTIFY_E_FAIL;
1063
 
                goto exit;
1064
 
        }
1065
 
 
1066
 
        /*Enable the receive interrupt for ducati */
1067
 
        omap_mbox_enable_irq(mbox, IRQ_RX);
1068
 
 
1069
 
exit:
1070
 
        if (status < 0) {
1071
 
                pr_err("notify_ducatidrv_enable failed! "
1072
 
                        "status = 0x%x", status);
1073
 
        }
1074
 
        return;
1075
 
}
1076
 
 
1077
 
/* Disable a specific event for this Notify ducati driver */
1078
 
void notify_ducatidrv_disable_event(struct notify_driver_object *handle,
1079
 
                                        u32 event_id)
1080
 
{
1081
 
        int status = NOTIFY_S_SUCCESS;
1082
 
        struct notify_ducatidrv_object *obj;
1083
 
        VOLATILE struct notify_ducatidrv_event_entry *event_entry;
1084
 
 
1085
 
        if (WARN_ON(unlikely(handle == NULL))) {
1086
 
                status = NOTIFY_E_INVALIDARG;
1087
 
                goto exit;
1088
 
        }
1089
 
        if (WARN_ON(unlikely(handle->is_init != \
1090
 
                                        NOTIFY_DRIVERINITSTATUS_DONE))) {
1091
 
                status = NOTIFY_E_INVALIDARG;
1092
 
                goto exit;
1093
 
        }
1094
 
        if (WARN_ON(unlikely(handle->notify_handle == NULL))) {
1095
 
                status = NOTIFY_E_INVALIDARG;
1096
 
                goto exit;
1097
 
        }
1098
 
        if (WARN_ON(unlikely(handle->notify_handle->driver_handle == NULL))) {
1099
 
                status = NOTIFY_E_DRIVERNOTREGISTERED;
1100
 
                goto exit;
1101
 
        }
1102
 
 
1103
 
        obj = (struct notify_ducatidrv_object *)
1104
 
                handle->notify_handle->driver_handle;
1105
 
        if (event_id > obj->num_events) {
1106
 
                status = NOTIFY_E_FAIL;
1107
 
                goto exit;
1108
 
        }
1109
 
 
1110
 
        /* Enter critical section protection. */
1111
 
        status = mutex_lock_interruptible(
1112
 
                                        notify_ducatidriver_state.gate_handle);
1113
 
        if (status)
1114
 
                goto exit;
1115
 
        clear_bit(event_id, (unsigned long *)
1116
 
                        &(obj->self_proc_ctrl->event_enable_mask));
1117
 
        /* Leave critical section protection. */
1118
 
        mutex_unlock(notify_ducatidriver_state.gate_handle);
1119
 
#if 0
1120
 
        if (obj->cache_enabled) {
1121
 
                /* Writeback event_enable_mask */
1122
 
                Cache_wbInv((void *) obj->self_proc_ctrl,
1123
 
                        sizeof(struct notify_ducatidrv_proc_ctrl),
1124
 
                        Cache_Type_ALL, true);
1125
 
        }
1126
 
#endif
1127
 
 
1128
 
        event_entry = EVENTENTRY(obj->self_event_chart, obj->event_entry_size,
1129
 
                                        event_id)
1130
 
#if 0
1131
 
        if (obj->cache_enabled) {
1132
 
                /* Writeback event entry */
1133
 
                Cache_wbInv((void *) event_entry,
1134
 
                        sizeof(struct notify_ducatidrv_event_entry),
1135
 
                        Cache_Type_ALL, true);
1136
 
        }
1137
 
#endif
1138
 
 
1139
 
        /* Disable incoming Notify interrupts.  This is done to ensure that the
1140
 
         * eventEntry->flag is read atomically with any write back to shared
1141
 
         * memory */
1142
 
        notify_ducatidrv_disable(handle);
1143
 
 
1144
 
        /* Is the local notify_ducatidrv_disable_event happening between the
1145
 
         * following two notify_ducatidrv_send_event operations on the remote
1146
 
         * processor?
1147
 
         * 1. Writing notify_ducatidrv_UP to shared memory
1148
 
         * 2. Sending the interrupt across
1149
 
         * If so, we should handle this event so the other core isn't left
1150
 
         * spinning until the event is re-enabled and the next
1151
 
         * notify_ducatidrv_isr executes This race condition is very rare but we
1152
 
         * need to account for it: */
1153
 
        if (event_entry->flag == NOTIFYDUCATIDRIVER_UP) {
1154
 
                /* Acknowledge the event. No need to store the payload. The
1155
 
                 * other side will not send this event again even though flag is
1156
 
                 * down, because the event is now disabled. So the payload
1157
 
                 * within the eventChart will not get overwritten. */
1158
 
                event_entry->flag = NOTIFYDUCATIDRIVER_DOWN;
1159
 
#if 0
1160
 
                /* Write back acknowledgement */
1161
 
                if (obj->cache_enabled) {
1162
 
                        Cache_wbInv(event_entry,
1163
 
                                sizeof(struct notify_ducatidrv_event_entry),
1164
 
                                Cache_Type_ALL, TRUE);
1165
 
                }
1166
 
#endif
1167
 
                /* Execute the callback function. This will execute in a Task
1168
 
                 * or Swi context (not Hwi!) */
1169
 
                notify_exec(obj->drv_handle->notify_handle, event_id,
1170
 
                        event_entry->payload);
1171
 
        }
1172
 
 
1173
 
        /* Re-enable incoming Notify interrupts */
1174
 
        notify_ducatidrv_enable(handle);
1175
 
 
1176
 
exit:
1177
 
        if (status < 0) {
1178
 
                pr_err("notify_ducatidrv_disable_event failed! "
1179
 
                        "status = 0x%x", status);
1180
 
        }
1181
 
        return;
1182
 
}
1183
 
 
1184
 
/* Enable a specific event for this Notify ducati driver */
1185
 
void notify_ducatidrv_enable_event(struct notify_driver_object *handle,
1186
 
                                                                u32 event_id)
1187
 
{
1188
 
        int status = 0;
1189
 
        struct notify_ducatidrv_object *obj;
1190
 
 
1191
 
        if (WARN_ON(unlikely(handle == NULL))) {
1192
 
                status = NOTIFY_E_INVALIDARG;
1193
 
                goto exit;
1194
 
        }
1195
 
        if (WARN_ON(unlikely(handle->is_init != \
1196
 
                                        NOTIFY_DRIVERINITSTATUS_DONE))) {
1197
 
                status = NOTIFY_E_INVALIDARG;
1198
 
                goto exit;
1199
 
        }
1200
 
        if (WARN_ON(unlikely(handle->notify_handle == NULL))) {
1201
 
                status = NOTIFY_E_INVALIDARG;
1202
 
                goto exit;
1203
 
        }
1204
 
        if (WARN_ON(unlikely(handle->notify_handle->driver_handle == NULL))) {
1205
 
                status = NOTIFY_E_DRIVERNOTREGISTERED;
1206
 
                goto exit;
1207
 
        }
1208
 
 
1209
 
        obj = (struct notify_ducatidrv_object *)
1210
 
                handle->notify_handle->driver_handle;
1211
 
        if (event_id > obj->num_events) {
1212
 
                status = NOTIFY_E_FAIL;
1213
 
                goto exit;
1214
 
        }
1215
 
 
1216
 
        /* Enter critical section protection. */
1217
 
        status = mutex_lock_interruptible(
1218
 
                                        notify_ducatidriver_state.gate_handle);
1219
 
        if (status)
1220
 
                goto exit;
1221
 
        set_bit(event_id, (unsigned long *)
1222
 
                        &(obj->self_proc_ctrl->event_enable_mask));
1223
 
        /* Leave critical section protection. */
1224
 
        mutex_unlock(notify_ducatidriver_state.gate_handle);
1225
 
#if 0
1226
 
        if (obj->cache_enabled) {
1227
 
                /* Writeback event_enable_mask */
1228
 
                Cache_wbInv((void *) obj->self_proc_ctrl,
1229
 
                        sizeof(struct notify_ducatidrv_proc_ctrl),
1230
 
                        Cache_Type_ALL, true);
1231
 
        }
1232
 
#endif
1233
 
 
1234
 
exit:
1235
 
        if (status < 0) {
1236
 
                pr_err("notify_ducatidrv_enable_event failed! "
1237
 
                        "status = 0x%x", status);
1238
 
        }
1239
 
        return;
1240
 
}
1241
 
 
1242
 
/* Get the shared memory requirements for the notify_ducatidrv. */
1243
 
uint notify_ducatidrv_shared_mem_req(
1244
 
                                const struct notify_ducatidrv_params *params)
1245
 
{
1246
 
        uint mem_req = 0;
1247
 
        u16 region_id;
1248
 
        uint region_cache_size;
1249
 
        uint min_align;
1250
 
        s32 status = NOTIFY_S_SUCCESS;
1251
 
 
1252
 
        if (WARN_ON(unlikely(atomic_cmpmask_and_lt(
1253
 
                        &(notify_ducatidriver_state.ref_count),
1254
 
                        NOTIFYDUCATIDRIVER_MAKE_MAGICSTAMP(0),
1255
 
                        NOTIFYDUCATIDRIVER_MAKE_MAGICSTAMP(1)) == true))) {
1256
 
                status = NOTIFY_E_INVALIDSTATE;
1257
 
                goto exit;
1258
 
        }
1259
 
        if (WARN_ON(unlikely(params == NULL))) {
1260
 
                status = NOTIFY_E_INVALIDARG;
1261
 
                goto exit;
1262
 
        }
1263
 
 
1264
 
        /* Determine obj->cache_enabled using params->cache_enabled and
1265
 
         * sharedregion cache flag setting, if applicable. */
1266
 
        min_align = params->cache_line_size;
1267
 
        region_id = sharedregion_get_id((void *) params->shared_addr);
1268
 
        if (region_id != SHAREDREGION_INVALIDREGIONID) {
1269
 
                region_cache_size = sharedregion_get_cache_line_size(region_id);
1270
 
 
1271
 
                /* Override the user cache line size setting if the region
1272
 
                 * cache line size is smaller. */
1273
 
                if (region_cache_size < min_align)
1274
 
                        min_align = region_cache_size;
1275
 
        }
1276
 
 
1277
 
        /* Determine obj->eventEntrySize which will be used to ROUND_UP
1278
 
         * addresses */
1279
 
        mem_req = ((ROUND_UP(sizeof(struct notify_ducatidrv_proc_ctrl),
1280
 
                        min_align)) * 2) + \
1281
 
                        ((ROUND_UP(sizeof(struct notify_ducatidrv_event_entry),
1282
 
                        min_align) * 2 * notify_state.cfg.num_events));
1283
 
 
1284
 
exit:
1285
 
        if (status < 0) {
1286
 
                pr_err("notify_ducatidrv_shared_mem_req failed!"
1287
 
                        " status = 0x%x", status);
1288
 
        }
1289
 
        return mem_req;
1290
 
}
1291
 
 
1292
 
/* This function implements the interrupt service routine for the interrupt
1293
 
 * received from the Ducati processor. */
1294
 
static int notify_shmdrv_isr(struct notifier_block *nb, unsigned long val,
1295
 
                                                                void *ntfy_msg)
1296
 
{
1297
 
        /* Decode the msg to identify the processor that has sent the message */
1298
 
        u32 proc_id = (u32)ntfy_msg;
1299
 
 
1300
 
        /* Call the corresponding prpc_id callback */
1301
 
        notify_shmdrv_isr_callback(notify_ducatidriver_state.driver_handles
1302
 
                [proc_id][0], ntfy_msg);
1303
 
 
1304
 
        return 0;
1305
 
}
1306
 
EXPORT_SYMBOL(notify_shmdrv_isr);
1307
 
 
1308
 
static bool notify_shmdrv_isr_callback(void *ref_data, void *notify_msg)
1309
 
{
1310
 
        u32 payload = 0;
1311
 
        u32 i = 0;
1312
 
        VOLATILE struct notify_ducatidrv_event_entry  *event_entry;
1313
 
        struct notify_ducatidrv_object *obj;
1314
 
        u32 event_id;
1315
 
 
1316
 
        obj = (struct notify_ducatidrv_object *) ref_data;
1317
 
 
1318
 
        dsb();
1319
 
        /* Execute the loop till no asserted event is found for one complete
1320
 
         * loop through all registered events */
1321
 
        do {
1322
 
                /* Check if the entry is a valid registered event.*/
1323
 
                event_id = obj->reg_chart[i];
1324
 
                if (event_id == (u32) -1)
1325
 
                        break;
1326
 
 
1327
 
                event_entry = EVENTENTRY(obj->self_event_chart,
1328
 
                                        obj->event_entry_size, event_id);
1329
 
#if 0
1330
 
                if (obj->cache_enabled) {
1331
 
                        Cache_inv((void *)event_entry,
1332
 
                        sizeof(struct notify_ducatidrv_event_entry),
1333
 
                        Cache_Type_ALL, TRUE);
1334
 
                }
1335
 
#endif
1336
 
                dsb();
1337
 
 
1338
 
                /* Determine the current high priority event.*/
1339
 
                /* Check if the event is set and enabled.*/
1340
 
                if (event_entry->flag == NOTIFYDUCATIDRIVER_UP &&
1341
 
                        test_bit(event_id, (unsigned long *)
1342
 
                                &obj->self_proc_ctrl->event_enable_mask)) {
1343
 
                        payload = event_entry->payload;
1344
 
 
1345
 
                        /* Acknowledge the event. */
1346
 
                        event_entry->flag = NOTIFYDUCATIDRIVER_DOWN;
1347
 
 
1348
 
                        /* Write back acknowledgement */
1349
 
#if 0
1350
 
                        if (obj->cache_enabled) {
1351
 
                                Cache_inv((void *)event_entry,
1352
 
                                sizeof(struct notify_ducatidrv_event_entry),
1353
 
                                Cache_Type_ALL, TRUE);
1354
 
                        }
1355
 
#endif
1356
 
                        dsb();
1357
 
 
1358
 
                        /* Execute the callback function */
1359
 
                        notify_exec(obj->drv_handle->notify_handle, event_id,
1360
 
                                        payload);
1361
 
                        /* reinitialize the event check counter. */
1362
 
                        i = 0;
1363
 
                } else {
1364
 
                        /* check for next event. */
1365
 
                        i++;
1366
 
                }
1367
 
        } while ((event_id != (u32) -1) && (i < obj->num_events));
1368
 
 
1369
 
        return true;
1370
 
}