summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVincent Palatin <vpalatin@chromium.org>2015-01-06 11:00:36 -0800
committerChromeOS Commit Bot <chromeos-commit-bot@chromium.org>2015-01-30 03:28:10 +0000
commit3cbff2d21dd7ca85bd5a5b86587625305204e78f (patch)
tree38cb765711f9f2bcd3d89921c057959bc8d8f683
parent95e74550f27e93a2133c3b5437dd2bdde8ac8956 (diff)
downloadchrome-ec-3cbff2d21dd7ca85bd5a5b86587625305204e78f.tar.gz
Add PD events logging
Add a FIFO to log important events on the PD MCU and coming from the PD accessories. The retrieval of the accessories log from the accessories by the PD MCU is not implemented yet. Signed-off-by: Vincent Palatin <vpalatin@chromium.org> BRANCH=samus BUG=chrome-os-partner:32785 TEST=execute "ectool --name=cros_pd pdlog" before and after plugging Zinger charger. Original-Change-Id: If96d73e711ff6ad64cfb99bd3e4d2d8f2643f19a Reviewed-on: https://chromium-review.googlesource.com/238854 Tested-by: Vincent Palatin <vpalatin@chromium.org> Reviewed-by: Alec Berg <alecaberg@chromium.org> Commit-Queue: Vincent Palatin <vpalatin@chromium.org> Trybot-Ready: Vincent Palatin <vpalatin@chromium.org> (cherry picked from commit 4e75e20f4ec5cecda6742d821b1a4484952fd07e) Reviewed-on: https://chromium-review.googlesource.com/240837 Reviewed-by: Vincent Palatin <vpalatin@chromium.org> (cherry picked from commit d8563a8aa292bb225b7c9a1d998d01ef154a10fb) Signed-off-by: Todd Broch <tbroch@chromium.org> Change-Id: I1b0b2b6fc5b9788ccd749626541181d62d185589 Reviewed-on: https://chromium-review.googlesource.com/244222 Reviewed-by: Alec Berg <alecaberg@chromium.org> Tested-by: Todd Broch <tbroch@chromium.org> Commit-Queue: Todd Broch <tbroch@chromium.org>
-rw-r--r--board/dingdong/board.h2
-rw-r--r--board/dingdong/usb_pd_policy.c13
-rw-r--r--board/hoho/board.h2
-rw-r--r--board/hoho/usb_pd_policy.c13
-rw-r--r--board/samus_pd/board.h2
-rw-r--r--board/zinger/board.h2
-rw-r--r--board/zinger/runtime.c10
-rw-r--r--board/zinger/usb_pd_policy.c3
-rw-r--r--common/build.mk1
-rw-r--r--common/pd_log.c151
-rw-r--r--include/config.h6
-rw-r--r--include/ec_commands.h75
-rw-r--r--include/usb_pd.h29
13 files changed, 302 insertions, 7 deletions
diff --git a/board/dingdong/board.h b/board/dingdong/board.h
index 6247ae5fcc..666ab2699e 100644
--- a/board/dingdong/board.h
+++ b/board/dingdong/board.h
@@ -36,6 +36,8 @@
#define CONFIG_USB_PD_IDENTITY_HW_VERS 1
#define CONFIG_USB_PD_IDENTITY_SW_VERS 1
#define CONFIG_USB_PD_NO_VBUS_DETECT
+#define CONFIG_USB_PD_LOGGING
+#define CONFIG_USB_PD_LOG_SIZE 256
#undef CONFIG_WATCHDOG_HELP
#undef CONFIG_LID_SWITCH
#undef CONFIG_TASK_PROFILING
diff --git a/board/dingdong/usb_pd_policy.c b/board/dingdong/usb_pd_policy.c
index 5c14e4a6da..520732cd26 100644
--- a/board/dingdong/usb_pd_policy.c
+++ b/board/dingdong/usb_pd_policy.c
@@ -244,8 +244,17 @@ int pd_custom_vdm(int port, int cnt, uint32_t *payload,
*rpayload = payload;
rsize = pd_custom_flash_vdm(port, cnt, payload);
- if (!rsize)
- return 0;
+ if (!rsize) {
+ int cmd = PD_VDO_CMD(payload[0]);
+ switch (cmd) {
+ case VDO_CMD_GET_LOG:
+ rsize = pd_vdm_get_log_entry(payload);
+ break;
+ default:
+ /* Unknown : do not answer */
+ return 0;
+ }
+ }
/* respond (positively) to the request */
payload[0] |= VDO_SRC_RESPONDER;
diff --git a/board/hoho/board.h b/board/hoho/board.h
index 74e3951b53..58dc4db20a 100644
--- a/board/hoho/board.h
+++ b/board/hoho/board.h
@@ -42,6 +42,8 @@
#define CONFIG_USB_PD_INTERNAL_COMP
#define CONFIG_USB_PD_IDENTITY_HW_VERS 1
#define CONFIG_USB_PD_IDENTITY_SW_VERS 1
+#define CONFIG_USB_PD_LOGGING
+#define CONFIG_USB_PD_LOG_SIZE 256
#define CONFIG_USB_PD_NO_VBUS_DETECT
/* mcdp2850 serial interface */
#define CONFIG_MCDP28X0 usart3_hw
diff --git a/board/hoho/usb_pd_policy.c b/board/hoho/usb_pd_policy.c
index 9ecfd38611..efd1bbc243 100644
--- a/board/hoho/usb_pd_policy.c
+++ b/board/hoho/usb_pd_policy.c
@@ -243,8 +243,17 @@ int pd_custom_vdm(int port, int cnt, uint32_t *payload,
*rpayload = payload;
rsize = pd_custom_flash_vdm(port, cnt, payload);
- if (!rsize)
- return 0;
+ if (!rsize) {
+ int cmd = PD_VDO_CMD(payload[0]);
+ switch (cmd) {
+ case VDO_CMD_GET_LOG:
+ rsize = pd_vdm_get_log_entry(payload);
+ break;
+ default:
+ /* Unknown : do not answer */
+ return 0;
+ }
+ }
/* respond (positively) to the request */
payload[0] |= VDO_SRC_RESPONDER;
diff --git a/board/samus_pd/board.h b/board/samus_pd/board.h
index 58e917d269..5adb1c46fc 100644
--- a/board/samus_pd/board.h
+++ b/board/samus_pd/board.h
@@ -45,6 +45,8 @@
#define CONFIG_USB_PD_DUAL_ROLE
#define CONFIG_USB_PD_FLASH_ERASE_CHECK
#define CONFIG_USB_PD_INTERNAL_COMP
+#define CONFIG_USB_PD_LOGGING
+#define CONFIG_USB_PD_LOG_SIZE 512
#define CONFIG_USB_SWITCH_PI3USB9281
#undef CONFIG_USB_SWITCH_PI3USB9281_MUX_GPIO
#define CONFIG_USB_SWITCH_PI3USB9281_MUX_GPIO GPIO_USB_C_BC12_SEL
diff --git a/board/zinger/board.h b/board/zinger/board.h
index e307c6ff27..8eba23e214 100644
--- a/board/zinger/board.h
+++ b/board/zinger/board.h
@@ -51,6 +51,8 @@
#define CONFIG_USB_PD_CUSTOM_VDM
#undef CONFIG_USB_PD_DUAL_ROLE
#undef CONFIG_USB_PD_INTERNAL_COMP
+#define CONFIG_USB_PD_LOGGING
+#define CONFIG_USB_PD_LOG_SIZE 256
#undef CONFIG_USB_PD_RX_COMP_IRQ
#define CONFIG_USB_PD_SIMPLE_DFP
#undef CONFIG_WATCHDOG_HELP
diff --git a/board/zinger/runtime.c b/board/zinger/runtime.c
index 9d644e763a..0dfb51aed4 100644
--- a/board/zinger/runtime.c
+++ b/board/zinger/runtime.c
@@ -56,6 +56,16 @@ void task_clear_pending_irq(int irq)
CPU_NVIC_UNPEND(0) = 1 << irq;
}
+void interrupt_disable(void)
+{
+ asm("cpsid i");
+}
+
+void interrupt_enable(void)
+{
+ asm("cpsie i");
+}
+
uint32_t task_set_event(task_id_t tskid, uint32_t event, int wait)
{
last_event = event;
diff --git a/board/zinger/usb_pd_policy.c b/board/zinger/usb_pd_policy.c
index 2e658428d9..d61023a13a 100644
--- a/board/zinger/usb_pd_policy.c
+++ b/board/zinger/usb_pd_policy.c
@@ -553,6 +553,9 @@ int pd_custom_vdm(int port, int cnt, uint32_t *payload,
payload[1] = ADC_TO_CURR_MA(vbus_amp);
rsize = 2;
break;
+ case VDO_CMD_GET_LOG:
+ rsize = pd_vdm_get_log_entry(payload);
+ break;
default:
/* Unknown : do not answer */
return 0;
diff --git a/common/build.mk b/common/build.mk
index 10d74c907d..2bb32b4f98 100644
--- a/common/build.mk
+++ b/common/build.mk
@@ -80,6 +80,7 @@ common-$(CONFIG_TEMP_SENSOR)+=temp_sensor.o thermal.o throttle_ap.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_USB_POWER_DELIVERY)+=usb_pd_protocol.o usb_pd_policy.o
+common-$(CONFIG_USB_PD_LOGGING)+=pd_log.o
common-$(CONFIG_VBOOT_HASH)+=sha256.o vboot_hash.o
common-$(CONFIG_WIRELESS)+=wireless.o
common-$(HAS_TASK_CHIPSET)+=chipset.o
diff --git a/common/pd_log.c b/common/pd_log.c
new file mode 100644
index 0000000000..e48b763b6c
--- /dev/null
+++ b/common/pd_log.c
@@ -0,0 +1,151 @@
+/* Copyright (c) 2014 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.
+ */
+
+#include "console.h"
+#include "hooks.h"
+#include "host_command.h"
+#include "task.h"
+#include "timer.h"
+#include "util.h"
+
+/* Event log FIFO */
+#define UNIT_SIZE sizeof(struct ec_response_pd_log)
+#define LOG_SIZE (CONFIG_USB_PD_LOG_SIZE/UNIT_SIZE)
+static struct ec_response_pd_log log_events[LOG_SIZE];
+BUILD_ASSERT(POWER_OF_TWO(LOG_SIZE));
+/*
+ * The FIFO pointers are defined as following :
+ * "log_head" is the next available event to dequeue.
+ * "log_tail" is marking the end of the FIFO content (after last commited event)
+ * "log_tail_next" is the next available spot to enqueue events.
+ * The pointers are not wrapped until they are used, so we don't need an extra
+ * entry to disambiguate between full and empty FIFO.
+ *
+ * For concurrency, several tasks might try to enqueue events in parallel with
+ * pd_log_event(). Only one task is dequeuing events (host commands or VDM).
+ * When the FIFO is full, pd_log_event() will discard the oldest events,
+ * so "log_head" is incremented/decremented in a critical section since it is
+ * accessed from both pd_log_event() and pd_log_dequeue().
+ * log_tail_next is also protected as several writers can race to add an event
+ * to the queue.
+ * When a writer is done adding its event, it is updating log_tail,
+ * so the event can be consumed by pd_log_dequeue().
+ */
+static size_t log_head;
+static size_t log_tail;
+static size_t log_tail_next;
+
+/* Size of one FIFO entry */
+#define ENTRY_SIZE(payload_sz) (1+DIV_ROUND_UP((payload_sz), UNIT_SIZE))
+
+void pd_log_event(uint8_t type, uint8_t size_port,
+ uint16_t data, void *payload)
+{
+ struct ec_response_pd_log *r;
+ size_t payload_size = PD_LOG_SIZE(size_port);
+ size_t total_size = ENTRY_SIZE(payload_size);
+ size_t current_tail, first;
+
+ /* --- critical section : reserve queue space --- */
+ interrupt_disable();
+ current_tail = log_tail_next;
+ log_tail_next = current_tail + total_size;
+ interrupt_enable();
+ /* --- end of critical section --- */
+
+ /* Out of space : discard the oldest entry */
+ while ((LOG_SIZE - (current_tail - log_head)) < total_size) {
+ struct ec_response_pd_log *oldest;
+ /* --- critical section : atomically free-up space --- */
+ interrupt_disable();
+ oldest = log_events + (log_head & (LOG_SIZE - 1));
+ log_head += ENTRY_SIZE(PD_LOG_SIZE(oldest->size_port));
+ interrupt_enable();
+ /* --- end of critical section --- */
+ }
+
+ r = log_events + (current_tail & (LOG_SIZE - 1));
+
+ r->timestamp = get_time().val >> PD_LOG_TIMESTAMP_SHIFT;
+ r->type = type;
+ r->size_port = size_port;
+ r->data = data;
+ /* copy the payload into the FIFO */
+ first = MIN(total_size - 1, (LOG_SIZE -
+ (current_tail & (LOG_SIZE - 1))) - 1);
+ if (first)
+ memcpy(r->payload, payload, first * UNIT_SIZE);
+ if (first < total_size - 1)
+ memcpy(log_events, ((uint8_t *)payload) + first * UNIT_SIZE,
+ (total_size - first) * UNIT_SIZE);
+ /* mark the entry available in the queue if nobody is behind us */
+ if (current_tail == log_tail)
+ log_tail = log_tail_next;
+}
+
+static int pd_log_dequeue(struct ec_response_pd_log *r)
+{
+ uint32_t now = get_time().val >> PD_LOG_TIMESTAMP_SHIFT;
+ unsigned total_size, first;
+ struct ec_response_pd_log *entry;
+ size_t current_head;
+
+retry:
+ current_head = log_head;
+ /* The log FIFO is empty */
+ if (log_tail == current_head) {
+ memset(r, 0, UNIT_SIZE);
+ r->type = PD_EVENT_NO_ENTRY;
+ return UNIT_SIZE;
+ }
+
+ entry = log_events + (current_head & (LOG_SIZE - 1));
+ total_size = ENTRY_SIZE(PD_LOG_SIZE(entry->size_port));
+ first = MIN(total_size, LOG_SIZE - (current_head & (LOG_SIZE - 1)));
+ memcpy(r, entry, first * UNIT_SIZE);
+ if (first < total_size)
+ memcpy(r + first, log_events, (total_size-first) * UNIT_SIZE);
+
+ /* --- critical section : remove the entry from the queue --- */
+ interrupt_disable();
+ if (log_head != current_head) { /* our entry was thrown away */
+ interrupt_enable();
+ goto retry;
+ }
+ log_head += total_size;
+ interrupt_enable();
+ /* --- end of critical section --- */
+
+ /* fixup the timestamp : number of milliseconds in the past */
+ r->timestamp = now - r->timestamp;
+
+ return total_size * UNIT_SIZE;
+}
+
+#ifdef HAS_TASK_HOSTCMD
+/* we are a PD MCU/EC, send back the events to the host */
+static int hc_pd_get_log_entry(struct host_cmd_handler_args *args)
+{
+ struct ec_response_pd_log *r = args->response;
+
+ args->response_size = pd_log_dequeue(r);
+
+ return EC_RES_SUCCESS;
+}
+DECLARE_HOST_COMMAND(EC_CMD_PD_GET_LOG_ENTRY,
+ hc_pd_get_log_entry,
+ EC_VER_MASK(0));
+#else /* !HAS_TASK_HOSTCMD */
+/* we are a PD accessory, send back the events as a VDM (VDO_CMD_GET_LOG) */
+int pd_vdm_get_log_entry(uint32_t *payload)
+{
+ struct ec_response_pd_log *r = (void *)&payload[1];
+ int byte_size;
+
+ byte_size = pd_log_dequeue(r);
+
+ return 1 + DIV_ROUND_UP(byte_size, sizeof(uint32_t));
+}
+#endif /* !HAS_TASK_HOSTCMD */
diff --git a/include/config.h b/include/config.h
index 2270277265..e1903ea68a 100644
--- a/include/config.h
+++ b/include/config.h
@@ -1165,6 +1165,12 @@
/* Define if using internal comparator for PD receive */
#undef CONFIG_USB_PD_INTERNAL_COMP
+/* Record main PD events in a circular buffer */
+#undef CONFIG_USB_PD_LOGGING
+
+/* The size in bytes of the FIFO used for PD events logging */
+#undef CONFIG_USB_PD_LOG_SIZE
+
/* Define if USB-PD device has no way of detecting USB VBUS */
#undef CONFIG_USB_PD_NO_VBUS_DETECT
diff --git a/include/ec_commands.h b/include/ec_commands.h
index 898d502c6c..954a423f5d 100644
--- a/include/ec_commands.h
+++ b/include/ec_commands.h
@@ -2776,14 +2776,22 @@ enum usb_power_roles {
USB_PD_PORT_POWER_SINK_NOT_CHARGING,
};
+struct usb_chg_measures {
+ uint16_t voltage_max;
+ uint16_t voltage_now;
+ uint16_t current_max;
+ /*
+ * this structure is used below in struct ec_response_usb_pd_power_info,
+ * and currently expects an odd number of uint16_t for alignment.
+ */
+} __packed;
+
struct ec_response_usb_pd_power_info {
uint8_t role;
uint8_t type;
uint8_t dualrole;
uint8_t reserved1;
- uint16_t voltage_max;
- uint16_t voltage_now;
- uint16_t current_max;
+ struct usb_chg_measures meas;
uint16_t reserved2;
uint32_t max_power;
} __packed;
@@ -2845,6 +2853,67 @@ enum usb_pd_override_ports {
struct ec_params_charge_port_override {
int16_t override_port; /* Override port# */
} __packed;
+
+/* Read (and delete) one entry of PD event log */
+#define EC_CMD_PD_GET_LOG_ENTRY 0x115
+
+struct ec_response_pd_log {
+ uint32_t timestamp; /* relative timestamp in milliseconds */
+ uint8_t type; /* event type : see PD_EVENT_xx below */
+ uint8_t size_port; /* [7:5] port number [4:0] payload size in bytes */
+ uint16_t data; /* type-defined data payload */
+ uint8_t payload[0]; /* optional additional data payload: 0..16 bytes */
+} __packed;
+
+
+/* The timestamp is the microsecond counter shifted to get about a ms. */
+#define PD_LOG_TIMESTAMP_SHIFT 10 /* 1 LSB = 1024us */
+
+#define PD_LOG_SIZE_MASK 0x1F
+#define PD_LOG_PORT_MASK 0xE0
+#define PD_LOG_PORT_SHIFT 5
+#define PD_LOG_PORT_SIZE(port, size) (((port) << PD_LOG_PORT_SHIFT) | \
+ ((size) & PD_LOG_SIZE_MASK))
+#define PD_LOG_PORT(size_port) ((size_port) >> PD_LOG_PORT_SHIFT)
+#define PD_LOG_SIZE(size_port) ((size_port) & PD_LOG_SIZE_MASK)
+
+/* PD event log : entry types */
+/* PD MCU events */
+#define PD_EVENT_MCU_BASE 0x00
+#define PD_EVENT_MCU_CHARGE (PD_EVENT_MCU_BASE+0)
+#define PD_EVENT_MCU_CONNECT (PD_EVENT_MCU_BASE+1)
+/* PD generic accessory events */
+#define PD_EVENT_ACC_BASE 0x20
+#define PD_EVENT_ACC_RW_FAIL (PD_EVENT_ACC_BASE+0)
+#define PD_EVENT_ACC_RW_ERASE (PD_EVENT_ACC_BASE+1)
+#define PD_EVENT_ACC_GFU_ENTER (PD_EVENT_ACC_BASE+2)
+/* PD power supply events */
+#define PD_EVENT_PS_BASE 0x40
+#define PD_EVENT_PS_OCP (PD_EVENT_PS_BASE+0)
+#define PD_EVENT_PS_OVP (PD_EVENT_PS_BASE+1)
+#define PD_EVENT_PS_TEMP (PD_EVENT_PS_BASE+2)
+/* PD video dongles events */
+#define PD_EVENT_VIDEO_BASE 0x60
+/* Returned in the "type" field, when there is no entry available */
+#define PD_EVENT_NO_ENTRY 0xFF
+
+/*
+ * PD_EVENT_MCU_CHARGE event definition :
+ * the payload is "struct usb_chg_measures"
+ * the data field contains the port state flags as defined below :
+ */
+/* Port partner is a dual role device */
+#define CHARGE_FLAGS_DUAL_ROLE (1 << 15)
+/* Port is the pending override port */
+#define CHARGE_FLAGS_DELAYED_OVERRIDE (1 << 14)
+/* Port is the override port */
+#define CHARGE_FLAGS_OVERRIDE (1 << 13)
+/* Charger type */
+#define CHARGE_FLAGS_TYPE_SHIFT 3
+#define CHARGE_FLAGS_TYPE_MASK (0xF << CHARGE_FLAGS_TYPE_SHIFT)
+/* Power delivery role */
+#define CHARGE_FLAGS_ROLE_MASK (7 << 0)
+
#endif /* !__ACPI__ */
/*****************************************************************************/
diff --git a/include/usb_pd.h b/include/usb_pd.h
index 081e78c6f3..14b83ae41b 100644
--- a/include/usb_pd.h
+++ b/include/usb_pd.h
@@ -282,6 +282,7 @@ struct pd_policy {
#define VDO_CMD_PING_ENABLE VDO_CMD_VENDOR(10)
#define VDO_CMD_CURRENT VDO_CMD_VENDOR(11)
#define VDO_CMD_FLIP VDO_CMD_VENDOR(12)
+#define VDO_CMD_GET_LOG VDO_CMD_VENDOR(13)
#define PD_VDO_VID(vdo) ((vdo) >> 16)
#define PD_VDO_SVDM(vdo) (((vdo) >> 15) & 1)
@@ -1276,4 +1277,32 @@ void pd_prepare_sysjump(void);
*/
void pd_set_new_power_request(int port);
+/* ----- Logging ----- */
+#ifdef CONFIG_USB_PD_LOGGING
+/**
+ * Record one event in the PD logging FIFO.
+ *
+ * @param type event type as defined by PD_EVENT_xx in ec_commands.h
+ * @param size_port payload size and port num (defined by PD_LOG_PORT_SIZE)
+ * @param data type-defined information
+ * @param payload pointer to the optional payload (0..16 bytes)
+ */
+void pd_log_event(uint8_t type, uint8_t size_port,
+ uint16_t data, void *payload);
+
+/**
+ * Retrieve one logged event and prepare a VDM with it.
+ *
+ * Used to answer the VDO_CMD_GET_LOG unstructured VDM.
+ *
+ * @param payload pointer to the payload data buffer (must be 7 words)
+ * @return number of 32-bit words in the VDM payload.
+ */
+int pd_vdm_get_log_entry(uint32_t *payload);
+#else /* CONFIG_USB_PD_LOGGING */
+static inline void pd_log_event(uint8_t type, uint8_t size_port,
+ uint16_t data, void *payload) {}
+static inline int pd_vdm_get_log_entry(uint32_t *payload) { return 0; }
+#endif /* CONFIG_USB_PD_LOGGING */
+
#endif /* __USB_PD_H */