diff options
-rw-r--r-- | common/build.mk | 1 | ||||
-rw-r--r-- | common/usb_pd_protocol.c | 96 | ||||
-rw-r--r-- | common/usbc/usbc_task.c | 100 | ||||
-rw-r--r-- | common/usbc_intr_task.c | 105 |
4 files changed, 109 insertions, 193 deletions
diff --git a/common/build.mk b/common/build.mk index 4ef78d57f5..ebaa3cc582 100644 --- a/common/build.mk +++ b/common/build.mk @@ -143,6 +143,7 @@ common-$(CONFIG_USB_CONSOLE_STREAM)+=usb_console_stream.o common-$(CONFIG_USB_I2C)+=usb_i2c.o common-$(CONFIG_USB_PORT_POWER_DUMB)+=usb_port_power_dumb.o common-$(CONFIG_USB_PORT_POWER_SMART)+=usb_port_power_smart.o +common-$(CONFIG_HAS_TASK_PD_INT)+=usbc_intr_task.o ifneq ($(CONFIG_USB_POWER_DELIVERY),) common-$(CONFIG_USB_POWER_DELIVERY)+=usb_common.o ifneq ($(CONFIG_USB_PD_TCPMV1),) diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c index 45b91397b2..aed9e4dd86 100644 --- a/common/usb_pd_protocol.c +++ b/common/usb_pd_protocol.c @@ -2754,97 +2754,6 @@ static int pd_restart_tcpc(int port) } #endif -/* High-priority interrupt tasks implementations */ -#ifdef CONFIG_HAS_TASK_PD_INT - -/* Used to conditionally compile code in main pd task. */ -#define HAS_DEFFERED_INTERRUPT_HANDLER - -/* Events for pd_interrupt_handler_task */ -#define PD_PROCESS_INTERRUPT BIT(0) - -static uint8_t pd_int_task_id[CONFIG_USB_PD_PORT_MAX_COUNT]; - -void schedule_deferred_pd_interrupt(const int port) -{ - task_set_event(pd_int_task_id[port], PD_PROCESS_INTERRUPT, 0); -} - -/* - * Theoretically, we may need to support up to 480 USB-PD packets per second for - * intensive operations such as FW update over PD. This value has tested well - * preventing watchdog resets with a single bad port partner plugged in. - */ -#define ALERT_STORM_MAX_COUNT 480 -#define ALERT_STORM_INTERVAL SECOND - -/** - * Main task entry point that handles PD interrupts for a single port - * - * @param p The PD port number for which to handle interrupts (pointer is - * reinterpreted as an integer directly). - */ -void pd_interrupt_handler_task(void *p) -{ - const int port = (int) ((intptr_t) p); - const int port_mask = (PD_STATUS_TCPC_ALERT_0 << port); - struct { - int count; - timestamp_t time; - } storm_tracker[CONFIG_USB_PD_PORT_MAX_COUNT] = {}; - - ASSERT(port >= 0 && port < CONFIG_USB_PD_PORT_MAX_COUNT); - - pd_int_task_id[port] = task_get_current(); - - while (1) { - const int evt = task_wait_event(-1); - - if (evt & PD_PROCESS_INTERRUPT) { - /* - * While the interrupt signal is asserted; we have more - * work to do. This effectively makes the interrupt a - * level-interrupt instead of an edge-interrupt without - * having to enable/disable a real level-interrupt in - * multiple locations. - * - * Also, if the port is disabled do not process - * interrupts. Upon existing suspend, we schedule a - * PD_PROCESS_INTERRUPT to check if we missed anything. - */ - while ((tcpc_get_alert_status() & port_mask) && - pd_is_port_enabled(port)) { - timestamp_t now; - - tcpc_alert(port); - - now = get_time(); - if (timestamp_expired( - storm_tracker[port].time, &now)) { - /* Reset timer into future */ - storm_tracker[port].time.val = - now.val + ALERT_STORM_INTERVAL; - - /* - * Start at 1 since we are processing - * an interrupt now - */ - storm_tracker[port].count = 1; - } else if (++storm_tracker[port].count > - ALERT_STORM_MAX_COUNT) { - CPRINTS("C%d Interrupt storm detected. " - "Disabling port for 5 seconds.", - port); - - pd_set_suspend(port, 1); - pd_deferred_resume(port); - } - } - } - } -} -#endif /* CONFIG_HAS_TASK_PD_INT */ - static void pd_send_enter_usb(int port, int *timeout) { uint32_t usb4_payload; @@ -3100,7 +3009,6 @@ void pd_task(void *u) charge_manager_update_dualrole(port, CAP_UNKNOWN); #endif -#ifdef HAS_DEFFERED_INTERRUPT_HANDLER /* * Since most boards configure the TCPC interrupt as edge * and it is possible that the interrupt line was asserted between init @@ -3108,8 +3016,8 @@ void pd_task(void *u) * Otherwise future interrupts will never fire because another edge * never happens. Note this needs to happen after set_state() is called. */ - schedule_deferred_pd_interrupt(port); -#endif + if (IS_ENABLED(CONFIG_HAS_TASK_PD_INT)) + schedule_deferred_pd_interrupt(port); while (1) { /* process VDM messages last */ diff --git a/common/usbc/usbc_task.c b/common/usbc/usbc_task.c index f52d19ea0d..7099154f38 100644 --- a/common/usbc/usbc_task.c +++ b/common/usbc/usbc_task.c @@ -56,104 +56,6 @@ void tc_start_event_loop(int port) } } -/* High-priority interrupt tasks implementations */ -#ifdef CONFIG_HAS_TASK_PD_INT - -/* Used to conditionally compile code in main pd task. */ -#define HAS_DEFFERED_INTERRUPT_HANDLER - -/* Events for pd_interrupt_handler_task */ -#define PD_PROCESS_INTERRUPT (1<<0) - -static uint8_t pd_int_task_id[CONFIG_USB_PD_PORT_MAX_COUNT]; - -void schedule_deferred_pd_interrupt(const int port) -{ - task_set_event(pd_int_task_id[port], PD_PROCESS_INTERRUPT, 0); -} - -/* - * Theoretically, we may need to support up to 400 USB-PD packets per second for - * intensive operations such as FW update over PD. This value has tested well - * preventing watchdog resets with a single bad port partner plugged in. - */ -#define ALERT_STORM_MAX_COUNT 400 -#define ALERT_STORM_INTERVAL SECOND - -/* - * Main task entry point that handles PD interrupts for a single port - * - * @param p The PD port number for which to handle interrupts (pointer is - * reinterpreted as an integer directly). - */ -void pd_interrupt_handler_task(void *p) -{ - const int port = (int) ((intptr_t) p); - const int port_mask = (PD_STATUS_TCPC_ALERT_0 << port); - struct { - int count; - timestamp_t time; - } storm_tracker[CONFIG_USB_PD_PORT_MAX_COUNT] = {}; - - ASSERT(port >= 0 && port < CONFIG_USB_PD_PORT_MAX_COUNT); - - /* - * If port does not exist, return - */ - if (port >= board_get_usb_pd_port_count()) - return; - - pd_int_task_id[port] = task_get_current(); - - while (1) { - const int evt = task_wait_event(-1); - - if (evt & PD_PROCESS_INTERRUPT) { - /* - * While the interrupt signal is asserted; we have more - * work to do. This effectively makes the interrupt a - * level-interrupt instead of an edge-interrupt without - * having to enable/disable a real level-interrupt in - * multiple locations. - * - * Also, if the port is disabled do not process - * interrupts. Upon existing suspend, we schedule a - * PD_PROCESS_INTERRUPT to check if we missed anything. - */ - while ((tcpc_get_alert_status() & port_mask) && - pd_is_port_enabled(port)) { - timestamp_t now; - - tcpc_alert(port); - - now = get_time(); - if (timestamp_expired(storm_tracker[port].time, - &now)) { - /* Reset timer into future */ - storm_tracker[port].time.val = - now.val + ALERT_STORM_INTERVAL; - - /* - * Start at 1 since we are processing an - * interrupt right now - */ - storm_tracker[port].count = 1; - } else if (++storm_tracker[port].count > - ALERT_STORM_MAX_COUNT) { - CPRINTS("C%d: Interrupt storm detected." - " Disabling port temporarily", - port); - - pd_set_suspend(port, 1); - pd_deferred_resume(port); - } - } - } - } -} -#endif /* CONFIG_HAS_TASK_PD_INT */ - - static void pd_task_init(int port) { if (IS_ENABLED(CONFIG_USB_TYPEC_SM)) @@ -167,7 +69,7 @@ static void pd_task_init(int port) * Otherwise future interrupts will never fire because another edge * never happens. Note this needs to happen after set_state() is called. */ - if (IS_ENABLED(HAS_DEFFERED_INTERRUPT_HANDLER)) + if (IS_ENABLED(CONFIG_HAS_TASK_PD_INT)) schedule_deferred_pd_interrupt(port); } diff --git a/common/usbc_intr_task.c b/common/usbc_intr_task.c new file mode 100644 index 0000000000..ca410363f1 --- /dev/null +++ b/common/usbc_intr_task.c @@ -0,0 +1,105 @@ +/* Copyright 2020 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/* High-priority interrupt tasks implementations */ + +#include "console.h" +#include "task.h" +#include "timer.h" +#include "usb_mux.h" +#include "usb_pd.h" + +#define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args) +#define CPRINTS(format, args...) cprints(CC_USBPD, format, ## args) + +/* Events for pd_interrupt_handler_task */ +#define PD_PROCESS_INTERRUPT BIT(0) + +/* + * Theoretically, we may need to support up to 480 USB-PD packets per second for + * intensive operations such as FW update over PD. This value has tested well + * preventing watchdog resets with a single bad port partner plugged in. + */ +#define ALERT_STORM_MAX_COUNT 480 +#define ALERT_STORM_INTERVAL SECOND + +static uint8_t pd_int_task_id[CONFIG_USB_PD_PORT_MAX_COUNT]; + +void schedule_deferred_pd_interrupt(const int port) +{ + task_set_event(pd_int_task_id[port], PD_PROCESS_INTERRUPT, 0); +} + +/* + * Main task entry point that handles PD interrupts for a single port + * + * @param p The PD port number for which to handle interrupts (pointer is + * reinterpreted as an integer directly). + */ +void pd_interrupt_handler_task(void *p) +{ + const int port = (int) ((intptr_t) p); + const int port_mask = (PD_STATUS_TCPC_ALERT_0 << port); + struct { + int count; + timestamp_t time; + } storm_tracker[CONFIG_USB_PD_PORT_MAX_COUNT] = {}; + + ASSERT(port >= 0 && port < CONFIG_USB_PD_PORT_MAX_COUNT); + + /* + * If port does not exist, return + */ + if (port >= board_get_usb_pd_port_count()) + return; + + pd_int_task_id[port] = task_get_current(); + + while (1) { + const int evt = task_wait_event(-1); + + if (evt & PD_PROCESS_INTERRUPT) { + /* + * While the interrupt signal is asserted; we have more + * work to do. This effectively makes the interrupt a + * level-interrupt instead of an edge-interrupt without + * having to enable/disable a real level-interrupt in + * multiple locations. + * + * Also, if the port is disabled do not process + * interrupts. Upon existing suspend, we schedule a + * PD_PROCESS_INTERRUPT to check if we missed anything. + */ + while ((tcpc_get_alert_status() & port_mask) && + pd_is_port_enabled(port)) { + timestamp_t now; + + tcpc_alert(port); + + now = get_time(); + if (timestamp_expired(storm_tracker[port].time, + &now)) { + /* Reset timer into future */ + storm_tracker[port].time.val = + now.val + ALERT_STORM_INTERVAL; + + /* + * Start at 1 since we are processing an + * interrupt right now + */ + storm_tracker[port].count = 1; + } else if (++storm_tracker[port].count > + ALERT_STORM_MAX_COUNT) { + CPRINTS("C%d: Interrupt storm detected." + " Disabling port temporarily", + port); + + pd_set_suspend(port, 1); + pd_deferred_resume(port); + } + } + } + } +} |