enum cts_rc test_task_priority(void) { uint32_t event; repeat_count = 2; task_wake(TASK_ID_A); task_wake(TASK_ID_C); event = task_wait_event(5 * SECOND); if (event != TASK_EVENT_WAKE) { CPRINTS("Woken up by unexpected event: 0x%08x", event); return CTS_RC_FAILURE; } if (wake_count[0] != repeat_count - 1 || wake_count[1] != repeat_count - 1) { CPRINTS("Unexpected counter values: %d %d %d", wake_count[0], wake_count[1], wake_count[2]); return CTS_RC_FAILURE; } /* TODO: Verify no tasks are ready, no events are pending. */ if (*task_get_event_bitmap(TASK_ID_A) || *task_get_event_bitmap(TASK_ID_B) || *task_get_event_bitmap(TASK_ID_C)) { CPRINTS("Events are pending"); return CTS_RC_FAILURE; } return CTS_RC_SUCCESS; }
static int test_request(void) { uint32_t expected_rdo = RDO_FIXED(1, 900, 900, RDO_CAP_MISMATCH); plug_in_source(0, 0); task_wake(PD_PORT_TO_TASK_ID(0)); task_wait_event(2 * PD_T_CC_DEBOUNCE + 100 * MSEC); TEST_ASSERT(pd_port[0].polarity == 0); /* We're in SNK_DISCOVERY now. Let's send the source cap. */ simulate_source_cap(0); task_wait_event(30 * MSEC); TEST_ASSERT(verify_goodcrc(0, PD_ROLE_SINK, pd_port[0].msg_rx_id)); /* Wait for the power request */ task_wake(PD_PORT_TO_TASK_ID(0)); task_wait_event(35 * MSEC); /* tSenderResponse: 24~30 ms */ inc_rx_id(0); /* Process the request */ TEST_ASSERT(pd_test_tx_msg_verify_sop(0)); TEST_ASSERT(pd_test_tx_msg_verify_short(0, PD_HEADER(PD_DATA_REQUEST, PD_ROLE_SINK, PD_ROLE_UFP, pd_port[0].msg_tx_id, 1))); TEST_ASSERT(pd_test_tx_msg_verify_word(0, expected_rdo)); TEST_ASSERT(pd_test_tx_msg_verify_crc(0)); TEST_ASSERT(pd_test_tx_msg_verify_eop(0)); inc_tx_id(0); /* We're done */ unplug(0); return EC_SUCCESS; }
static int test_sink(void) { int i; plug_in_sink(1, 1); task_wake(PD_PORT_TO_TASK_ID(1)); task_wait_event(250 * MSEC); /* tTypeCSinkWaitCap: 210~250 ms */ TEST_ASSERT(pd_port[1].polarity == 1); /* The source cap should be sent */ TEST_ASSERT(pd_test_tx_msg_verify_sop(1)); TEST_ASSERT(pd_test_tx_msg_verify_short(1, PD_HEADER(PD_DATA_SOURCE_CAP, PD_ROLE_SOURCE, PD_ROLE_DFP, pd_port[1].msg_tx_id, pd_src_pdo_cnt))); for (i = 0; i < pd_src_pdo_cnt; ++i) TEST_ASSERT(pd_test_tx_msg_verify_word(1, pd_src_pdo[i])); TEST_ASSERT(pd_test_tx_msg_verify_crc(1)); TEST_ASSERT(pd_test_tx_msg_verify_eop(1)); /* Looks good. Ack the source cap. */ simulate_goodcrc(1, PD_ROLE_SINK, pd_port[1].msg_tx_id); task_wake(PD_PORT_TO_TASK_ID(1)); usleep(30 * MSEC); inc_tx_id(1); /* We're done */ unplug(1); return EC_SUCCESS; }
void tcpci_tcpc_alert(int port) { int status; /* Read the Alert register from the TCPC */ tcpm_alert_status(port, &status); /* * Clear alert status for everything except RX_STATUS, which shouldn't * be cleared until we have successfully retrieved message. */ if (status & ~TCPC_REG_ALERT_RX_STATUS) tcpc_write16(port, TCPC_REG_ALERT, status & ~TCPC_REG_ALERT_RX_STATUS); if (status & TCPC_REG_ALERT_CC_STATUS) { /* CC status changed, wake task */ task_set_event(PD_PORT_TO_TASK_ID(port), PD_EVENT_CC, 0); } if (status & TCPC_REG_ALERT_POWER_STATUS) { int reg = 0; tcpc_read(port, TCPC_REG_POWER_STATUS_MASK, ®); if (reg == TCPC_REG_POWER_STATUS_MASK_ALL) { /* * If power status mask has been reset, then the TCPC * has reset. */ task_set_event(PD_PORT_TO_TASK_ID(port), PD_EVENT_TCPC_RESET, 0); } else { /* Read Power Status register */ tcpci_tcpm_get_power_status(port, ®); /* Update VBUS status */ tcpc_vbus[port] = reg & TCPC_REG_POWER_STATUS_VBUS_PRES ? 1 : 0; #if defined(CONFIG_USB_PD_VBUS_DETECT_TCPC) && defined(CONFIG_USB_CHARGER) /* Update charge manager with new VBUS state */ usb_charger_vbus_change(port, tcpc_vbus[port]); task_wake(PD_PORT_TO_TASK_ID(port)); #endif /* CONFIG_USB_PD_VBUS_DETECT_TCPC && CONFIG_USB_CHARGER */ } } if (status & TCPC_REG_ALERT_RX_STATUS) { /* message received */ task_set_event(PD_PORT_TO_TASK_ID(port), PD_EVENT_RX, 0); } if (status & TCPC_REG_ALERT_RX_HARD_RST) { /* hard reset received */ pd_execute_hard_reset(port); task_wake(PD_PORT_TO_TASK_ID(port)); } if (status & TCPC_REG_ALERT_TX_COMPLETE) { /* transmit complete */ pd_transmit_complete(port, status & TCPC_REG_ALERT_TX_SUCCESS ? TCPC_TX_COMPLETE_SUCCESS : TCPC_TX_COMPLETE_FAILED); } }
/** * Handle debounced power button changing state. */ static void powerbtn_x86_changed(void) { if (pwrbtn_state == PWRBTN_STATE_BOOT_KB_RESET || pwrbtn_state == PWRBTN_STATE_INIT_ON || pwrbtn_state == PWRBTN_STATE_LID_OPEN || pwrbtn_state == PWRBTN_STATE_WAS_OFF) { /* Ignore all power button changes during an initial pulse */ CPRINTS("PB ignoring change"); return; } if (power_button_is_pressed()) { /* Power button pressed */ power_button_pressed(get_time().val); } else { /* Power button released */ if (pwrbtn_state == PWRBTN_STATE_EAT_RELEASE) { /* * Ignore the first power button release if we already * told the PCH the power button was released. */ CPRINTS("PB ignoring release"); pwrbtn_state = PWRBTN_STATE_IDLE; return; } power_button_released(get_time().val); } /* Wake the power button task */ task_wake(TASK_ID_POWERBTN); }
static int command_power(int argc, char **argv) { int v; if (argc < 2) { enum power_state_t state; state = PSTATE_UNKNOWN; if (chipset_in_state(CHIPSET_STATE_ANY_OFF)) state = PSTATE_OFF; if (chipset_in_state(CHIPSET_STATE_SUSPEND)) state = PSTATE_SUSPEND; if (chipset_in_state(CHIPSET_STATE_ON)) state = PSTATE_ON; ccprintf("%s\n", state_name[state]); return EC_SUCCESS; } if (!parse_bool(argv[1], &v)) return EC_ERROR_PARAM1; power_request = v ? POWER_REQ_ON : POWER_REQ_OFF; ccprintf("Requesting power %s\n", power_req_name[power_request]); task_wake(TASK_ID_CHIPSET); return EC_SUCCESS; }
void vbus_wake_interrupt(enum gpio_signal signal) { CPRINTF("VBUS %d\n", !gpio_get_level(signal)); gpio_set_level(GPIO_USB_PD_VBUS_WAKE, !gpio_get_level(GPIO_VBUS_WAKE_L)); /* * TODO(crosbug.com/p/41226): * rev1/rev2 boards don't have vbus input on ec. vbus_wake is a * logical OR of two vbus status. to workaround the power status * issue, wake up both pd tasks on vbus_wake interrupt. a proper * hardware fix will be in rev3. * enable TCPC POWER_STATUS ALERT1 can solve this issue too. */ task_wake(TASK_ID_PD_C0); task_wake(TASK_ID_PD_C1); }
void kb_ibf_interrupt(void) { if (lpc_keyboard_input_pending()) keyboard_host_write(MEC1322_8042_H2E, MEC1322_8042_STS & (1 << 3)); task_wake(TASK_ID_KEYPROTO); }
static void siglog_deferred(void) { const struct gpio_info *g = gpio_list; unsigned int i; timestamp_t tdiff = {.val = 0}; /* Disable interrupts for input signals while we print stuff.*/ for (i = 0; i < POWER_SIGNAL_COUNT; i++) gpio_disable_interrupt(power_signal_list[i].gpio); CPRINTF("%d signal changes:\n", siglog_entries); for (i = 0; i < siglog_entries; i++) { if (i) tdiff.val = siglog[i].time.val - siglog[i-1].time.val; CPRINTF(" %.6ld +%.6ld %s => %d\n", siglog[i].time.val, tdiff.val, g[siglog[i].signal].name, siglog[i].level); } if (siglog_truncated) CPRINTF(" SIGNAL LOG TRUNCATED...\n"); siglog_entries = siglog_truncated = 0; /* Okay, turn 'em on again. */ for (i = 0; i < POWER_SIGNAL_COUNT; i++) gpio_enable_interrupt(power_signal_list[i].gpio); } DECLARE_DEFERRED(siglog_deferred); static void siglog_add(enum gpio_signal signal) { if (siglog_entries >= MAX_SIGLOG_ENTRIES) { siglog_truncated = 1; return; } siglog[siglog_entries].time = get_time(); siglog[siglog_entries].signal = signal; siglog[siglog_entries].level = gpio_get_level(signal); siglog_entries++; hook_call_deferred(siglog_deferred, SECOND); } #define SIGLOG(S) siglog_add(S) #else #define SIGLOG(S) #endif /* CONFIG_BRINGUP */ void power_signal_interrupt(enum gpio_signal signal) { SIGLOG(signal); /* Shadow signals and compare with our desired signal state. */ power_update_signals(); /* Wake up the task */ task_wake(TASK_ID_CHIPSET); }
static int command_display_accel_info(int argc, char **argv) { char *e; int val; if (argc > 3) return EC_ERROR_PARAM_COUNT; /* First argument is on/off whether to display accel data. */ if (argc > 1) { if (!parse_bool(argv[1], &val)) return EC_ERROR_PARAM1; accel_disp = val; } /* * Second arg changes the accel task time interval. Note accel * sampling interval will be clobbered when chipset suspends or * resumes. */ if (argc > 2) { val = strtoi(argv[2], &e, 0); if (*e) return EC_ERROR_PARAM2; accel_interval = val * MSEC; task_wake(TASK_ID_MOTIONSENSE); } return EC_SUCCESS; }
static int verify_variable_not_set(int *var) { *var = 0; task_wake(TASK_ID_KEYSCAN); msleep(NO_KEYDOWN_DELAY_MS); return *var ? EC_ERROR_UNKNOWN : EC_SUCCESS; }
static int expect_no_keychange(void) { int old_count = fifo_add_count; task_wake(TASK_ID_KEYSCAN); msleep(NO_KEYDOWN_DELAY_MS); return (fifo_add_count == old_count) ? EC_SUCCESS : EC_ERROR_UNKNOWN; }
void tcpc_alert(int port) { int status; /* Read the Alert register from the TCPC */ tcpm_alert_status(port, &status); /* * Clear alert status for everything except RX_STATUS, which shouldn't * be cleared until we have successfully retrieved message. */ if (status & ~TCPC_REG_ALERT_RX_STATUS) i2c_write16(I2C_PORT_TCPC, I2C_ADDR_TCPC(port), TCPC_REG_ALERT, status & ~TCPC_REG_ALERT_RX_STATUS); if (status & TCPC_REG_ALERT_CC_STATUS) { /* CC status changed, wake task */ task_set_event(PD_PORT_TO_TASK_ID(port), PD_EVENT_CC, 0); } if (status & TCPC_REG_ALERT_RX_STATUS) { /* message received */ task_set_event(PD_PORT_TO_TASK_ID(port), PD_EVENT_RX, 0); } if (status & TCPC_REG_ALERT_RX_HARD_RST) { /* hard reset received */ pd_execute_hard_reset(port); task_wake(PD_PORT_TO_TASK_ID(port)); } if (status & TCPC_REG_ALERT_TX_COMPLETE) { /* transmit complete */ pd_transmit_complete(port, status & TCPC_REG_ALERT_TX_SUCCESS ? TCPC_TX_COMPLETE_SUCCESS : TCPC_TX_COMPLETE_FAILED); } }
static void wake_pmu_task_if_necessary(void) { if (has_pending_event) { has_pending_event = 0; task_wake(TASK_ID_CHARGER); } }
/*---------------------------------------------------------------------------*/ void kbd_isr (u8 key_press) { /* If the Keypress is valid, give the Semaphore */ if (kbd_char_get (key_press, &key) == GOOD) task_wake (task_id) ; } /* End of function kbd_isr() */
static void unplug(int port) { pd_port[port].has_vbus = 0; pd_port[port].partner_role = -1; task_wake(PD_PORT_TO_TASK_ID(port)); usleep(30 * MSEC); }
/* * motion_sense_set_accel_interval * * Set the wake up interval for the motion sense thread. * It is set to the highest frequency one of the sensors need to be polled at. * * Note: Not static to be tested. */ int motion_sense_set_accel_interval(void) { int i, sensor_ec_rate, ec_rate, wake_up = 0; struct motion_sensor_t *sensor; for (i = 0, ec_rate = 0; i < motion_sensor_count; ++i) { sensor = &motion_sensors[i]; /* * If the sensor is sleeping, no need to check it periodicaly. */ if ((sensor->state != SENSOR_INITIALIZED) || (sensor->drv->get_data_rate(sensor) == 0)) continue; sensor_ec_rate = motion_sense_ec_rate(sensor); if ((ec_rate == 0 && sensor_ec_rate != 0) || (sensor_ec_rate != 0 && sensor_ec_rate < ec_rate)) ec_rate = sensor_ec_rate; } /* * Wake up the motion sense task: we want to sensor task to take * in account the new period right away. */ if (accel_interval == 0 || (ec_rate > 0 && accel_interval > ec_rate)) wake_up = 1; accel_interval = ec_rate; if (wake_up) task_wake(TASK_ID_MOTIONSENSE); return accel_interval; }
void chipset_exit_hard_off(void) { /* * If not in the soft-off state, hard-off state, or headed there, * nothing to do. */ if (state != POWER_G3 && state != POWER_S5G3 && state != POWER_S5) return; /* * Set a flag to leave G3, then wake the task. If the power state is * POWER_S5G3, or is POWER_S5 but the S5 inactivity timer has * expired, set this flag can let system go to G3 and then exit G3 * immediately for powering on. */ want_g3_exit = 1; /* * If the power state is in POWER_S5 and S5 inactivity timer is * running, to wake the chipset task can cancel S5 inactivity timer and * then restart the timer. This will give cpu a chance to start up if * S5 inactivity timer is about to expire while power button is * pressed. For other states here, to wake the chipset task to trigger * the event for leaving G3 is necessary. */ if (task_start_called()) task_wake(TASK_ID_CHIPSET); }
void keyboard_raw_interrupt(void) { /* Clear interrupt status bits */ MEC1322_KS_KSI_STATUS = 0xff; /* Wake keyboard scan task to handle interrupt */ task_wake(TASK_ID_KEYSCAN); }
/* KB controller input buffer full ISR */ void lpc_kbc_ibf_interrupt(void) { /* If "command" input 0, else 1*/ if (lpc_keyboard_input_pending()) keyboard_host_write(NPCX_HIKMDI, (NPCX_HIKMST & 0x08) ? 1 : 0); CPRINTS("ibf isr %02x", NPCX_HIKMDI); task_wake(TASK_ID_KEYPROTO); }
static int wait_charging_state(void) { enum charge_state state; task_wake(TASK_ID_CHARGER); msleep(WAIT_CHARGER_TASK); state = charge_get_state(); ccprintf("[CHARGING TEST] state = %d\n", state); return state; }
static void rockchip_lid_event(void) { /* Power task only cares about lid-open events */ if (!lid_is_open()) return; lid_opened = 1; task_wake(TASK_ID_CHIPSET); }
/** * Handle charge state changes */ static void powerbtn_x86_charge(void) { /* * If we were waiting for the charge state machine to init before we * powered on the chipset, we can stop waiting. */ if (pwrbtn_state == PWRBTN_STATE_INIT_ON) task_wake(TASK_ID_POWERBTN); }
/* KB controller output buffer empty ISR */ void lpc_kbc_obe_interrupt(void) { /* Disable KBC OBE interrupt */ CLEAR_BIT(NPCX_HICTRL, NPCX_HICTRL_OBECIE); task_disable_irq(NPCX_IRQ_KBC_OBE); CPRINTS("obe isr %02x", NPCX_HIKMST); task_wake(TASK_ID_KEYPROTO); }
void power_button_pch_pulse(void) { CPRINTS("PB PCH pulse"); chipset_exit_hard_off(); set_pwrbtn_to_pch(0); pwrbtn_state = PWRBTN_STATE_LID_OPEN; tnext_state = get_time().val + PWRBTN_INITIAL_US; task_wake(TASK_ID_POWERBTN); }
void pmu_task_throttled_wake(void) { timestamp_t now = get_time(); if (now.val - last_waken.val >= HOOK_TICK_INTERVAL) { has_pending_event = 0; task_wake(TASK_ID_CHARGER); } else { has_pending_event = 1; } }
void chipset_exit_hard_off(void) { /* If not in the hard-off state nor headed there, nothing to do */ if (state != POWER_G3 && state != POWER_S5G3) return; /* Set a flag to leave G3, then wake the task */ want_g3_exit = 1; task_wake(TASK_ID_CHIPSET); }
static int expect_keychange(void) { int old_count = fifo_add_count; int retry = KEYDOWN_RETRY; task_wake(TASK_ID_KEYSCAN); while (retry--) { msleep(KEYDOWN_DELAY_MS); if (fifo_add_count > old_count) return EC_SUCCESS; } return EC_ERROR_UNKNOWN; }
static int wait_variable_set(int *var) { int retry = KEYDOWN_RETRY; *var = 0; task_wake(TASK_ID_KEYSCAN); while (retry--) { msleep(KEYDOWN_DELAY_MS); if (*var == 1) return EC_SUCCESS; } return EC_ERROR_UNKNOWN; }
/* * Header: Run the task in three parts: wake - decode - execute * * Params: tsk - task to run * Return: ETRSLP - task is still sleeping and yielded before run * ETRPAU - task was paused and yielded before run * ETRINS - invalid instruction, now in error state * ETRPWM - invalid target, now in error state * ETRNLP - encountered nested loop, now in error state * * Description: * * This function is decomposed into three (static) functions. First, we try to * wake the task from sleep (if necessary). If we cannot wake from sleep yet, * then we return immediately - we do not consider the task to have run at * all in that cycle. * * Before we run instruction decode, we transfer last cycle's target to this * cycle's current position. That is, if the last instruction was a MOV, we * are now at that position. * * Next is instruction decode. If any error occurs here, we throw the task * into error state. * * Finally, the instruction itself is executed. In the case of an invalid * target or encounter of a nested loop, we throw the task into error state. * * Overall, note this function deals primarly with two control variables: * * - result: contains success or an error code * * - increment_pc: some branches in this function require that $pc not be * incremented. For example, when we return after not waking from sleep, * we are still on the same instruction. */ char task_run(struct task *tsk) { char result = 0; /* Initially assume function will succeed */ char increment_pc = 1; /* Initially assume $pc will be incremented */ char wake_result, decode_result, exe_result; /* intermediates */ unsigned char opcode, params; /* This determines if the task should RUN or YIELD IMMEDIATELY */ switch(wake_result = task_wake(tsk)) { case ETRSLP: case ETRPAU: case ETREND: case ETRCRT: increment_pc = 0; /* Do NOT increment PC! */ result = wake_result; goto yield; } tsk->state = ST_RUNNING; tsk->cur_pos = tsk->mov_pos; /* We're now at last cycle's target */ /* If decode fails, the func will return ETRINS */ switch(decode_result = task_instr_decode(tsk, &opcode, ¶ms)) { case ETRINS: increment_pc = 0; /* Do NOT increment PC! */ result = decode_result; goto yield; } switch(exe_result = task_instr_exe(tsk, opcode, params)) { case ETRPWM: case ETRNLP: case ETREND: increment_pc = 0; /* Do NOT increment PC! */ result = exe_result; goto yield; } tsk->state = ST_SLEEPING; yield: if(increment_pc) tsk->pc++; /* (else: i.e. fail to wake from sleep) */ if(tsk->state == ST_END && tsk->preempted) { task_fake_stack_pop(tsk); } return result; }