+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+#include <kern/queue.h>
+
+typedef kern_return_t (*iocpu_platform_action_t)(void * refcon0, void * refcon1, uint32_t priority,
+ void * param1, void * param2, void * param3);
+
+struct iocpu_platform_action_entry
+{
+ queue_chain_t link;
+ iocpu_platform_action_t action;
+ int32_t priority;
+ void * refcon0;
+ void * refcon1;
+ struct iocpu_platform_action_entry * alloc_list;
+};
+typedef struct iocpu_platform_action_entry iocpu_platform_action_entry_t;
+
+queue_head_t *
+iocpu_get_platform_quiesce_queue(void);
+
+queue_head_t *
+iocpu_get_platform_active_queue(void);
+
+void
+iocpu_platform_cpu_action_init(queue_head_t * quiesce_queue, queue_head_t * init_queue);
+
+void
+iocpu_add_platform_action(queue_head_t * queue, iocpu_platform_action_entry_t * entry);
+
+void
+iocpu_remove_platform_action(iocpu_platform_action_entry_t * entry);
+
+kern_return_t
+iocpu_run_platform_actions(queue_head_t * queue, uint32_t first_priority, uint32_t last_priority,
+ void * param1, void * param2, void * param3);
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#define kBootCPUNumber 0
+
+static iocpu_platform_action_entry_t * gIOAllActionsQueue;
+static queue_head_t gIOSleepActionQueue;
+static queue_head_t gIOWakeActionQueue;
+
+static queue_head_t iocpu_quiesce_queue;
+static queue_head_t iocpu_active_queue;
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+void
+iocpu_platform_cpu_action_init(queue_head_t * quiesce_queue, __unused queue_head_t * init_queue)
+{
+#if 0
+ enum { kNumQuiesceActions = 2 };
+ static iocpu_platform_action_entry_t quiesce_actions[kNumQuiesceActions] =
+ {
+ { { NULL, NULL }, (iocpu_platform_action_t) &clean_mmu_dcache, 97000, 0, 0, NULL },
+ { { NULL, NULL }, (iocpu_platform_action_t) &arm_sleep, 99000, 0, 0, NULL },
+ };
+ unsigned int idx;
+
+ for (idx = 0; idx < kNumQuiesceActions; idx++)
+ iocpu_add_platform_action(quiesce_queue, &quiesce_actions[idx]);
+#endif
+}
+
+queue_head_t * iocpu_get_platform_quiesce_queue(void)
+{
+ if (!iocpu_quiesce_queue.next)
+ {
+ queue_init(&iocpu_quiesce_queue);
+ queue_init(&iocpu_active_queue);
+ iocpu_platform_cpu_action_init(&iocpu_quiesce_queue, &iocpu_active_queue);
+ }
+ return (&iocpu_quiesce_queue);
+}
+
+queue_head_t * iocpu_get_platform_active_queue(void)
+{
+ if (!iocpu_active_queue.next)
+ {
+ queue_init(&iocpu_quiesce_queue);
+ queue_init(&iocpu_active_queue);
+ iocpu_platform_cpu_action_init(&iocpu_quiesce_queue, &iocpu_active_queue);
+ }
+ return (&iocpu_active_queue);
+}
+
+void iocpu_add_platform_action(queue_head_t * queue, iocpu_platform_action_entry_t * entry)
+{
+ iocpu_platform_action_entry_t * next;
+
+ queue_iterate(queue, next, iocpu_platform_action_entry_t *, link)
+ {
+ if (next->priority > entry->priority)
+ {
+ queue_insert_before(queue, entry, next, iocpu_platform_action_entry_t *, link);
+ return;
+ }
+ }
+ queue_enter(queue, entry, iocpu_platform_action_entry_t *, link); // at tail
+}
+
+void iocpu_remove_platform_action(iocpu_platform_action_entry_t * entry)
+{
+ remque(&entry->link);
+}
+
+kern_return_t
+iocpu_run_platform_actions(queue_head_t * queue, uint32_t first_priority, uint32_t last_priority,
+ void * param1, void * param2, void * param3)
+{
+ kern_return_t ret = KERN_SUCCESS;
+ kern_return_t result = KERN_SUCCESS;
+ iocpu_platform_action_entry_t * next;
+
+ queue_iterate(queue, next, iocpu_platform_action_entry_t *, link)
+ {
+ uint32_t pri = (next->priority < 0) ? -next->priority : next->priority;
+ if ((pri >= first_priority) && (pri <= last_priority))
+ {
+ //kprintf("[%p]", next->action);
+ ret = (*next->action)(next->refcon0, next->refcon1, pri, param1, param2, param3);
+ }
+ if (KERN_SUCCESS == result)
+ result = ret;
+ }
+ return (result);
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+extern "C" kern_return_t
+IOCPURunPlatformQuiesceActions(void)
+{
+ return (iocpu_run_platform_actions(iocpu_get_platform_quiesce_queue(), 0, 0U-1,
+ NULL, NULL, NULL));
+}
+
+extern "C" kern_return_t
+IOCPURunPlatformActiveActions(void)
+{
+ return (iocpu_run_platform_actions(iocpu_get_platform_active_queue(), 0, 0U-1,
+ NULL, NULL, NULL));
+}
+
+static kern_return_t
+IOServicePlatformAction(void * refcon0, void * refcon1, uint32_t priority,
+ void * param1, void * param2, void * param3)
+{
+ IOReturn ret;
+ IOService * service = (IOService *) refcon0;
+ const OSSymbol * function = (const OSSymbol *) refcon1;
+
+ kprintf("%s -> %s\n", function->getCStringNoCopy(), service->getName());
+
+ ret = service->callPlatformFunction(function, false,
+ (void *) priority, param1, param2, param3);
+
+ return (ret);
+}
+
+static void
+IOInstallServicePlatformAction(IOService * service,
+ const OSSymbol * key, queue_head_t * queue,
+ bool reverse)
+{
+ OSNumber * num;
+ iocpu_platform_action_entry_t * entry;
+ uint32_t priority;
+
+ num = OSDynamicCast(OSNumber, service->getProperty(key));
+ if (!num)
+ return;
+
+ entry = IONew(iocpu_platform_action_entry_t, 1);
+ entry->action = &IOServicePlatformAction;
+ priority = num->unsigned32BitValue();
+ if (reverse)
+ entry->priority = -priority;
+ else
+ entry->priority = priority;
+ entry->refcon0 = service;
+ entry->refcon1 = (void *) key;
+
+ iocpu_add_platform_action(queue, entry);
+ entry->alloc_list = gIOAllActionsQueue;
+ gIOAllActionsQueue = entry;
+}