+/* Defers SFI off and per-class on timers (if live) by the specified interval
+ * in Mach Absolute Time Units. Currently invoked to align with the global
+ * forced idle mechanism. Making some simplifying assumptions, the iterative GFI
+ * induced SFI on+off deferrals form a geometric series that converges to yield
+ * an effective SFI duty cycle that is scaled by the GFI duty cycle. Initial phase
+ * alignment and congruency of the SFI/GFI periods can distort this to some extent.
+ */
+
+kern_return_t sfi_defer(uint64_t sfi_defer_matus)
+{
+ spl_t s;
+ kern_return_t kr = KERN_FAILURE;
+ s = splsched();
+
+ KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_SFI, SFI_GLOBAL_DEFER), sfi_defer_matus, 0, 0, 0, 0);
+
+ simple_lock(&sfi_lock);
+ if (!sfi_is_enabled) {
+ goto sfi_defer_done;
+ }
+
+ assert(sfi_next_off_deadline != 0);
+
+ sfi_next_off_deadline += sfi_defer_matus;
+ timer_call_enter1(&sfi_timer_call_entry, NULL, sfi_next_off_deadline, TIMER_CALL_SYS_CRITICAL);
+
+ int i;
+ for (i = 0; i < MAX_SFI_CLASS_ID; i++) {
+ if (sfi_classes[i].class_sfi_is_enabled) {
+ if (sfi_classes[i].on_timer_programmed) {
+ uint64_t new_on_deadline = sfi_classes[i].on_timer_deadline + sfi_defer_matus;
+ sfi_classes[i].on_timer_deadline = new_on_deadline;
+ timer_call_enter1(&sfi_classes[i].on_timer, NULL, new_on_deadline, TIMER_CALL_SYS_CRITICAL);
+ }
+ }
+ }
+
+ kr = KERN_SUCCESS;
+sfi_defer_done:
+ simple_unlock(&sfi_lock);
+
+ splx(s);
+
+ return (kr);
+}
+