4
* Syslink driver support functions for TI OMAP processors.
6
* Copyright (C) 2008-2009 Texas Instruments, Inc.
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.
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.
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>
25
#include <linux/module.h>
26
#include <linux/slab.h>
27
#include <plat/mailbox.h>
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>
39
#define NOTIFYDUCATIDRIVER_MEM_ALIGN 0
41
#define NOTIFYDUCATIDRIVER_MAX_EVENTS 32
43
#define NOTIFYNONSHMDRV_MAX_EVENTS 1
45
#define NOTIFYNONSHMDRV_RESERVED_EVENTS 1
47
#define NOTIFYDRV_DUCATI_RECV_MBX 2
49
#define NOTIFYDRV_DUCATI_SEND_MBX 3
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)));
56
/* Stamp indicating that the Notify Shared Memory driver on the
57
* processor has been initialized. */
58
#define NOTIFYDUCATIDRIVER_INIT_STAMP 0xA9C8B7D6
60
/* Flag indicating event is set. */
61
#define NOTIFYDUCATIDRIVER_UP 1
63
/* Flag indicating event is not set. */
64
#define NOTIFYDUCATIDRIVER_DOWN 0
66
/*FIX ME: Make use of Multi Proc module */
76
#define MAX_SUBPROC_EVENTS 15
78
/* Macro to make a correct module magic number with refCount */
79
#define NOTIFYDUCATIDRIVER_MAKE_MAGICSTAMP(x) \
80
((NOTIFY_DUCATIDRIVER_MODULEID << 12u) | (x))
82
#define ROUND_UP(a, b) (((a) + ((b) - 1)) & (~((b) - 1)))
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);
90
/* Defines the notify_ducatidrv state object, which contains all
91
* the module specific information. */
92
struct notify_ducatidrv_module {
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 */
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. */
127
/* Self ID used for identification of local control region */
129
/* Other ID used for identification of remote control region */
131
/* Processor ID of the remote processor which which this driver instance
133
struct notify_driver_object *drv_handle;
134
/* Common NotifyDriver handle */
136
/* For disable/restore nesting */
138
/* Whether to perform cache calls */
139
u32 event_entry_size;
140
/* Spacing between event entries */
142
/* Number of events configured */
146
static struct notify_ducatidrv_module notify_ducatidriver_state = {
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
157
static struct notifier_block ducati_notify_nb = {
158
.notifier_call = notify_shmdrv_isr,
161
/* Get the default configuration for the notify_ducatidrv module. */
162
void notify_ducatidrv_get_config(struct notify_ducatidrv_config *cfg)
164
int status = NOTIFY_S_SUCCESS;
166
if (WARN_ON(unlikely(cfg == NULL))) {
167
status = NOTIFY_E_INVALIDARG;
171
if (atomic_cmpmask_and_lt(&(notify_ducatidriver_state.ref_count),
172
NOTIFYDUCATIDRIVER_MAKE_MAGICSTAMP(0),
173
NOTIFYDUCATIDRIVER_MAKE_MAGICSTAMP(1))
175
memcpy(cfg, &(notify_ducatidriver_state.def_cfg),
176
sizeof(struct notify_ducatidrv_config));
178
memcpy(cfg, &(notify_ducatidriver_state.cfg),
179
sizeof(struct notify_ducatidrv_config));
183
pr_err("notify_ducatidrv_get_config failed! "
184
"status = 0x%x", status);
188
EXPORT_SYMBOL(notify_ducatidrv_get_config);
190
/* Setup the notify_ducatidrv module. */
191
int notify_ducatidrv_setup(struct notify_ducatidrv_config *cfg)
194
struct notify_ducatidrv_config tmp_cfg;
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;
206
atomic_set(&(notify_ducatidriver_state.mbox2_ref_count), 0);
207
atomic_set(&(notify_ducatidriver_state.mbox1_ref_count), 0);
210
notify_ducatidrv_get_config(&tmp_cfg);
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;
221
mutex_init(notify_ducatidriver_state.gate_handle);
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;
227
memcpy(¬ify_ducatidriver_state.cfg, cfg,
228
sizeof(struct notify_ducatidrv_config));
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;
240
/* Initialize the maibox module for Tesla */
242
tesla_mbox = omap_mbox_get("mailbox-1", &ducati_notify_nb);
244
pr_err("Failed in omap_mbox_get(tesla)\n");
245
status = NOTIFY_E_INVALIDSTATE;
246
goto error_mailbox_get_failed;
251
error_mailbox_get_failed:
252
kfree(notify_ducatidriver_state.gate_handle);
254
atomic_set(&(notify_ducatidriver_state.ref_count),
255
NOTIFYDUCATIDRIVER_MAKE_MAGICSTAMP(0));
256
pr_err("notify_ducatidrv_setup failed! status = 0x%x", status);
259
EXPORT_SYMBOL(notify_ducatidrv_setup);
261
/* Destroy the notify_ducatidrv module. */
262
int notify_ducatidrv_destroy(void)
264
int status = NOTIFY_S_SUCCESS;
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;
275
if (!(atomic_dec_return(¬ify_ducatidriver_state.ref_count) == \
276
NOTIFYDUCATIDRIVER_MAKE_MAGICSTAMP(0)))
277
return NOTIFY_S_ALREADYSETUP;
279
/* Temporarily increment the refcount */
280
atomic_set(&(notify_ducatidriver_state.ref_count),
281
NOTIFYDUCATIDRIVER_MAKE_MAGICSTAMP(1));
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] != \
287
notify_ducatidrv_delete(
288
¬ify_ducatidriver_state.\
289
driver_handles[i][j]);
294
if (notify_ducatidriver_state.gate_handle != NULL)
295
kfree(notify_ducatidriver_state.gate_handle);
297
atomic_set(&(notify_ducatidriver_state.ref_count),
298
NOTIFYDUCATIDRIVER_MAKE_MAGICSTAMP(0));
300
/* Finalize the maibox module for Ducati */
301
omap_mbox_put(ducati_mbox, &ducati_notify_nb);
304
/* Finalize the maibox module for Tesla */
305
omap_mbox_put(tesla_mbox, &ducati_notify_nb);
310
pr_err("notify_ducatidrv_destroy failed! "
311
"status = 0x%x", status);
315
EXPORT_SYMBOL(notify_ducatidrv_destroy);
317
/* Function to initialize the parameters for this notify_ducatidrv instance. */
318
void notify_ducatidrv_params_init(struct notify_ducatidrv_params *params)
320
int status = NOTIFY_S_SUCCESS;
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;
329
if (WARN_ON(unlikely(params == NULL))) {
330
status = NOTIFY_E_INVALIDARG;
334
/*Return updated notify_ducatidrv instance specific parameters*/
335
memcpy(params, &(notify_ducatidriver_state.def_inst_params),
336
sizeof(struct notify_ducatidrv_params));
340
pr_err("notify_ducatidrv_params_init failed! "
341
"status = 0x%x", status);
345
EXPORT_SYMBOL(notify_ducatidrv_params_init);
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)
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;
359
uint region_cache_size;
361
struct notify_ducatidrv_event_entry *event_entry;
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;
371
if (WARN_ON(unlikely(params == NULL))) {
372
status = NOTIFY_E_INVALIDARG;
375
if (WARN_ON(unlikely((params->remote_proc_id == MULTIPROC_INVALIDID)
376
|| (params->remote_proc_id == multiproc_self())))) {
377
status = NOTIFY_E_INVALIDARG;
380
if (WARN_ON(unlikely(params->line_id >= NOTIFY_MAX_INTLINES))) {
381
status = NOTIFY_E_INVALIDARG;
384
if (WARN_ON(unlikely(((u32)params->shared_addr % \
385
(u32) params->cache_line_size)) != 0)) {
386
status = NOTIFY_E_INVALIDARG;
390
if (params->remote_proc_id) {
392
mbx_cnt = ¬ify_ducatidriver_state.mbox2_ref_count;
395
mbx_cnt = ¬ify_ducatidriver_state.mbox1_ref_count;
398
status = mutex_lock_interruptible(
399
notify_ducatidriver_state.gate_handle);
403
/* Check if driver already exists. */
404
drv_handle = notify_get_driver_handle(params->remote_proc_id,
406
if (drv_handle != NULL) {
407
status = NOTIFY_E_ALREADYEXISTS;
408
goto error_unlock_and_return;
411
/* Function table information */
412
fxn_table.register_event = (void *)¬ify_ducatidrv_register_event;
413
fxn_table.unregister_event = (void *)¬ify_ducatidrv_unregister_event;
414
fxn_table.send_event = (void *)¬ify_ducatidrv_send_event;
415
fxn_table.disable = (void *)¬ify_ducatidrv_disable;
416
fxn_table.enable = (void *)¬ify_ducatidrv_enable;
417
fxn_table.disable_event = (void *)¬ify_ducatidrv_disable_event;
418
fxn_table.enable_event = (void *)¬ify_ducatidrv_enable_event;
420
/* Register driver with the Notify module. */
421
status = notify_register_driver(params->remote_proc_id,
422
params->line_id, &fxn_table,
425
status = NOTIFY_E_FAIL;
426
goto error_clean_and_exit;
429
/* Allocate memory for the notify_ducatidrv_object object. */
430
obj = kzalloc(sizeof(struct notify_ducatidrv_object), GFP_ATOMIC);
432
status = NOTIFY_E_MEMORY;
433
goto error_clean_and_exit;
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;
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;
456
region_cache_size = sharedregion_get_cache_line_size(region_id);
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;
464
if ((u32)params->shared_addr % min_align != 0) {
465
status = NOTIFY_E_FAIL;
466
goto error_clean_and_exit;
468
obj->remote_proc_id = params->remote_proc_id;
470
if (params->remote_proc_id > multiproc_self()) {
471
obj->self_id = SELF_ID;
472
obj->other_id = OTHER_ID;
474
obj->self_id = OTHER_ID;
475
obj->other_id = SELF_ID;
478
proc_ctrl_size = ROUND_UP(sizeof(struct notify_ducatidrv_proc_ctrl),
481
/* Save the eventEntrySize in obj since we will need it at runtime to
482
* index the event charts */
484
obj->event_entry_size = ROUND_UP(
485
sizeof(struct notify_ducatidrv_event_entry),
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));
504
for (i = 0; i < obj->num_events; i++)
505
obj->reg_chart[i] = (u32)-1;
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;
514
/* All events initially not registered */
515
obj->self_proc_ctrl->event_reg_mask = 0x0;
517
/* Enable all events initially.*/
518
obj->self_proc_ctrl->event_enable_mask = 0xFFFFFFFF;
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;
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);
536
drv_handle->is_init = NOTIFY_DRIVERINITSTATUS_DONE;
537
mutex_unlock(notify_ducatidriver_state.gate_handle);
540
error_clean_and_exit:
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;
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);
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;
566
error_unlock_and_return:
567
/* Leave critical section protection. */
568
mutex_unlock(notify_ducatidriver_state.gate_handle);
570
pr_err("notify_ducatidrv_create failed! status = 0x%x", status);
573
EXPORT_SYMBOL(notify_ducatidrv_create);
575
/* Function to delete the instance of shared memory driver */
576
int notify_ducatidrv_delete(struct notify_ducatidrv_object **handle_ptr)
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;
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;
592
if (WARN_ON(unlikely(handle_ptr == NULL))) {
593
status = NOTIFY_E_INVALIDARG;
596
if (WARN_ON(unlikely(*handle_ptr == NULL))) {
597
status = NOTIFY_E_INVALIDARG;
601
obj = (struct notify_ducatidrv_object *)(*handle_ptr);
603
if (obj->remote_proc_id) {
605
mbx_cnt = ¬ify_ducatidriver_state.mbox2_ref_count;
608
mbx_cnt = ¬ify_ducatidriver_state.mbox1_ref_count;
610
/* Uninstall the ISRs & Disable the Mailbox interrupt.*/
611
if (atomic_dec_and_test(mbx_cnt))
612
omap_mbox_disable_irq(mbox, IRQ_RX);
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;
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);
629
tmp_status = notify_unregister_driver(obj->drv_handle);
630
if (status >= 0 && tmp_status < 0)
633
notify_ducatidriver_state.driver_handles
634
[obj->params.remote_proc_id][obj->params.line_id] = \
643
pr_err("notify_ducatidrv_delete failed! status = 0x%x", status);
646
EXPORT_SYMBOL(notify_ducatidrv_delete);
648
/* Register a callback for an event with the Notify driver. */
649
int notify_ducatidrv_register_event(struct notify_driver_object *handle,
652
int status = NOTIFY_S_SUCCESS;
653
struct notify_ducatidrv_object *obj;
654
VOLATILE struct notify_ducatidrv_event_entry *event_entry;
658
if (WARN_ON(unlikely(handle == NULL))) {
659
status = NOTIFY_E_INVALIDARG;
662
if (WARN_ON(unlikely(handle->is_init != \
663
NOTIFY_DRIVERINITSTATUS_DONE))) {
664
status = NOTIFY_E_INVALIDARG;
667
if (WARN_ON(unlikely(handle->notify_handle == NULL))) {
668
status = NOTIFY_E_INVALIDARG;
671
if (WARN_ON(unlikely(handle->notify_handle->driver_handle == NULL))) {
672
status = NOTIFY_E_DRIVERNOTREGISTERED;
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;
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.
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] = \
699
/* End the loop, slot found. */
703
obj->reg_chart[i] = event_id;
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,
712
event_entry->flag = NOTIFYDUCATIDRIVER_DOWN;
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));
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);
734
pr_err("notify_ducatidrv_register_event failed! "
735
"status = 0x%x", status);
740
/* Unregister a callback for an event with the Notify driver. */
741
int notify_ducatidrv_unregister_event(struct notify_driver_object *handle,
744
int status = NOTIFY_S_SUCCESS;
745
struct notify_ducatidrv_object *obj;
746
VOLATILE struct notify_ducatidrv_event_entry *event_entry;
750
if (WARN_ON(unlikely(handle == NULL))) {
751
status = NOTIFY_E_INVALIDARG;
754
if (WARN_ON(unlikely(handle->is_init != \
755
NOTIFY_DRIVERINITSTATUS_DONE))) {
756
status = NOTIFY_E_INVALIDARG;
759
if (WARN_ON(unlikely(handle->notify_handle == NULL))) {
760
status = NOTIFY_E_INVALIDARG;
763
if (WARN_ON(unlikely(handle->notify_handle->driver_handle == NULL))) {
764
status = NOTIFY_E_DRIVERNOTREGISTERED;
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;
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));
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
786
event_entry = EVENTENTRY(obj->self_event_chart, obj->event_entry_size,
788
event_entry->flag = NOTIFYDUCATIDRIVER_DOWN;
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);
804
/* Re-arrange eventIds in the Event Registration Chart so there is
805
* no gap caused by the removal of this eventId
807
* There is no need to make this atomic since Notify_exec cannot
808
* preempt: the event has already been disabled in shared memory
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;
825
pr_err("notify_ducatidrv_unregister_event failed! "
826
"status = 0x%x", status);
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)
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;
844
if (WARN_ON(unlikely(handle == NULL))) {
845
status = NOTIFY_E_INVALIDARG;
848
if (WARN_ON(unlikely(handle->is_init != \
849
NOTIFY_DRIVERINITSTATUS_DONE))) {
850
status = NOTIFY_E_INVALIDARG;
853
if (WARN_ON(unlikely(handle->notify_handle == NULL))) {
854
status = NOTIFY_E_INVALIDARG;
857
if (WARN_ON(unlikely(handle->notify_handle->driver_handle == NULL))) {
858
status = NOTIFY_E_DRIVERNOTREGISTERED;
862
obj = (struct notify_ducatidrv_object *)
863
handle->notify_handle->driver_handle;
865
mbox = (obj->remote_proc_id) ? ducati_mbox : tesla_mbox;
866
if (WARN_ON(unlikely(obj->reg_chart == NULL))) {
867
status = NOTIFY_E_FAIL;
872
event_entry = EVENTENTRY(obj->other_event_chart, obj->event_entry_size,
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);
882
max_poll_count = notify_state.cfg.send_event_poll_count;
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;
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. */
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. */
908
if (obj->cache_enabled) {
909
Cache_inv((void *)event_entry,
910
sizeof(struct notify_ducatidrv_event_entry),
911
Cache_Type_ALL, TRUE);
915
status = mutex_lock_interruptible(
916
notify_ducatidriver_state.gate_handle);
920
if (wait_clear == true) {
921
/*Wait for completion of prev
922
event from other side*/
923
while ((event_entry->flag != NOTIFYDUCATIDRIVER_DOWN) && \
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);
929
if ((max_poll_count != (u32)-1) && \
930
(i == max_poll_count)) {
931
status = NOTIFY_E_TIMEOUT;
936
if (obj->cache_enabled) {
937
Cache_inv((void *)event_entry,
938
sizeof(struct notify_ducatidrv_event_entry),
939
Cache_Type_ALL, TRUE);
944
/* Enter critical section protection. */
945
status = mutex_lock_interruptible(
946
notify_ducatidriver_state.gate_handle);
951
/* Set the event bit field and payload. */
952
event_entry->payload = payload;
953
event_entry->flag = NOTIFYDUCATIDRIVER_UP;
956
if (obj->cache_enabled) {
957
Cache_inv((void *)event_entry,
958
sizeof(struct notify_ducatidrv_event_entry),
959
Cache_Type_ALL, TRUE);
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);
969
/* Leave critical section protection. */
970
mutex_unlock(notify_ducatidriver_state.gate_handle);
975
pr_err("notify_ducatidrv_sendevent failed! "
976
"status = 0x%x", status);
981
/* Disable all events for this Notify driver.*/
982
int notify_ducatidrv_disable(struct notify_driver_object *handle)
984
int status = NOTIFY_S_SUCCESS;
985
struct notify_ducatidrv_object *obj;
986
struct omap_mbox *mbox;
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;
994
if (WARN_ON(unlikely(handle->is_init != \
995
NOTIFY_DRIVERINITSTATUS_DONE))) {
996
status = NOTIFY_E_INVALIDARG;
999
if (WARN_ON(unlikely(handle->notify_handle == NULL))) {
1000
status = NOTIFY_E_INVALIDARG;
1003
if (WARN_ON(unlikely(handle->notify_handle->driver_handle == NULL))) {
1004
status = NOTIFY_E_DRIVERNOTREGISTERED;
1008
obj = (struct notify_ducatidrv_object *)
1009
handle->notify_handle->driver_handle;
1011
mbox = (obj->remote_proc_id) ? ducati_mbox : tesla_mbox;
1012
if (WARN_ON(unlikely(obj->reg_chart == NULL))) {
1013
status = NOTIFY_E_FAIL;
1017
/* Disable the mailbox interrupt associated with ducati mailbox */
1018
omap_mbox_disable_irq(mbox, IRQ_RX);
1022
pr_err("notify_ducatidrv_disable failed! "
1023
"status = 0x%x", status);
1025
/*No flags to be returned. */
1029
/* Restore the notify_ducatidrv to the state before the last disable was
1031
void notify_ducatidrv_enable(struct notify_driver_object *handle)
1033
int status = NOTIFY_S_SUCCESS;
1034
struct notify_ducatidrv_object *obj;
1035
struct omap_mbox *mbox;
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;
1043
if (WARN_ON(unlikely(handle->is_init != \
1044
NOTIFY_DRIVERINITSTATUS_DONE))) {
1045
status = NOTIFY_E_INVALIDARG;
1048
if (WARN_ON(unlikely(handle->notify_handle == NULL))) {
1049
status = NOTIFY_E_INVALIDARG;
1052
if (WARN_ON(unlikely(handle->notify_handle->driver_handle == NULL))) {
1053
status = NOTIFY_E_DRIVERNOTREGISTERED;
1057
obj = (struct notify_ducatidrv_object *)
1058
handle->notify_handle->driver_handle;
1060
mbox = (obj->remote_proc_id) ? ducati_mbox : tesla_mbox;
1061
if (WARN_ON(unlikely(obj->reg_chart == NULL))) {
1062
status = NOTIFY_E_FAIL;
1066
/*Enable the receive interrupt for ducati */
1067
omap_mbox_enable_irq(mbox, IRQ_RX);
1071
pr_err("notify_ducatidrv_enable failed! "
1072
"status = 0x%x", status);
1077
/* Disable a specific event for this Notify ducati driver */
1078
void notify_ducatidrv_disable_event(struct notify_driver_object *handle,
1081
int status = NOTIFY_S_SUCCESS;
1082
struct notify_ducatidrv_object *obj;
1083
VOLATILE struct notify_ducatidrv_event_entry *event_entry;
1085
if (WARN_ON(unlikely(handle == NULL))) {
1086
status = NOTIFY_E_INVALIDARG;
1089
if (WARN_ON(unlikely(handle->is_init != \
1090
NOTIFY_DRIVERINITSTATUS_DONE))) {
1091
status = NOTIFY_E_INVALIDARG;
1094
if (WARN_ON(unlikely(handle->notify_handle == NULL))) {
1095
status = NOTIFY_E_INVALIDARG;
1098
if (WARN_ON(unlikely(handle->notify_handle->driver_handle == NULL))) {
1099
status = NOTIFY_E_DRIVERNOTREGISTERED;
1103
obj = (struct notify_ducatidrv_object *)
1104
handle->notify_handle->driver_handle;
1105
if (event_id > obj->num_events) {
1106
status = NOTIFY_E_FAIL;
1110
/* Enter critical section protection. */
1111
status = mutex_lock_interruptible(
1112
notify_ducatidriver_state.gate_handle);
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);
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);
1128
event_entry = EVENTENTRY(obj->self_event_chart, obj->event_entry_size,
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);
1139
/* Disable incoming Notify interrupts. This is done to ensure that the
1140
* eventEntry->flag is read atomically with any write back to shared
1142
notify_ducatidrv_disable(handle);
1144
/* Is the local notify_ducatidrv_disable_event happening between the
1145
* following two notify_ducatidrv_send_event operations on the remote
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;
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);
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);
1173
/* Re-enable incoming Notify interrupts */
1174
notify_ducatidrv_enable(handle);
1178
pr_err("notify_ducatidrv_disable_event failed! "
1179
"status = 0x%x", status);
1184
/* Enable a specific event for this Notify ducati driver */
1185
void notify_ducatidrv_enable_event(struct notify_driver_object *handle,
1189
struct notify_ducatidrv_object *obj;
1191
if (WARN_ON(unlikely(handle == NULL))) {
1192
status = NOTIFY_E_INVALIDARG;
1195
if (WARN_ON(unlikely(handle->is_init != \
1196
NOTIFY_DRIVERINITSTATUS_DONE))) {
1197
status = NOTIFY_E_INVALIDARG;
1200
if (WARN_ON(unlikely(handle->notify_handle == NULL))) {
1201
status = NOTIFY_E_INVALIDARG;
1204
if (WARN_ON(unlikely(handle->notify_handle->driver_handle == NULL))) {
1205
status = NOTIFY_E_DRIVERNOTREGISTERED;
1209
obj = (struct notify_ducatidrv_object *)
1210
handle->notify_handle->driver_handle;
1211
if (event_id > obj->num_events) {
1212
status = NOTIFY_E_FAIL;
1216
/* Enter critical section protection. */
1217
status = mutex_lock_interruptible(
1218
notify_ducatidriver_state.gate_handle);
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);
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);
1236
pr_err("notify_ducatidrv_enable_event failed! "
1237
"status = 0x%x", status);
1242
/* Get the shared memory requirements for the notify_ducatidrv. */
1243
uint notify_ducatidrv_shared_mem_req(
1244
const struct notify_ducatidrv_params *params)
1248
uint region_cache_size;
1250
s32 status = NOTIFY_S_SUCCESS;
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;
1259
if (WARN_ON(unlikely(params == NULL))) {
1260
status = NOTIFY_E_INVALIDARG;
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);
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;
1277
/* Determine obj->eventEntrySize which will be used to ROUND_UP
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));
1286
pr_err("notify_ducatidrv_shared_mem_req failed!"
1287
" status = 0x%x", status);
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,
1297
/* Decode the msg to identify the processor that has sent the message */
1298
u32 proc_id = (u32)ntfy_msg;
1300
/* Call the corresponding prpc_id callback */
1301
notify_shmdrv_isr_callback(notify_ducatidriver_state.driver_handles
1302
[proc_id][0], ntfy_msg);
1306
EXPORT_SYMBOL(notify_shmdrv_isr);
1308
static bool notify_shmdrv_isr_callback(void *ref_data, void *notify_msg)
1312
VOLATILE struct notify_ducatidrv_event_entry *event_entry;
1313
struct notify_ducatidrv_object *obj;
1316
obj = (struct notify_ducatidrv_object *) ref_data;
1319
/* Execute the loop till no asserted event is found for one complete
1320
* loop through all registered events */
1322
/* Check if the entry is a valid registered event.*/
1323
event_id = obj->reg_chart[i];
1324
if (event_id == (u32) -1)
1327
event_entry = EVENTENTRY(obj->self_event_chart,
1328
obj->event_entry_size, event_id);
1330
if (obj->cache_enabled) {
1331
Cache_inv((void *)event_entry,
1332
sizeof(struct notify_ducatidrv_event_entry),
1333
Cache_Type_ALL, TRUE);
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;
1345
/* Acknowledge the event. */
1346
event_entry->flag = NOTIFYDUCATIDRIVER_DOWN;
1348
/* Write back acknowledgement */
1350
if (obj->cache_enabled) {
1351
Cache_inv((void *)event_entry,
1352
sizeof(struct notify_ducatidrv_event_entry),
1353
Cache_Type_ALL, TRUE);
1358
/* Execute the callback function */
1359
notify_exec(obj->drv_handle->notify_handle, event_id,
1361
/* reinitialize the event check counter. */
1364
/* check for next event. */
1367
} while ((event_id != (u32) -1) && (i < obj->num_events));