twinkie: send raw packet traces to sniffer endpoint

When using the PD packet tracer and we are in raw mode (aka 'tw trace
raw'), send the packet data to the sniffer endpoint rather than the USB
console. This way we avoid having mixed asynchronous packet trace inside
our command trace.
Then, put the raw packet trace in binary rather than text, with
following format (as 32-bit words) :
[0] micro-second timestamp
[2] PD header
[2..8] PD payloads (unused ones might be junk)
[9..15] junk

Signed-off-by: Vincent Palatin <vpalatin@chromium.org>

BRANCH=twinkie
BUG=none
TEST=trace a PD sequence with Twebkie.

Change-Id: I551ab468f663b2702b7d6e3f0bb51bdb9cfb414a
Reviewed-on: https://chromium-review.googlesource.com/742920
Tested-by: Vincent Palatin <vpalatin@chromium.org>
Trybot-Ready: Vincent Palatin <vpalatin@chromium.org>
Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
Commit-Queue: Vincent Palatin <vpalatin@chromium.org>
diff --git a/board/twinkie/board.h b/board/twinkie/board.h
index 3223570..341909e 100644
--- a/board/twinkie/board.h
+++ b/board/twinkie/board.h
@@ -70,6 +70,8 @@
 
 #ifndef __ASSEMBLER__
 
+struct rx_header;
+
 void sniffer_init(void);
 
 int wait_packet(int pol, uint32_t min_edges, uint32_t timeout_us);
@@ -82,6 +84,9 @@
 
 void set_trace_mode(int mode);
 
+void sniffer_trace_packet(struct rx_header rx, uint32_t *payload);
+void sniffer_trace_reload(void);
+
 /* Timer selection */
 #define TIM_CLOCK_MSB  3
 #define TIM_CLOCK_LSB 15
diff --git a/board/twinkie/ec.tasklist b/board/twinkie/ec.tasklist
index e09bfd6..5c5213b 100644
--- a/board/twinkie/ec.tasklist
+++ b/board/twinkie/ec.tasklist
@@ -19,5 +19,5 @@
 #define CONFIG_TASK_LIST \
 	TASK_ALWAYS(HOOKS, hook_task, NULL, TASK_STACK_SIZE) \
 	TASK_ALWAYS(CONSOLE, console_task, NULL, LARGER_TASK_STACK_SIZE) \
-	TASK_ALWAYS_RO(SNIFFER, sniffer_task, NULL, TASK_STACK_SIZE) \
+	TASK_ALWAYS_RO(SNIFFER, sniffer_task, NULL, LARGER_TASK_STACK_SIZE) \
 	TASK_ALWAYS_RW(PD_C0, pd_task, NULL, LARGER_TASK_STACK_SIZE)
diff --git a/board/twinkie/simpletrace.c b/board/twinkie/simpletrace.c
index 2f0a5ba..81e5c23 100644
--- a/board/twinkie/simpletrace.c
+++ b/board/twinkie/simpletrace.c
@@ -127,13 +127,6 @@
 		ccprintf("ERR %d\n", rx.packet_type); return;
 	}
 
-	if (trace_mode == TRACE_MODE_RAW) {
-		ccprintf("%T[%04x]", head);
-		for (i = 0; i < cnt; i++)
-			ccprintf(" %08x", payload[i]);
-		ccputs("\n");
-		return;
-	}
 	name = cnt ? data_msg_name[typ] : ctrl_msg_name[typ];
 	prole = head & (PD_ROLE_SOURCE << 8) ? "SRC" : "SNK";
 	ccprintf("%T %s/%d [%04x]%s", prole, id, head, name);
@@ -201,7 +194,7 @@
 				pd_rx_disable_monitoring(0);
 				/* trigger the analysis in the task */
 #ifdef HAS_TASK_SNIFFER
-				task_set_event(TASK_ID_SNIFFER, 1 << i, 0);
+				task_set_event(TASK_ID_SNIFFER, 4 << i, 0);
 #endif
 				/* start reception only one CC line */
 				break;
