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); +}