Wesley Cheng 2a3c2ae619 usb: dwc3: dwc3-msm-ops: Modify DWC3 traces to enable ftrace over IPC
Modify kretprobe tracepoint symbols for capturing DWC3 ftrace logs into
IPC.  This is useful for capturing any errors that may happen within the
DWC3 core.

Change-Id: Ic54aedd0d948263553b87bdb1e01faf4e83d6384
Signed-off-by: Wesley Cheng <quic_wcheng@quicinc.com>
2023-02-27 12:43:01 -08:00

301 lines
7.3 KiB
C

// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
* Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include "debug-ipc.h"
#include <linux/moduleparam.h>
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;
}
void dwc3_dbg_trace_log_ctrl(void *log_ctxt, struct usb_ctrlrequest *ctrl)
{
char *ctrl_req_str;
if (ctrl == NULL)
return;
ctrl_req_str = kzalloc(DWC3_MSG_MAX, GFP_ATOMIC);
if (!ctrl_req_str)
return;
usb_decode_ctrl(ctrl_req_str, DWC3_MSG_MAX, ctrl->bRequestType,
ctrl->bRequest, le16_to_cpu(ctrl->wValue),
le16_to_cpu(ctrl->wIndex),
le16_to_cpu(ctrl->wLength));
ipc_log_string(log_ctxt, "dbg_trace_log_ctrl: %s", ctrl_req_str);
kfree(ctrl_req_str);
}
void dwc3_dbg_trace_log_request(void *log_ctxt, struct dwc3_request *req,
char *tag)
{
struct dwc3_ep *dep;
if (req == NULL)
return;
dep = req->dep;
ipc_log_string(log_ctxt, "%s: %s: req %p length %u/%u %s%s%s ==> %d",
tag, dep->name, req, req->request.actual,
req->request.length,
req->request.zero ? "Z" : "z",
req->request.short_not_ok ? "S" : "s",
req->request.no_interrupt ? "i" : "I",
req->request.status);
}
void dwc3_dbg_trace_ep_cmd(void *log_ctxt, struct dwc3_ep *dep,
unsigned int cmd,
struct dwc3_gadget_ep_cmd_params *params,
int cmd_status)
{
ipc_log_string(log_ctxt,
"dbg_send_ep_cmd: %s: cmd '%s' [%x] params %08x %08x %08x --> status: %s",
dep->name, dwc3_gadget_ep_cmd_string(cmd), cmd, params->param0,
params->param1, params->param2, dwc3_ep_cmd_status_string(cmd_status));
}
void dwc3_dbg_trace_trb_complete(void *log_ctxt, struct dwc3_ep *dep,
struct dwc3_trb *trb, char *tag)
{
char *s;
int pcm = ((trb->size >> 24) & 3) + 1;
switch (usb_endpoint_type(dep->endpoint.desc)) {
case USB_ENDPOINT_XFER_INT:
case USB_ENDPOINT_XFER_ISOC:
switch (pcm) {
case 1:
s = "1x ";
break;
case 2:
s = "2x ";
break;
case 3:
default:
s = "3x ";
break;
}
break;
default:
s = "";
}
ipc_log_string(log_ctxt,
"%s: %s: trb %p (E%d:D%d) buf %08x%08x sz %s%d ctrl %08x (%c%c%c%c:%c%c:%s)",
tag, dep->name, trb, dep->trb_enqueue,
dep->trb_dequeue, trb->bph, trb->bpl, s, trb->size, trb->ctrl,
trb->ctrl & DWC3_TRB_CTRL_HWO ? 'H' : 'h',
trb->ctrl & DWC3_TRB_CTRL_LST ? 'L' : 'l',
trb->ctrl & DWC3_TRB_CTRL_CHN ? 'C' : 'c',
trb->ctrl & DWC3_TRB_CTRL_CSP ? 'S' : 's',
trb->ctrl & DWC3_TRB_CTRL_ISP_IMI ? 'S' : 's',
trb->ctrl & DWC3_TRB_CTRL_IOC ? 'C' : 'c',
dwc3_trb_type_string(DWC3_TRBCTL_TYPE(trb->ctrl)));
}
void dwc3_dbg_trace_event(void *log_ctxt, u32 event, struct dwc3 *dwc)
{
char *event_str;
event_str = kzalloc(DWC3_MSG_MAX, GFP_ATOMIC);
if (!event_str)
return;
ipc_log_string(log_ctxt, "event (%08x): %s", event,
dwc3_decode_event(event_str, DWC3_MSG_MAX,
event, dwc->ep0state));
kfree(event_str);
}
void dwc3_dbg_trace_ep(void *log_ctxt, struct dwc3_ep *dep)
{
ipc_log_string(log_ctxt,
"%s: mps %d/%d streams %d burst %d ring %d/%d flags %c:%c%c%c%c:%c",
dep->name, dep->endpoint.maxpacket,
dep->endpoint.maxpacket_limit, dep->endpoint.max_streams,
dep->endpoint.maxburst, dep->trb_enqueue,
dep->trb_dequeue,
dep->flags & DWC3_EP_ENABLED ? 'E' : 'e',
dep->flags & DWC3_EP_STALL ? 'S' : 's',
dep->flags & DWC3_EP_WEDGE ? 'W' : 'w',
dep->flags & DWC3_EP_TRANSFER_STARTED ? 'B' : 'b',
dep->flags & DWC3_EP_PENDING_REQUEST ? 'P' : 'p',
dep->direction ? '<' : '>');
}
/**
* 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(void *log_ctxt, 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(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(void *log_ctxt, u8 ep_num,
const u32 count, int status)
{
if (!allow_dbg_print(ep_num))
return;
ipc_log_string(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(void *log_ctxt, u8 ep_num, const char *name, int status)
{
if (!allow_dbg_print(ep_num))
return;
if (name != NULL)
dwc3_dbg_print(log_ctxt, ep_num, name, status, "");
}
/*
* dwc3_dbg_queue: prints a QUEUE event
* @addr: endpoint address
* @req: USB request
* @status: status
*/
void dwc3_dbg_queue(void *log_ctxt, u8 ep_num,
const struct usb_request *req, int status)
{
if (!allow_dbg_print(ep_num))
return;
if (req != NULL) {
ipc_log_string(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(void *log_ctxt, u8 ep_num,
const struct usb_ctrlrequest *req)
{
if (!allow_dbg_print(ep_num))
return;
if (req != NULL) {
ipc_log_string(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(void *log_ctxt, const char *name, int reg)
{
if (name == NULL)
return;
ipc_log_string(log_ctxt, "%s = 0x%08x", name, reg);
}
void dwc3_dbg_dma_unmap(void *log_ctxt, u8 ep_num, struct dwc3_request *req)
{
if (ep_num < 2)
return;
ipc_log_string(log_ctxt,
"%02X-%-3.3s %-25.25s 0x%pK %pad %u %pad %s", ep_num >> 1,
ep_num & 1 ? "IN":"OUT", "UNMAP", &req->request,
&req->request.dma, req->request.length, &req->trb_dma,
req->trb->ctrl & DWC3_TRB_CTRL_HWO ? "HWO" : "");
}
void dwc3_dbg_dma_map(void *log_ctxt, u8 ep_num, struct dwc3_request *req)
{
if (ep_num < 2)
return;
ipc_log_string(log_ctxt,
"%02X-%-3.3s %-25.25s 0x%pK %pad %u %pad", ep_num >> 1,
ep_num & 1 ? "IN":"OUT", "MAP", &req->request,
&req->request.dma, req->request.length, &req->trb_dma);
}
void dwc3_dbg_dma_dequeue(void *log_ctxt, u8 ep_num, struct dwc3_request *req)
{
if (ep_num < 2)
return;
ipc_log_string(log_ctxt,
"%02X-%-3.3s %-25.25s 0x%pK %pad %pad", ep_num >> 1,
ep_num & 1 ? "IN":"OUT", "DEQUEUE", &req->request,
&req->request.dma, &req->trb_dma);
}
void dwc3_dbg_dma_queue(void *log_ctxt, u8 ep_num, struct dwc3_request *req)
{
if (ep_num < 2)
return;
ipc_log_string(log_ctxt,
"%02X-%-3.3s %-25.25s 0x%pK", ep_num >> 1,
ep_num & 1 ? "IN":"OUT", "QUEUE", &req->request);
}