@@ -221,6 +214,7 @@
 {
 	struct rx_header rx;
 	uint32_t payload[7];
+	uint32_t evt;
 
 #ifdef HAS_TASK_SNIFFER
 	/* Disable sniffer DMA configuration */
@@ -240,9 +234,13 @@
 	pd_rx_enable_monitoring(0);
 
 	while (1) {
-		task_wait_event(-1);
+		evt = task_wait_event(-1);
 		if (trace_mode == TRACE_MODE_OFF)
 			break;
+		if (evt < 4) { /* USB event only */
+			sniffer_trace_reload();
+			continue;
+		}
 		/* incoming packet processing */
 		rx = pd_analyze_rx(0, payload);
 		pd_rx_complete(0);
@@ -250,7 +248,10 @@
 		STM32_COMP_CSR |= STM32_COMP_CMP2EN | STM32_COMP_CMP1EN;
 		pd_rx_enable_monitoring(0);
 		/* print the last packet content */
-		print_packet(rx, payload);
+		if (trace_mode == TRACE_MODE_RAW)
+			sniffer_trace_packet(rx, payload);
+		else
+			print_packet(rx, payload);
 		if (rx.packet_type >= 0 &&
 		    expected_cmd == PD_HEADER_TYPE(rx.head))
 			task_wake(TASK_ID_CONSOLE);
diff --git a/board/twinkie/sniffer.c b/board/twinkie/sniffer.c
index d929477..80887ba 100644
--- a/board/twinkie/sniffer.c
+++ b/board/twinkie/sniffer.c
@@ -18,6 +18,7 @@
 #include "timer.h"
 #include "usb_descriptor.h"
 #include "usb_hw.h"
+#include "usb_pd.h"
 #include "util.h"
 #include "ina2xx.h"
 
@@ -286,6 +287,11 @@
 /* state of the simple text tracer */
 extern int trace_mode;
 
+/* Index of the next buffer to use inside the 'samples' array */
+static uint32_t sp_idx;
+/* bitmap of the 'samples' sub-buffer filled with packet binary traces */
+static volatile uint32_t filled_pkt;
+
 /* Task to post-process the samples and copy them the USB endpoint buffer */
 void sniffer_task(void)
 {
@@ -321,12 +327,51 @@
 
 		if (trace_mode != TRACE_MODE_OFF) {
 			uint8_t curr = recording_enable(0);
+			filled_pkt = 0;
 			trace_packets();
+			filled_dma = 0;
 			recording_enable(curr);
 		}
 	}
 }
 
+void sniffer_trace_reload(void)
+{
+	static uint32_t u;
+	/* copy a new buffer to send over USB if needed */
+	while (free_usb && filled_pkt) {
+		static int idx;
+		uint8_t *buff;
+
+		while (!(filled_pkt & (1 << idx)))
+			idx = (idx + 1) & 31;
+		buff = &samples[idx >> 4][(idx & 0xF) * EP_PAYLOAD_SIZE];
+		/* it's faster to let some junk at the end of the buffer */
+		memcpy_to_usbram(((void *)usb_sram_addr(ep_buf[u])), buff, 40);
+		atomic_clear((uint32_t *)&free_usb, 1 << u);
+		u = !u;
+		filled_pkt &= ~(1 << idx);
+	}
+}
+
+void sniffer_trace_packet(struct rx_header rx, uint32_t *payload)
+{
+	uint32_t tstamp = __hw_clock_source_read();
+	uint32_t *buf = (uint32_t *)
+		&samples[sp_idx >> 4][(sp_idx & 0xF) * EP_PAYLOAD_SIZE];
+
+	buf[0] = tstamp;
+	buf[1] = sp_idx | 0xfada0000; /* reserved */
+	buf[2] = *(uint32_t *)&rx;
+	memcpy(buf + 3, payload, 7 * sizeof(uint32_t));
+	filled_pkt |= 1 << sp_idx;
+	sp_idx = (sp_idx + 1) & 31;
+
+	/* copy a new buffer to send over USB if starved */
+	if (free_usb == 3)
+		sniffer_trace_reload();
+}
+
 int wait_packet(int pol, uint32_t min_edges, uint32_t timeout_us)
 {
 	stm32_dma_chan_t *chan = dma_get_channel(pol ? DMAC_TIM_RX2