There are two cases where the scheduler code schedule() is invoked-
schedule()
When a process voluntarily calls schedule()
Timer
schedule() always runs in process context. In the second case, when it is initiated by a timer interrupt, it is in the return path back from the kernel to the interrupted process where schedule() is called.