From adb9732230e91dbbf76d68e5e9aeb91d60b3d6bf Mon Sep 17 00:00:00 2001 From: Mayank Rana Date: Mon, 15 Jan 2018 16:23:45 -0800 Subject: [PATCH] usb: dwc3: debug: Add logging APIs using IPC logging framework This change creates separate debug buffer with each DWC instance and provides debug API to log different important events using IPC logging framework. CRs-Fixed: 1040809 Change-Id: I9aee21a99f5bcd0e82e81092c05bc2238863f5e4 Signed-off-by: Mayank Rana [jackp@codeaurora: since debug.c is gone, added debug_ipc.c] Signed-off-by: Jack Pham --- drivers/usb/dwc3/Makefile | 2 +- drivers/usb/dwc3/core.c | 18 +++++ drivers/usb/dwc3/core.h | 8 ++ drivers/usb/dwc3/debug.h | 39 ++++++++++ drivers/usb/dwc3/debug_ipc.c | 138 +++++++++++++++++++++++++++++++++++ 5 files changed, 204 insertions(+), 1 deletion(-) create mode 100644 drivers/usb/dwc3/debug_ipc.c diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile index ae86da0dc5bd..82c07f309908 100644 --- a/drivers/usb/dwc3/Makefile +++ b/drivers/usb/dwc3/Makefile @@ -4,7 +4,7 @@ CFLAGS_trace.o := -I$(src) obj-$(CONFIG_USB_DWC3) += dwc3.o -dwc3-y := core.o +dwc3-y := core.o debug_ipc.o ifneq ($(CONFIG_TRACING),) dwc3-y += trace.o diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index bb59787d803a..ed2d8b9a7315 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -40,6 +40,9 @@ #define DWC3_DEFAULT_AUTOSUSPEND_DELAY 5000 /* ms */ +static int count; +static struct dwc3 *dwc3_instance[DWC_CTRL_COUNT]; + /** * dwc3_get_dr_mode - Validates and sets dr_mode * @dwc: pointer to our context structure @@ -1523,6 +1526,16 @@ static int dwc3_probe(struct platform_device *pdev) goto err5; dwc3_debugfs_init(dwc); + + dwc->dwc_ipc_log_ctxt = ipc_log_context_create(NUM_LOG_PAGES, + dev_name(dwc->dev), 0); + if (!dwc->dwc_ipc_log_ctxt) + dev_err(dwc->dev, "Error getting ipc_log_ctxt\n"); + + dwc3_instance[count] = dwc; + dwc->index = count; + count++; + pm_runtime_put(dev); return 0; @@ -1571,6 +1584,11 @@ static int dwc3_remove(struct platform_device *pdev) dwc3_free_event_buffers(dwc); dwc3_free_scratch_buffers(dwc); + ipc_log_context_destroy(dwc->dwc_ipc_log_ctxt); + dwc->dwc_ipc_log_ctxt = NULL; + count--; + dwc3_instance[dwc->index] = NULL; + return 0; } diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 916497bfeba4..5bf72e1fab1a 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -606,6 +606,9 @@ #define DWC3_OSTS_VBUSVLD BIT(1) #define DWC3_OSTS_CONIDSTS BIT(0) +#define DWC_CTRL_COUNT 10 +#define NUM_LOG_PAGES 12 + /* Structures */ struct dwc3_trb; @@ -1033,6 +1036,8 @@ struct dwc3_scratchpad_array { * @imod_interval: set the interrupt moderation interval in 250ns * increments or 0 to disable. * @xhci_imod_value: imod value to use with xhci + * @index: dwc3's instance number + * @dwc_ipc_log_ctxt: dwc3 ipc log context */ struct dwc3 { struct work_struct drd_work; @@ -1223,6 +1228,9 @@ struct dwc3 { u16 imod_interval; u32 xhci_imod_value; + + unsigned int index; + void *dwc_ipc_log_ctxt; }; #define INCRX_BURST_MODE 0 diff --git a/drivers/usb/dwc3/debug.h b/drivers/usb/dwc3/debug.h index 9baabed87d61..84350b90457e 100644 --- a/drivers/usb/dwc3/debug.h +++ b/drivers/usb/dwc3/debug.h @@ -12,6 +12,33 @@ #define __DWC3_DEBUG_H #include "core.h" +#include + +/* + * NOTE: Make sure to have dwc as local variable in function before using + * below macros. + */ +#define dbg_event(ep_num, name, status) \ + dwc3_dbg_print(dwc, ep_num, name, status, "") + +#define dbg_print(ep_num, name, status, extra) \ + dwc3_dbg_print(dwc, ep_num, name, status, extra) + +#define dbg_print_reg(name, reg) \ + dwc3_dbg_print_reg(dwc, name, reg) + +#define dbg_done(ep_num, count, status) \ + dwc3_dbg_done(dwc, ep_num, count, status) + +#define dbg_queue(ep_num, req, status) \ + dwc3_dbg_queue(dwc, ep_num, req, status) + +#define dbg_setup(ep_num, req) \ + dwc3_dbg_setup(dwc, ep_num, req) + +#define dbg_log_string(fmt, ...) \ + ipc_log_string(dwc->dwc_ipc_log_ctxt,\ + "%s: " fmt, __func__, ##__VA_ARGS__) /** * dwc3_gadget_ep_cmd_string - returns endpoint command string @@ -416,6 +443,18 @@ static inline const char *dwc3_gadget_generic_cmd_status_string(int status) } } +void dwc3_dbg_print(struct dwc3 *dwc, u8 ep_num, + const char *name, int status, const char *extra); +void dwc3_dbg_done(struct dwc3 *dwc, u8 ep_num, + const u32 count, int status); +void dwc3_dbg_event(struct dwc3 *dwc, u8 ep_num, + const char *name, int status); +void dwc3_dbg_queue(struct dwc3 *dwc, u8 ep_num, + const struct usb_request *req, int status); +void dwc3_dbg_setup(struct dwc3 *dwc, u8 ep_num, + const struct usb_ctrlrequest *req); +void dwc3_dbg_print_reg(struct dwc3 *dwc, + const char *name, int reg); #ifdef CONFIG_DEBUG_FS extern void dwc3_debugfs_init(struct dwc3 *); diff --git a/drivers/usb/dwc3/debug_ipc.c b/drivers/usb/dwc3/debug_ipc.c new file mode 100644 index 000000000000..b6942466af0f --- /dev/null +++ b/drivers/usb/dwc3/debug_ipc.c @@ -0,0 +1,138 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + */ + +#include "debug.h" + +#include + +static unsigned int ep_addr_rxdbg_mask = 1; +module_param(ep_addr_rxdbg_mask, uint, 0644); +static unsigned int ep_addr_txdbg_mask = 1; +module_param(ep_addr_txdbg_mask, uint, 0644); + +static int allow_dbg_print(u8 ep_num) +{ + int dir, num; + + /* allow bus wide events */ + if (ep_num == 0xff) + return 1; + + dir = ep_num & 0x1; + num = ep_num >> 1; + num = 1 << num; + + if (dir && (num & ep_addr_txdbg_mask)) + return 1; + if (!dir && (num & ep_addr_rxdbg_mask)) + return 1; + + return 0; +} + +/** + * dwc3_dbg_print: prints the common part of the event + * @addr: endpoint address + * @name: event name + * @status: status + * @extra: extra information + * @dwc3: pointer to struct dwc3 + */ +void dwc3_dbg_print(struct dwc3 *dwc, u8 ep_num, const char *name, + int status, const char *extra) +{ + if (!allow_dbg_print(ep_num)) + return; + + if (name == NULL) + return; + + ipc_log_string(dwc->dwc_ipc_log_ctxt, "%02X %-25.25s %4i ?\t%s", + ep_num, name, status, extra); +} + +/** + * dwc3_dbg_done: prints a DONE event + * @addr: endpoint address + * @td: transfer descriptor + * @status: status + * @dwc3: pointer to struct dwc3 + */ +void dwc3_dbg_done(struct dwc3 *dwc, u8 ep_num, + const u32 count, int status) +{ + if (!allow_dbg_print(ep_num)) + return; + + ipc_log_string(dwc->dwc_ipc_log_ctxt, "%02X %-25.25s %4i ?\t%d", + ep_num, "DONE", status, count); +} + +/** + * dwc3_dbg_event: prints a generic event + * @addr: endpoint address + * @name: event name + * @status: status + */ +void dwc3_dbg_event(struct dwc3 *dwc, u8 ep_num, const char *name, int status) +{ + if (!allow_dbg_print(ep_num)) + return; + + if (name != NULL) + dwc3_dbg_print(dwc, ep_num, name, status, ""); +} + +/* + * dwc3_dbg_queue: prints a QUEUE event + * @addr: endpoint address + * @req: USB request + * @status: status + */ +void dwc3_dbg_queue(struct dwc3 *dwc, u8 ep_num, + const struct usb_request *req, int status) +{ + if (!allow_dbg_print(ep_num)) + return; + + if (req != NULL) { + ipc_log_string(dwc->dwc_ipc_log_ctxt, + "%02X %-25.25s %4i ?\t%d %d", ep_num, "QUEUE", status, + !req->no_interrupt, req->length); + } +} + +/** + * dwc3_dbg_setup: prints a SETUP event + * @addr: endpoint address + * @req: setup request + */ +void dwc3_dbg_setup(struct dwc3 *dwc, u8 ep_num, + const struct usb_ctrlrequest *req) +{ + if (!allow_dbg_print(ep_num)) + return; + + if (req != NULL) { + ipc_log_string(dwc->dwc_ipc_log_ctxt, + "%02X %-25.25s ?\t%02X %02X %04X %04X %d", + ep_num, "SETUP", req->bRequestType, + req->bRequest, le16_to_cpu(req->wValue), + le16_to_cpu(req->wIndex), le16_to_cpu(req->wLength)); + } +} + +/** + * dwc3_dbg_print_reg: prints a reg value + * @name: reg name + * @reg: reg value to be printed + */ +void dwc3_dbg_print_reg(struct dwc3 *dwc, const char *name, int reg) +{ + if (name == NULL) + return; + + ipc_log_string(dwc->dwc_ipc_log_ctxt, "%s = 0x%08x", name, reg); +}