Hi, On 01/16/2017 03:03 PM, Felipe Balbi wrote: > Hi, > > Lu Baolu <baolu.lu@xxxxxxxxxxxxxxx> writes: >> On 12/29/2016 07:01 PM, Felipe Balbi wrote: >>> instead of having a tracer that can only trace command completions, >>> let's promote this tracer so it can trace and decode any TRB. >>> >>> With that, it will be easier to extrapolate the lifetime of any TRB >>> which might help debugging certain issues. >>> >>> Signed-off-by: Felipe Balbi <felipe.balbi@xxxxxxxxxxxxxxx> >>> --- >>> drivers/usb/host/xhci-ring.c | 14 +- >>> drivers/usb/host/xhci-trace.h | 55 +++++--- >>> drivers/usb/host/xhci.h | 311 ++++++++++++++++++++++++++++++++++++++++++ >>> 3 files changed, 357 insertions(+), 23 deletions(-) >>> >>> diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c >>> index 393c64f8acef..0ee7d358b812 100644 >>> --- a/drivers/usb/host/xhci-ring.c >>> +++ b/drivers/usb/host/xhci-ring.c >>> @@ -1346,6 +1346,9 @@ static void handle_cmd_completion(struct xhci_hcd *xhci, >>> >>> cmd_dma = le64_to_cpu(event->cmd_trb); >>> cmd_trb = xhci->cmd_ring->dequeue; >>> + >>> + trace_xhci_handle_command(xhci->cmd_ring, &cmd_trb->generic); >>> + >> This is duplicated with trace_xhci_handle_event(). > no it's not. They separate events from the same event class, but they're > different things. Comments below. > >>> @@ -2407,6 +2408,10 @@ static int handle_tx_event(struct xhci_hcd *xhci, >>> >>> ep_trb = &ep_seg->trbs[(ep_trb_dma - ep_seg->dma) / >>> sizeof(*ep_trb)]; >>> + >>> + trace_xhci_handle_transfer(ep_ring, >>> + (struct xhci_generic_trb *) ep_trb); >>> + >> This is duplicated with trace_xhci_handle_event(). > ditto > >>> + __entry->type = ring->type; >>> + __entry->field0 = le32_to_cpu(trb->field[0]); >>> + __entry->field1 = le32_to_cpu(trb->field[1]); >>> + __entry->field2 = le32_to_cpu(trb->field[2]); >>> + __entry->field3 = le32_to_cpu(trb->field[3]); >>> ), >>> - TP_printk("\ntrb_dma=@%llx, trb_va=@%p, status=%08x, flags=%08x", >>> - (unsigned long long) __entry->dma, __entry->va, >>> - __entry->status, __entry->flags >>> + TP_printk("%s: %s", xhci_ring_type_string(__entry->type), >> How about moving the common fields of a TRB (like TRB type and >> the cycle bit) to the place between ring type and trb decoding string? >> And remove type and cycle decoding in xhci_decode_trb() as well. >> >> Something like: >> >> diff --git a/drivers/usb/host/xhci-trace.h b/drivers/usb/host/xhci-trace.h >> index d01524b..f8ef7b8 100644 >> --- a/drivers/usb/host/xhci-trace.h >> +++ b/drivers/usb/host/xhci-trace.h >> @@ -132,9 +132,11 @@ DECLARE_EVENT_CLASS(xhci_log_trb, >> __entry->field2 = le32_to_cpu(trb->field[2]); >> __entry->field3 = le32_to_cpu(trb->field[3]); >> ), >> - TP_printk("%s: %s", xhci_ring_type_string(__entry->type), >> - xhci_decode_trb(__entry->field0, __entry->field1, >> - __entry->field2, __entry->field3) >> + TP_printk("%s: %s: %c: %s", xhci_ring_type_string(__entry->type), >> + xhci_trb_type_string(TRB_FIELD_TO_TYPE(__entry->field3)), >> + __entry->field3 & TRB_CYCLE ? 'C' : 'c', >> + xhci_decode_trb(__entry->field0, __entry->field1, >> + __entry->field2, __entry->field3) > and what do I get with that? What's the actual benefit? I thought that it could make xhci_decode_trb() a bit simpler. > >> ) >> ); >> >> >>> + xhci_decode_trb(__entry->field0, __entry->field1, >>> + __entry->field2, __entry->field3) >>> ) >>> ); >>> >>> -DEFINE_EVENT(xhci_log_event, xhci_cmd_completion, >>> - TP_PROTO(void *trb_va, struct xhci_generic_trb *ev), >>> - TP_ARGS(trb_va, ev) >>> +DEFINE_EVENT(xhci_log_trb, xhci_handle_event, >>> + TP_PROTO(struct xhci_ring *ring, struct xhci_generic_trb *trb), >>> + TP_ARGS(ring, trb) >>> +); >>> + >>> +DEFINE_EVENT(xhci_log_trb, xhci_handle_command, >>> + TP_PROTO(struct xhci_ring *ring, struct xhci_generic_trb *trb), >>> + TP_ARGS(ring, trb) >>> +); >>> + >>> +DEFINE_EVENT(xhci_log_trb, xhci_handle_transfer, >>> + TP_PROTO(struct xhci_ring *ring, struct xhci_generic_trb *trb), >>> + TP_ARGS(ring, trb) >>> +); >>> + >>> +DEFINE_EVENT(xhci_log_trb, xhci_queue_trb, >>> + TP_PROTO(struct xhci_ring *ring, struct xhci_generic_trb *trb), >>> + TP_ARGS(ring, trb) >>> ); >> xhci_handle_command and xhci_handle_transfer are duplications >> of xhci_handle_event. I suggest to remove them. > no, they are not. They give us more granularity into which events we > want to enable. Fair enough. But why not defining events for all possible event types as well and dropping the all-in-one xhci_handle_event switch. A single event TRB will be traced twice in the same execution path if xhci_handle_event and xhci_handle_command/transfer are both enabled. > They also make it clear where the even is coming > from. Imagine how the trace would look like if I had a single event and > just called trace_xhci_handle_event() from all locations. How would you > differentiate from all possible call sites? These events happen only in interrupt handler. There are no other possible call sites. > >> How about adding an event for the link TRBs. Something like, >> >> diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c >> index 4bad432..6dc8efb 100644 >> --- a/drivers/usb/host/xhci-ring.c >> +++ b/drivers/usb/host/xhci-ring.c >> @@ -173,6 +173,7 @@ static void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring) >> ring->num_trbs_free++; >> } >> while (trb_is_link(ring->dequeue)) { >> + trace_xhci_link_trb(ring, ring->dequeue); >> ring->deq_seg = ring->deq_seg->next; >> ring->dequeue = ring->deq_seg->trbs; >> } >> @@ -211,6 +212,7 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring, >> ring->enq_updates++; >> /* Update the dequeue pointer further if that was a link TRB */ >> while (trb_is_link(next)) { >> + trace_xhci_link_trb(ring, next); >> >> /* >> * If the caller doesn't plan on enqueueing more TDs before >> diff --git a/drivers/usb/host/xhci-trace.h b/drivers/usb/host/xhci-trace.h >> index d01524b..f1a06b5 100644 >> --- a/drivers/usb/host/xhci-trace.h >> +++ b/drivers/usb/host/xhci-trace.h >> @@ -158,6 +158,10 @@ DEFINE_EVENT(xhci_log_trb, xhci_queue_trb, >> TP_ARGS(ring, trb) >> ); >> >> +DEFINE_EVENT(xhci_log_trb, xhci_link_trb, >> + TP_PROTO(struct xhci_ring *ring, struct xhci_generic_trb *trb), >> + TP_ARGS(ring, trb) >> +); >> #endif /* __XHCI_TRACE_H */ > what are you trying to achieve with this? To trace and debug the ring itself, especially for ring auto expending and shrinking. > >>> +static inline const char *xhci_decode_trb(u32 field0, u32 field1, u32 field2, >>> + u32 field3) >>> +{ >>> + static char str[256]; >>> + int type = TRB_FIELD_TO_TYPE(field3); >>> + >>> + switch (type) { >>> + case TRB_LINK: >>> + sprintf(str, "TRB %08x%08x status '%s' len %d slot %d ep %d type '%s' flags %c:%c", >> How about using snprintf() to avoid buffer over flow? > sure > >>> + field1, field0, >>> + xhci_trb_comp_code_string(GET_COMP_CODE(field2)), >>> + EVENT_TRB_LEN(field2), TRB_TO_SLOT_ID(field3), >>> + /* Macro decrements 1, maybe it shouldn't?!? */ >>> + TRB_TO_EP_INDEX(field3) + 1, >>> + xhci_trb_type_string(TRB_FIELD_TO_TYPE(field3)), >> "TRB_FIELD_TO_TYPE(field3)" could be replaced with "type". The same for other >> places in this function. > good catch > >>> + field3 & EVENT_DATA ? 'E' : 'e', >>> + field3 & TRB_CYCLE ? 'C' : 'c'); >> This decoding seems not for a link trb, but an event one. :-) > copy paste error > Best regards, Lu Baolu -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html