1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2002 by Björn Stenberg
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
28 #if !defined(CPU_PP) || !defined(BOOTLOADER)
29 volatile long current_tick NOCACHEDATA_ATTR
= 0;
32 void (*tick_funcs
[MAX_NUM_TICK_TASKS
])(void);
34 /* This array holds all queues that are initiated. It is used for broadcast. */
35 static struct event_queue
*all_queues
[32] NOCACHEBSS_ATTR
;
36 static int num_queues NOCACHEBSS_ATTR
;
38 void queue_wait(struct event_queue
*q
, struct event
*ev
) ICODE_ATTR
;
40 /****************************************************************************
41 * Standard kernel stuff
42 ****************************************************************************/
43 void kernel_init(void)
45 /* Init the threading API */
48 if(CURRENT_CORE
== CPU
)
50 memset(tick_funcs
, 0, sizeof(tick_funcs
));
53 memset(all_queues
, 0, sizeof(all_queues
));
61 #if CONFIG_CPU == S3C2440 && defined(BOOTLOADER)
63 TCON
&= ~(1 << 20); // stop timer 4
64 // TODO: this constant depends on dividers settings inherited from
65 // firmware. Set them explicitly somwhere.
66 TCNTB4
= 12193 * ticks
/ HZ
;
67 TCON
|= 1 << 21; // set manual bit
68 TCON
&= ~(1 << 21); // reset manual bit
69 TCON
&= ~(1 << 22); //autoreload Off
70 TCON
|= (1 << 20); // start timer 4
75 #elif defined(CPU_PP) && defined(BOOTLOADER)
76 unsigned stop
= USEC_TIMER
+ ticks
* (1000000/HZ
);
77 while (TIME_BEFORE(USEC_TIMER
, stop
))
78 switch_thread(true,NULL
);
86 #if ((CONFIG_CPU == S3C2440 || defined(ELIO_TPJ1022)) && defined(BOOTLOADER))
87 /* Some targets don't like yielding in the bootloader */
89 switch_thread(true, NULL
);
93 /****************************************************************************
94 * Queue handling stuff
95 ****************************************************************************/
97 #ifdef HAVE_EXTENDED_MESSAGING_AND_NAME
98 /* Moves waiting thread's descriptor to the current sender when a
99 message is dequeued */
100 static void queue_fetch_sender(struct queue_sender_list
*send
,
103 struct thread_entry
**spp
= &send
->senders
[i
];
107 send
->curr_sender
= *spp
;
112 /* Puts the specified return value in the waiting thread's return value
113 * and wakes the thread.
114 * 1) A sender should be confirmed to exist before calling which makes it
115 * more efficent to reject the majority of cases that don't need this
117 * 2) Requires interrupts disabled since queue overflows can cause posts
118 * from interrupt handlers to wake threads. Not doing so could cause
119 * an attempt at multiple wakes or other problems.
121 static void queue_release_sender(struct thread_entry
**sender
,
124 (*sender
)->retval
= retval
;
125 wakeup_thread_irq_safe(sender
);
127 /* This should _never_ happen - there must never be multiple
128 threads in this list and it is a corrupt state */
130 panicf("Queue: send slot ovf");
134 /* Releases any waiting threads that are queued with queue_send -
136 * Disable IRQs before calling since it uses queue_release_sender.
138 static void queue_release_all_senders(struct event_queue
*q
)
143 for(i
= q
->read
; i
!= q
->write
; i
++)
145 struct thread_entry
**spp
=
146 &q
->send
->senders
[i
& QUEUE_LENGTH_MASK
];
150 queue_release_sender(spp
, 0);
156 /* Enables queue_send on the specified queue - caller allocates the extra
158 void queue_enable_queue_send(struct event_queue
*q
,
159 struct queue_sender_list
*send
)
162 memset(send
, 0, sizeof(struct queue_sender_list
));
164 #endif /* HAVE_EXTENDED_MESSAGING_AND_NAME */
167 void queue_init(struct event_queue
*q
, bool register_queue
)
175 #ifdef HAVE_EXTENDED_MESSAGING_AND_NAME
176 q
->send
= NULL
; /* No message sending by default */
181 /* Add it to the all_queues array */
182 all_queues
[num_queues
++] = q
;
188 * If IRQ mode is enabled, some core-wise locking mechanisms are disabled
189 * causing accessing queue to be no longer thread safe from the other core.
190 * However, that locking mechanism would also kill IRQ handlers.
192 * @param q struct of an event_queue
193 * @param state enable/disable IRQ mode
194 * @default state disabled
196 void queue_set_irq_safe(struct event_queue
*q
, bool state
)
202 void queue_delete(struct event_queue
*q
)
207 int oldlevel
= set_irq_level(HIGHEST_IRQ_LEVEL
);
210 /* Release theads waiting on queue */
211 wakeup_thread(&q
->thread
);
213 #ifdef HAVE_EXTENDED_MESSAGING_AND_NAME
214 /* Release waiting threads and reply to any dequeued message
216 queue_release_all_senders(q
);
220 /* Find the queue to be deleted */
221 for(i
= 0;i
< num_queues
;i
++)
223 if(all_queues
[i
] == q
)
232 /* Move the following queues up in the list */
233 for(;i
< num_queues
-1;i
++)
235 all_queues
[i
] = all_queues
[i
+1];
242 set_irq_level(oldlevel
);
245 void queue_wait(struct event_queue
*q
, struct event
*ev
)
250 oldlevel
= set_irq_level(HIGHEST_IRQ_LEVEL
);
253 if (q
->read
== q
->write
)
255 set_irq_level_and_block_thread(&q
->thread
, oldlevel
);
256 oldlevel
= set_irq_level(HIGHEST_IRQ_LEVEL
);
260 rd
= q
->read
++ & QUEUE_LENGTH_MASK
;
263 #ifdef HAVE_EXTENDED_MESSAGING_AND_NAME
264 if(q
->send
&& q
->send
->senders
[rd
])
266 /* Get data for a waiting thread if one */
267 queue_fetch_sender(q
->send
, rd
);
272 set_irq_level(oldlevel
);
275 void queue_wait_w_tmo(struct event_queue
*q
, struct event
*ev
, int ticks
)
277 int oldlevel
= set_irq_level(HIGHEST_IRQ_LEVEL
);
280 if (q
->read
== q
->write
&& ticks
> 0)
282 set_irq_level_and_block_thread_w_tmo(&q
->thread
, ticks
, oldlevel
);
283 oldlevel
= set_irq_level(HIGHEST_IRQ_LEVEL
);
287 if (q
->read
!= q
->write
)
289 unsigned int rd
= q
->read
++ & QUEUE_LENGTH_MASK
;
292 #ifdef HAVE_EXTENDED_MESSAGING_AND_NAME
293 if(q
->send
&& q
->send
->senders
[rd
])
295 /* Get data for a waiting thread if one */
296 queue_fetch_sender(q
->send
, rd
);
302 ev
->id
= SYS_TIMEOUT
;
306 set_irq_level(oldlevel
);
309 void queue_post(struct event_queue
*q
, long id
, intptr_t data
)
311 int oldlevel
= set_irq_level(HIGHEST_IRQ_LEVEL
);
319 wr
= q
->write
++ & QUEUE_LENGTH_MASK
;
321 q
->events
[wr
].id
= id
;
322 q
->events
[wr
].data
= data
;
324 #ifdef HAVE_EXTENDED_MESSAGING_AND_NAME
327 struct thread_entry
**spp
= &q
->send
->senders
[wr
];
331 /* overflow protect - unblock any thread waiting at this index */
332 queue_release_sender(spp
, 0);
337 wakeup_thread_irq_safe(&q
->thread
);
342 set_irq_level(oldlevel
);
346 #ifdef HAVE_EXTENDED_MESSAGING_AND_NAME
347 /* No wakeup_thread_irq_safe here because IRQ handlers are not allowed
348 use of this function - we only aim to protect the queue integrity by
350 intptr_t queue_send(struct event_queue
*q
, long id
, intptr_t data
)
352 int oldlevel
= set_irq_level(HIGHEST_IRQ_LEVEL
);
357 wr
= q
->write
++ & QUEUE_LENGTH_MASK
;
359 q
->events
[wr
].id
= id
;
360 q
->events
[wr
].data
= data
;
364 struct thread_entry
**spp
= &q
->send
->senders
[wr
];
368 /* overflow protect - unblock any thread waiting at this index */
369 queue_release_sender(spp
, 0);
372 wakeup_thread(&q
->thread
);
373 set_irq_level_and_block_thread(spp
, oldlevel
);
374 return thread_get_current()->retval
;
377 /* Function as queue_post if sending is not enabled */
378 wakeup_thread(&q
->thread
);
380 set_irq_level(oldlevel
);
385 #if 0 /* not used now but probably will be later */
386 /* Query if the last message dequeued was added by queue_send or not */
387 bool queue_in_queue_send(struct event_queue
*q
)
389 return q
->send
&& q
->send
->curr_sender
;
393 /* Replies with retval to any dequeued message sent with queue_send */
394 void queue_reply(struct event_queue
*q
, intptr_t retval
)
397 /* No IRQ lock here since IRQs cannot change this */
398 if(q
->send
&& q
->send
->curr_sender
)
400 queue_release_sender(&q
->send
->curr_sender
, retval
);
404 #endif /* HAVE_EXTENDED_MESSAGING_AND_NAME */
406 bool queue_empty(const struct event_queue
* q
)
415 is_empty
= ( q
->read
== q
->write
);
424 void queue_clear(struct event_queue
* q
)
426 int oldlevel
= set_irq_level(HIGHEST_IRQ_LEVEL
);
433 #ifdef HAVE_EXTENDED_MESSAGING_AND_NAME
434 /* Release all thread waiting in the queue for a reply -
435 dequeued sent message will be handled by owning thread */
436 queue_release_all_senders(q
);
447 set_irq_level(oldlevel
);
450 void queue_remove_from_head(struct event_queue
*q
, long id
)
452 int oldlevel
= set_irq_level(HIGHEST_IRQ_LEVEL
);
459 while(q
->read
!= q
->write
)
461 unsigned int rd
= q
->read
& QUEUE_LENGTH_MASK
;
463 if(q
->events
[rd
].id
!= id
)
468 #ifdef HAVE_EXTENDED_MESSAGING_AND_NAME
471 struct thread_entry
**spp
= &q
->send
->senders
[rd
];
475 /* Release any thread waiting on this message */
476 queue_release_sender(spp
, 0);
488 set_irq_level(oldlevel
);
492 * The number of events waiting in the queue.
494 * @param struct of event_queue
495 * @return number of events in the queue
497 int queue_count(const struct event_queue
*q
)
499 int oldlevel
= set_irq_level(HIGHEST_IRQ_LEVEL
);
507 result
= q
->write
- q
->read
;
514 set_irq_level(oldlevel
);
519 int queue_broadcast(long id
, intptr_t data
)
523 for(i
= 0;i
< num_queues
;i
++)
525 queue_post(all_queues
[i
], id
, data
);
531 /****************************************************************************
533 ****************************************************************************/
534 #if CONFIG_CPU == SH7034
535 void tick_start(unsigned int interval_in_ms
)
539 count
= CPU_FREQ
* interval_in_ms
/ 1000 / 8;
543 panicf("Error! The tick interval is too long (%d ms)\n",
548 /* We are using timer 0 */
550 TSTR
&= ~0x01; /* Stop the timer */
551 TSNC
&= ~0x01; /* No synchronization */
552 TMDR
&= ~0x01; /* Operate normally */
554 TCNT0
= 0; /* Start counting at 0 */
555 GRA0
= (unsigned short)(count
- 1);
556 TCR0
= 0x23; /* Clear at GRA match, sysclock/8 */
558 /* Enable interrupt on level 1 */
559 IPRC
= (IPRC
& ~0x00f0) | 0x0010;
562 TIER0
= 0xf9; /* Enable GRA match interrupt */
564 TSTR
|= 0x01; /* Start timer 1 */
567 void IMIA0(void) __attribute__ ((interrupt_handler
));
572 /* Run through the list of tick tasks */
573 for(i
= 0;i
< MAX_NUM_TICK_TASKS
;i
++)
585 #elif defined(CPU_COLDFIRE)
586 void tick_start(unsigned int interval_in_ms
)
591 count
= CPU_FREQ
/2 * interval_in_ms
/ 1000 / 16;
595 panicf("Error! The tick interval is too long (%d ms)\n",
600 prescale
= cpu_frequency
/ CPU_FREQ
;
601 /* Note: The prescaler is later adjusted on-the-fly on CPU frequency
602 changes within timer.c */
604 /* We are using timer 0 */
606 TRR0
= (unsigned short)(count
- 1); /* The reference count */
607 TCN0
= 0; /* reset the timer */
608 TMR0
= 0x001d | ((unsigned short)(prescale
- 1) << 8);
609 /* restart, CLK/16, enabled, prescaler */
611 TER0
= 0xff; /* Clear all events */
613 ICR1
= 0x8c; /* Interrupt on level 3.0 */
617 void TIMER0(void) __attribute__ ((interrupt_handler
));
622 /* Run through the list of tick tasks */
623 for(i
= 0;i
< MAX_NUM_TICK_TASKS
;i
++)
633 TER0
= 0xff; /* Clear all events */
636 #elif defined(CPU_PP)
643 TIMER1_VAL
; /* Read value to ack IRQ */
644 /* Run through the list of tick tasks (using main core) */
645 if (CURRENT_CORE
== CPU
)
647 for (i
= 0;i
< MAX_NUM_TICK_TASKS
;i
++)
660 void tick_start(unsigned int interval_in_ms
)
663 if(CURRENT_CORE
== CPU
)
668 TIMER1_CFG
= 0xc0000000 | (interval_in_ms
*1000 - 1);
669 /* unmask interrupt source */
670 CPU_INT_EN
= TIMER1_MASK
;
672 COP_INT_EN
= TIMER1_MASK
;
675 /* We don't enable interrupts in the bootloader */
676 (void)interval_in_ms
;
680 #elif CONFIG_CPU == PNX0101
682 void timer_handler(void)
686 /* Run through the list of tick tasks */
687 for(i
= 0;i
< MAX_NUM_TICK_TASKS
;i
++)
698 void tick_start(unsigned int interval_in_ms
)
700 TIMER0
.ctrl
&= ~0x80; /* Disable the counter */
701 TIMER0
.ctrl
|= 0x40; /* Reload after counting down to zero */
702 TIMER0
.load
= 3000000 * interval_in_ms
/ 1000;
703 TIMER0
.ctrl
&= ~0xc; /* No prescaler */
704 TIMER0
.clr
= 1; /* Clear the interrupt request */
706 irq_set_int_handler(IRQ_TIMER0
, timer_handler
);
707 irq_enable_int(IRQ_TIMER0
);
709 TIMER0
.ctrl
|= 0x80; /* Enable the counter */
713 int tick_add_task(void (*f
)(void))
716 int oldlevel
= set_irq_level(HIGHEST_IRQ_LEVEL
);
718 /* Add a task if there is room */
719 for(i
= 0;i
< MAX_NUM_TICK_TASKS
;i
++)
721 if(tick_funcs
[i
] == NULL
)
724 set_irq_level(oldlevel
);
728 set_irq_level(oldlevel
);
729 panicf("Error! tick_add_task(): out of tasks");
733 int tick_remove_task(void (*f
)(void))
736 int oldlevel
= set_irq_level(HIGHEST_IRQ_LEVEL
);
738 /* Remove a task if it is there */
739 for(i
= 0;i
< MAX_NUM_TICK_TASKS
;i
++)
741 if(tick_funcs
[i
] == f
)
743 tick_funcs
[i
] = NULL
;
744 set_irq_level(oldlevel
);
749 set_irq_level(oldlevel
);
753 /****************************************************************************
754 * Tick-based interval timers/one-shots - be mindful this is not really
755 * intended for continuous timers but for events that need to run for a short
756 * time and be cancelled without further software intervention.
757 ****************************************************************************/
758 #ifdef INCLUDE_TIMEOUT_API
759 static struct timeout
*tmo_list
= NULL
; /* list of active timeout events */
761 /* timeout tick task - calls event handlers when they expire
762 * Event handlers may alter ticks, callback and data during operation.
764 static void timeout_tick(void)
766 unsigned long tick
= current_tick
;
767 struct timeout
*curr
, *next
;
769 for (curr
= tmo_list
; curr
!= NULL
; curr
= next
)
771 next
= (struct timeout
*)curr
->next
;
773 if (TIME_BEFORE(tick
, curr
->expires
))
776 /* this event has expired - call callback */
777 if (curr
->callback(curr
))
778 *(long *)&curr
->expires
= tick
+ curr
->ticks
; /* reload */
780 timeout_cancel(curr
); /* cancel */
784 /* Cancels a timeout callback - can be called from the ISR */
785 void timeout_cancel(struct timeout
*tmo
)
787 int oldlevel
= set_irq_level(HIGHEST_IRQ_LEVEL
);
789 if (tmo_list
!= NULL
)
791 struct timeout
*curr
= tmo_list
;
792 struct timeout
*prev
= NULL
;
794 while (curr
!= tmo
&& curr
!= NULL
)
797 curr
= (struct timeout
*)curr
->next
;
804 tmo_list
= (struct timeout
*)curr
->next
;
806 *(const struct timeout
**)&prev
->next
= curr
->next
;
808 if (tmo_list
== NULL
)
809 tick_remove_task(timeout_tick
); /* last one - remove task */
811 /* not in list or tmo == NULL */
814 set_irq_level(oldlevel
);
817 /* Adds a timeout callback - calling with an active timeout resets the
818 interval - can be called from the ISR */
819 void timeout_register(struct timeout
*tmo
, timeout_cb_type callback
,
820 int ticks
, intptr_t data
)
823 struct timeout
*curr
;
828 oldlevel
= set_irq_level(HIGHEST_IRQ_LEVEL
);
830 /* see if this one is already registered */
832 while (curr
!= tmo
&& curr
!= NULL
)
833 curr
= (struct timeout
*)curr
->next
;
837 /* not found - add it */
838 if (tmo_list
== NULL
)
839 tick_add_task(timeout_tick
); /* first one - add task */
841 *(struct timeout
**)&tmo
->next
= tmo_list
;
845 tmo
->callback
= callback
;
848 *(long *)&tmo
->expires
= current_tick
+ ticks
;
850 set_irq_level(oldlevel
);
853 #endif /* INCLUDE_TIMEOUT_API */
857 * Simulator versions in uisimulator/SIMVER/
860 /****************************************************************************
861 * Simple mutex functions
862 ****************************************************************************/
863 void mutex_init(struct mutex
*m
)
869 void mutex_lock(struct mutex
*m
)
871 if (test_and_set(&m
->locked
, 1))
873 /* Wait until the lock is open... */
874 block_thread(&m
->thread
);
878 void mutex_unlock(struct mutex
*m
)
882 if (m
->thread
== NULL
)
885 wakeup_thread(&m
->thread
);
890 void spinlock_lock(struct mutex
*m
)
892 while (test_and_set(&m
->locked
, 1))
894 /* wait until the lock is open... */
895 switch_thread(true, NULL
);
899 void spinlock_unlock(struct mutex
*m
)
904 #endif /* ndef SIMULATOR */