/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ /* * * (C) COPYRIGHT 2019-2021 ARM Limited. All rights reserved. * * This program is free software and is provided to you under the terms of the * GNU General Public License version 2 as published by the Free Software * Foundation, and any use by you of this program is subject to the terms * of such GNU license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, you can access it online at * http://www.gnu.org/licenses/gpl-2.0.html. * */ #ifndef _KBASE_CSF_SCHEDULER_H_ #define _KBASE_CSF_SCHEDULER_H_ #include "mali_kbase_csf.h" /** * kbase_csf_scheduler_queue_start() - Enable the running of GPU command queue * on firmware. * * @queue: Pointer to the GPU command queue to be started. * * This function would enable the start of a CSI, within a * CSG, to which the @queue was bound. * If the CSG is already scheduled and resident, the CSI will be started * right away, otherwise once the group is made resident. * * Return: 0 on success, or negative on failure. */ int kbase_csf_scheduler_queue_start(struct kbase_queue *queue); /** * kbase_csf_scheduler_queue_stop() - Disable the running of GPU command queue * on firmware. * * @queue: Pointer to the GPU command queue to be stopped. * * This function would stop the CSI, within a CSG, to which @queue was bound. * * Return: 0 on success, or negative on failure. */ int kbase_csf_scheduler_queue_stop(struct kbase_queue *queue); /** * kbase_csf_scheduler_group_protm_enter - Handle the protm enter event for the * GPU command queue group. * * @group: The command queue group. * * This function could request the firmware to enter the protected mode * and allow the execution of protected region instructions for all the * bound queues of the group that have protm pending bit set in their * respective CS_ACK register. */ void kbase_csf_scheduler_group_protm_enter(struct kbase_queue_group *group); /** * kbase_csf_scheduler_group_get_slot() - Checks if a queue group is * programmed on a firmware CSG slot * and returns the slot number. * * @group: The command queue group. * * Return: The slot number, if the group is programmed on a slot. * Otherwise returns a negative number. * * Note: This function should not be used if the interrupt_lock is held. Use * kbase_csf_scheduler_group_get_slot_locked() instead. */ int kbase_csf_scheduler_group_get_slot(struct kbase_queue_group *group); /** * kbase_csf_scheduler_group_get_slot_locked() - Checks if a queue group is * programmed on a firmware CSG slot * and returns the slot number. * * @group: The command queue group. * * Return: The slot number, if the group is programmed on a slot. * Otherwise returns a negative number. * * Note: Caller must hold the interrupt_lock. */ int kbase_csf_scheduler_group_get_slot_locked(struct kbase_queue_group *group); /** * kbase_csf_scheduler_group_events_enabled() - Checks if interrupt events * should be handled for a queue group. * * @kbdev: The device of the group. * @group: The queue group. * * Return: true if interrupt events should be handled. * * Note: Caller must hold the interrupt_lock. */ bool kbase_csf_scheduler_group_events_enabled(struct kbase_device *kbdev, struct kbase_queue_group *group); /** * kbase_csf_scheduler_get_group_on_slot()- Gets the queue group that has been * programmed to a firmware CSG slot. * * @kbdev: The GPU device. * @slot: The slot for which to get the queue group. * * Return: Pointer to the programmed queue group. * * Note: Caller must hold the interrupt_lock. */ struct kbase_queue_group *kbase_csf_scheduler_get_group_on_slot( struct kbase_device *kbdev, int slot); /** * kbase_csf_scheduler_group_deschedule() - Deschedule a GPU command queue * group from the firmware. * * @group: Pointer to the queue group to be descheduled. * * This function would disable the scheduling of GPU command queue group on * firmware. */ void kbase_csf_scheduler_group_deschedule(struct kbase_queue_group *group); /** * kbase_csf_scheduler_evict_ctx_slots() - Evict all GPU command queue groups * of a given context that are active * running from the firmware. * * @kbdev: The GPU device. * @kctx: Kbase context for the evict operation. * @evicted_groups: List_head for returning evicted active queue groups. * * This function would disable the scheduling of GPU command queue groups active * on firmware slots from the given Kbase context. The affected groups are * added to the supplied list_head argument. */ void kbase_csf_scheduler_evict_ctx_slots(struct kbase_device *kbdev, struct kbase_context *kctx, struct list_head *evicted_groups); /** * kbase_csf_scheduler_context_init() - Initialize the context-specific part * for CSF scheduler. * * @kctx: Pointer to kbase context that is being created. * * This function must be called during Kbase context creation. * * Return: 0 on success, or negative on failure. */ int kbase_csf_scheduler_context_init(struct kbase_context *kctx); /** * kbase_csf_scheduler_init - Initialize the CSF scheduler * * @kbdev: Instance of a GPU platform device that implements a CSF interface. * * The scheduler does the arbitration for the CSG slots * provided by the firmware between the GPU command queue groups created * by the Clients. * This function must be called after loading firmware and parsing its capabilities. * * Return: 0 on success, or negative on failure. */ int kbase_csf_scheduler_init(struct kbase_device *kbdev); /** * kbase_csf_scheduler_early_init - Early initialization for the CSF scheduler * * @kbdev: Instance of a GPU platform device that implements a CSF interface. * * Initialize necessary resources such as locks, workqueue for CSF scheduler. * This must be called at kbase probe. * * Return: 0 on success, or negative on failure. */ int kbase_csf_scheduler_early_init(struct kbase_device *kbdev); /** * kbase_csf_scheduler_context_term() - Terminate the context-specific part * for CSF scheduler. * * @kctx: Pointer to kbase context that is being terminated. * * This function must be called during Kbase context termination. */ void kbase_csf_scheduler_context_term(struct kbase_context *kctx); /** * kbase_csf_scheduler_term - Terminate the CSF scheduler. * * @kbdev: Instance of a GPU platform device that implements a CSF interface. * * This should be called when unload of firmware is done on device * termination. */ void kbase_csf_scheduler_term(struct kbase_device *kbdev); /** * kbase_csf_scheduler_early_term - Early termination of the CSF scheduler. * * @kbdev: Instance of a GPU platform device that implements a CSF interface. * * This should be called only when kbase probe fails or gets rmmoded. */ void kbase_csf_scheduler_early_term(struct kbase_device *kbdev); /** * kbase_csf_scheduler_reset - Reset the state of all active GPU command * queue groups. * * @kbdev: Instance of a GPU platform device that implements a CSF interface. * * This function will first iterate through all the active/scheduled GPU * command queue groups and suspend them (to avoid losing work for groups * that are not stuck). The groups that could not get suspended would be * descheduled and marked as terminated (which will then lead to unbinding * of all the queues bound to them) and also no more work would be allowed * to execute for them. * * This is similar to the action taken in response to an unexpected OoM event. * No explicit re-initialization is done for CSG & CS interface I/O pages; * instead, that happens implicitly on firmware reload. * * Should be called only after initiating the GPU reset. */ void kbase_csf_scheduler_reset(struct kbase_device *kbdev); /** * kbase_csf_scheduler_enable_tick_timer - Enable the scheduler tick timer. * * @kbdev: Instance of a GPU platform device that implements a CSF interface. * * This function will restart the scheduler tick so that regular scheduling can * be resumed without any explicit trigger (like kicking of GPU queues). */ void kbase_csf_scheduler_enable_tick_timer(struct kbase_device *kbdev); /** * kbase_csf_scheduler_group_copy_suspend_buf - Suspend a queue * group and copy suspend buffer. * * This function is called to suspend a queue group and copy the suspend_buffer * contents to the input buffer provided. * * @group: Pointer to the queue group to be suspended. * @sus_buf: Pointer to the structure which contains details of the * user buffer and its kernel pinned pages to which we need to copy * the group suspend buffer. * * Return: 0 on success, or negative on failure. */ int kbase_csf_scheduler_group_copy_suspend_buf(struct kbase_queue_group *group, struct kbase_suspend_copy_buffer *sus_buf); /** * kbase_csf_scheduler_lock - Acquire the global Scheduler lock. * * @kbdev: Instance of a GPU platform device that implements a CSF interface. * * This function will take the global scheduler lock, in order to serialize * against the Scheduler actions, for access to CS IO pages. */ static inline void kbase_csf_scheduler_lock(struct kbase_device *kbdev) { mutex_lock(&kbdev->csf.scheduler.lock); } /** * kbase_csf_scheduler_unlock - Release the global Scheduler lock. * * @kbdev: Instance of a GPU platform device that implements a CSF interface. */ static inline void kbase_csf_scheduler_unlock(struct kbase_device *kbdev) { mutex_unlock(&kbdev->csf.scheduler.lock); } /** * kbase_csf_scheduler_spin_lock - Acquire Scheduler interrupt spinlock. * * @kbdev: Instance of a GPU platform device that implements a CSF interface. * @flags: Pointer to the memory location that would store the previous * interrupt state. * * This function will take the global scheduler lock, in order to serialize * against the Scheduler actions, for access to CS IO pages. */ static inline void kbase_csf_scheduler_spin_lock(struct kbase_device *kbdev, unsigned long *flags) { spin_lock_irqsave(&kbdev->csf.scheduler.interrupt_lock, *flags); } /** * kbase_csf_scheduler_spin_unlock - Release Scheduler interrupt spinlock. * * @kbdev: Instance of a GPU platform device that implements a CSF interface. * @flags: Previously stored interrupt state when Scheduler interrupt * spinlock was acquired. */ static inline void kbase_csf_scheduler_spin_unlock(struct kbase_device *kbdev, unsigned long flags) { spin_unlock_irqrestore(&kbdev->csf.scheduler.interrupt_lock, flags); } /** * kbase_csf_scheduler_spin_lock_assert_held - Assert if the Scheduler * interrupt spinlock is held. * * @kbdev: Instance of a GPU platform device that implements a CSF interface. */ static inline void kbase_csf_scheduler_spin_lock_assert_held(struct kbase_device *kbdev) { lockdep_assert_held(&kbdev->csf.scheduler.interrupt_lock); } /** * kbase_csf_scheduler_timer_is_enabled() - Check if the scheduler wakes up * automatically for periodic tasks. * * @kbdev: Pointer to the device * * Return: true if the scheduler is configured to wake up periodically */ bool kbase_csf_scheduler_timer_is_enabled(struct kbase_device *kbdev); /** * kbase_csf_scheduler_timer_set_enabled() - Enable/disable periodic * scheduler tasks. * * @kbdev: Pointer to the device * @enable: Whether to enable periodic scheduler tasks */ void kbase_csf_scheduler_timer_set_enabled(struct kbase_device *kbdev, bool enable); /** * kbase_csf_scheduler_kick - Perform pending scheduling tasks once. * * Note: This function is only effective if the scheduling timer is disabled. * * @kbdev: Instance of a GPU platform device that implements a CSF interface. */ void kbase_csf_scheduler_kick(struct kbase_device *kbdev); /** * kbase_csf_scheduler_protected_mode_in_use() - Check if the scheduler is * running with protected mode tasks. * * @kbdev: Pointer to the device * * Return: true if the scheduler is running with protected mode tasks */ static inline bool kbase_csf_scheduler_protected_mode_in_use( struct kbase_device *kbdev) { return (kbdev->csf.scheduler.active_protm_grp != NULL); } /** * kbase_csf_scheduler_pm_active - Perform scheduler power active operation * * Note: This function will increase the scheduler's internal pm_active_count * value, ensuring that both GPU and MCU are powered for access. * * @kbdev: Instance of a GPU platform device that implements a CSF interface. */ void kbase_csf_scheduler_pm_active(struct kbase_device *kbdev); /** * kbase_csf_scheduler_pm_idle - Perform the scheduler power idle operation * * Note: This function will decrease the scheduler's internal pm_active_count * value. On reaching 0, the MCU and GPU could be powered off. * * @kbdev: Instance of a GPU platform device that implements a CSF interface. */ void kbase_csf_scheduler_pm_idle(struct kbase_device *kbdev); /** * kbase_csf_scheduler_pm_resume - Reactivate the scheduler on system resume * * @kbdev: Instance of a GPU platform device that implements a CSF interface. * * This function will make the scheduler resume the scheduling of queue groups * and take the power managemenet reference, if there are any runnable groups. */ void kbase_csf_scheduler_pm_resume(struct kbase_device *kbdev); /** * kbase_csf_scheduler_pm_suspend - Idle the scheduler on system suspend * * @kbdev: Instance of a GPU platform device that implements a CSF interface. * * This function will make the scheduler suspend all the running queue groups * and drop its power managemenet reference. */ void kbase_csf_scheduler_pm_suspend(struct kbase_device *kbdev); /** * kbase_csf_scheduler_all_csgs_idle() - Check if the scheduler internal * runtime used slots are all tagged as idle command queue groups. * * @kbdev: Pointer to the device * * Return: true if all the used slots are tagged as idle CSGs. */ static inline bool kbase_csf_scheduler_all_csgs_idle(struct kbase_device *kbdev) { lockdep_assert_held(&kbdev->csf.scheduler.interrupt_lock); return bitmap_equal(kbdev->csf.scheduler.csg_slots_idle_mask, kbdev->csf.scheduler.csg_inuse_bitmap, kbdev->csf.global_iface.group_num); } /** * kbase_csf_scheduler_advance_tick_nolock() - Advance the scheduling tick * * @kbdev: Pointer to the device * * This function advances the scheduling tick by enqueing the tick work item for * immediate execution, but only if the tick hrtimer is active. If the timer * is inactive then the tick work item is already in flight. * The caller must hold the interrupt lock. */ static inline void kbase_csf_scheduler_advance_tick_nolock(struct kbase_device *kbdev) { struct kbase_csf_scheduler *const scheduler = &kbdev->csf.scheduler; lockdep_assert_held(&scheduler->interrupt_lock); if (scheduler->tick_timer_active) { KBASE_KTRACE_ADD(kbdev, SCHEDULER_ADVANCE_TICK, NULL, 0u); scheduler->tick_timer_active = false; queue_work(scheduler->wq, &scheduler->tick_work); } else { KBASE_KTRACE_ADD(kbdev, SCHEDULER_NOADVANCE_TICK, NULL, 0u); } } /** * kbase_csf_scheduler_advance_tick() - Advance the scheduling tick * * @kbdev: Pointer to the device * * This function advances the scheduling tick by enqueing the tick work item for * immediate execution, but only if the tick hrtimer is active. If the timer * is inactive then the tick work item is already in flight. */ static inline void kbase_csf_scheduler_advance_tick(struct kbase_device *kbdev) { struct kbase_csf_scheduler *const scheduler = &kbdev->csf.scheduler; unsigned long flags; spin_lock_irqsave(&scheduler->interrupt_lock, flags); kbase_csf_scheduler_advance_tick_nolock(kbdev); spin_unlock_irqrestore(&scheduler->interrupt_lock, flags); } /** * kbase_csf_scheduler_queue_has_trace() - report whether the queue has been * configured to operate with the * cs_trace feature. * * @queue: Pointer to the queue. * * Return: True if the gpu queue is configured to operate with the cs_trace * feature, otherwise false. */ static inline bool kbase_csf_scheduler_queue_has_trace(struct kbase_queue *queue) { lockdep_assert_held(&queue->kctx->kbdev->csf.scheduler.lock); /* In the current arrangement, it is possible for the context to enable * the cs_trace after some queues have been registered with cs_trace in * disabled state. So each queue has its own enabled/disabled condition. */ return (queue->trace_buffer_size && queue->trace_buffer_base); } #endif /* _KBASE_CSF_SCHEDULER_H_ */