usb: xhci: Add debug capability support in xhci
Subsystems (3)
cover usb: xhci: Add debug capability support in xhci
Hi,
This series is for xHCI debug capability (spec section 7.6.8) support in the xHCI driver.
xHCI compatible USB host controllers(i.e. super-speed USB3 controllers) can be implemented with the Debug Capability(DbC). It presents a debug device which is fully compliant with the USB framework and provides the equivalent of a very high performance full-duplex serial link. The debug capability operation model and registers interface are defined in 7.6.8 of the xHCI specification, revision 1.1.
The DbC debug device shares a root port with the xHCI host. By default, the debug capability is disabled and the root port is assigned to xHCI. When the DbC is enabled, the root port will be assigned to the DbC debug device, and the xHCI sees nothing on this port. This implementation uses a sysfs node named <dbc> under the xHCI device to manage the enabling and disabling of the debug capability.
When the debug capability is enabled, it will present a debug device through the debug port. This debug device is fully compliant with the USB3 framework, and it can be enumerated by a debug host on the other end of the USB link. As soon as the debug device is configured, a TTY serial device named /dev/ttyGSn will be created.
One use of this link is running a login service on the debug target. Hence it can be remote accessed by a debug host. Another use case can probably be found in servers. It provides a peer-to-peer USB link between two host-only machines. This provides a reasonable out-of-band communication method between two servers.
Best regards,
Lu Baolu
Lu Baolu (3):
usb: xhci: Make some static functions global
usb: xhci: Add DbC support in xHCI driver
usb: doc: Update document for USB3 debug port usage
.../ABI/testing/sysfs-bus-pci-drivers-xhci_hcd | 25 + Documentation/driver-api/usb/usb3-debug-port.rst | 68 ++ drivers/usb/host/Kconfig | 10 + drivers/usb/host/Makefile | 5 + drivers/usb/host/xhci-dbgcap.c | 1128 ++++++++++++++++++++ drivers/usb/host/xhci-mem.c | 94 +- drivers/usb/host/xhci-ring.c | 4 +- drivers/usb/host/xhci-trace.h | 64 ++ drivers/usb/host/xhci.c | 9 + drivers/usb/host/xhci.h | 205 +++- 10 files changed, 1569 insertions(+), 43 deletions(-) create mode 100644 Documentation/ABI/testing/sysfs-bus-pci-drivers-xhci_hcd create mode 100644 drivers/usb/host/xhci-dbgcap.c
Signature · 1 line
2.7.4
PATCH 1/3 usb: xhci: Make some static functions global
This patch makes some static functions global to avoid duplications in different files. These functions can be used in the implementation of xHCI debug capability. There is no functional change.
--- drivers/usb/host/xhci-mem.c | 94 ++++++++++++++++++++++++++------------------ drivers/usb/host/xhci-ring.c | 4 +- drivers/usb/host/xhci.h | 16 +++++++- 3 files changed, 72 insertions(+), 42 deletions(-)
drivers/usb/host/xhci-mem.c +55 -39
@@ -368,7 +368,7 @@ static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci,* Set the end flag and the cycle toggle bit on the last segment. * See section 4.9.1 and figures 15 and 16. */ -static struct xhci_ring *xhci_ring_alloc (struct xhci_hcd *xhci, +struct xhci_ring *xhci_ring_alloc (struct xhci_hcd *xhci,unsigned int num_segs,unsigned int cycle_state,enum xhci_ring_type type,unsigned int max_packet,gfp_t flags) {
@@ -467,7 +467,7 @@ int xhci_ring_expansion(struct xhci_hcd *xhci, struct xhci_ring *ring,#define CTX_SIZE (_hcc) (HCC_64BYTE_CONTEXT(_hcc) ? 64 : 32) -static struct xhci_container_ctx *xhci_alloc_container_ctx (struct xhci_hcd *xhci, +struct xhci_container_ctx *xhci_alloc_container_ctx (struct xhci_hcd *xhci,int type,gfp_t flags) {struct xhci_container_ctx *ctx;
@@ -492,7 +492,7 @@ static struct xhci_container_ctx *xhci_alloc_container_ctx(struct xhci_hcd *xhcireturn ctx; } -static void xhci_free_container_ctx (struct xhci_hcd *xhci, +void xhci_free_container_ctx (struct xhci_hcd *xhci,struct xhci_container_ctx *ctx) {if (!ctx)
@@ -1762,21 +1762,61 @@ void xhci_free_command(struct xhci_hcd *xhci,kfree (command); } +int xhci_alloc_erst (struct xhci_hcd *xhci, +struct xhci_ring *evt_ring, +struct xhci_erst *erst, +gfp_t flags) +{ +size_t size; +unsigned int val; +struct xhci_segment *seg; +struct xhci_erst_entry *entry; + + size =sizeof (struct xhci_erst_entry ) * evt_ring->num_segs; + erst->entries =dma_alloc_coherent (xhci_to_hcd (xhci)->self.sysdev, + size, + &erst->erst_dma_addr, + flags); +if (!erst->entries) +return -ENOMEM ; + +memset (erst->entries,0 , size); + erst->num_entries = evt_ring->num_segs; + + seg = evt_ring->first_seg; +for (val =0 ; val < evt_ring->num_segs; val++) { + entry = &erst->entries[val]; + entry->seg_addr =cpu_to_le64 (seg->dma); + entry->seg_size =cpu_to_le32 (TRBS_PER_SEGMENT ); + entry->rsvd =0 ; + seg = seg->next; + } + +return 0 ; +} + +void xhci_free_erst (struct xhci_hcd *xhci,struct xhci_erst *erst) +{ +size_t size; +struct device *dev =xhci_to_hcd (xhci)->self.sysdev; + + size =sizeof (struct xhci_erst_entry ) * (erst->num_entries); +if (erst->entries) +dma_free_coherent (dev, size, + erst->entries, + erst->erst_dma_addr); + erst->entries =NULL ; +} +void xhci_mem_cleanup (struct xhci_hcd *xhci) {struct device *dev =xhci_to_hcd (xhci)->self.sysdev; -int size;int i, j, num_ports;cancel_delayed_work_sync (&xhci->cmd_timer); -/* Free the Event Ring Segment Table and the actual Event Ring */ - size =sizeof (struct xhci_erst_entry )*(xhci->erst.num_entries); -if (xhci->erst.entries) -dma_free_coherent (dev, size, - xhci->erst.entries, xhci->erst.erst_dma_addr); - xhci->erst.entries =NULL ; -xhci_dbg_trace (xhci, trace_xhci_dbg_init,"Freed ERST" ); +xhci_free_erst (xhci, &xhci->erst); +if (xhci->event_ring)xhci_ring_free (xhci, xhci->event_ring); xhci->event_ring =NULL ;
@@ -2313,9 +2353,8 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)struct device *dev =xhci_to_hcd (xhci)->self.sysdev;unsigned int val, val2;u64 val_64; -struct xhci_segment *seg; -u32 page_size, temp; -int i; +u32 page_size, temp; +int i, ret;INIT_LIST_HEAD (&xhci->cmd_list);
@@ -2454,32 +2493,9 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)if (xhci_check_trb_in_td_math (xhci) <0 ) goto fail; - xhci->erst.entries =dma_alloc_coherent (dev, -sizeof (struct xhci_erst_entry ) *ERST_NUM_SEGS , &dma, - flags); -if (!xhci->erst.entries) + ret =xhci_alloc_erst (xhci, xhci->event_ring, &xhci->erst, flags); +if (ret) goto fail; -xhci_dbg_trace (xhci, trace_xhci_dbg_init, -"// Allocated event ring segment table at 0x%llx" , - (unsigned long long )dma); - -memset (xhci->erst.entries,0 ,sizeof (struct xhci_erst_entry )*ERST_NUM_SEGS ); - xhci->erst.num_entries =ERST_NUM_SEGS ; - xhci->erst.erst_dma_addr = dma; -xhci_dbg_trace (xhci, trace_xhci_dbg_init, -"Set ERST to 0; private num segs = %i, virt addr = %p, dma addr = 0x%llx" , - xhci->erst.num_entries, - xhci->erst.entries, - (unsigned long long )xhci->erst.erst_dma_addr); - -/* set ring base address and size for each segment table entry */ -for (val =0 , seg = xhci->event_ring->first_seg; val <ERST_NUM_SEGS ; val++) { -struct xhci_erst_entry *entry = &xhci->erst.entries[val]; - entry->seg_addr =cpu_to_le64 (seg->dma); - entry->seg_size =cpu_to_le32 (TRBS_PER_SEGMENT ); - entry->rsvd =0 ; - seg = seg->next; - }/* set ERST count with the number of entries in the segment table */ val =readl (&xhci->ir_set->erst_size);
drivers/usb/host/xhci-ring.c +2 -2
@@ -165,7 +165,7 @@ static void next_trb(struct xhci_hcd *xhci,* See Cycle bit rules. SW is the consumer for the event ring only. * Don't make a ring full of link TRBs. That would be dumb and this would loop. */ -static void inc_deq (struct xhci_hcd *xhci,struct xhci_ring *ring) +void inc_deq (struct xhci_hcd *xhci,struct xhci_ring *ring) {/* event ring doesn't have link trbs, check for last trb */ if (ring->type ==TYPE_EVENT ) {
@@ -2958,7 +2958,7 @@ static int prepare_transfer(struct xhci_hcd *xhci,return 0 ; } -static unsigned int count_trbs (u64 addr,u64 len) +unsigned int count_trbs (u64 addr,u64 len) {unsigned int num_trbs;
drivers/usb/host/xhci.h +15 -1
@@ -1958,9 +1958,17 @@ void xhci_slot_copy(struct xhci_hcd *xhci,int xhci_endpoint_init (struct xhci_hcd *xhci,struct xhci_virt_device *virt_dev,struct usb_device *udev,struct usb_host_endpoint *ep,gfp_t mem_flags); +struct xhci_ring *xhci_ring_alloc (struct xhci_hcd *xhci, +unsigned int num_segs,unsigned int cycle_state, +enum xhci_ring_type type,unsigned int max_packet,gfp_t flags);void xhci_ring_free (struct xhci_hcd *xhci,struct xhci_ring *ring);int xhci_ring_expansion (struct xhci_hcd *xhci,struct xhci_ring *ring, -unsigned int num_trbs,gfp_t flags); +unsigned int num_trbs,gfp_t flags); +int xhci_alloc_erst (struct xhci_hcd *xhci, +struct xhci_ring *evt_ring, +struct xhci_erst *erst, +gfp_t flags); +void xhci_free_erst (struct xhci_hcd *xhci,struct xhci_erst *erst);void xhci_free_endpoint_ring (struct xhci_hcd *xhci,struct xhci_virt_device *virt_dev,unsigned int ep_index);
@@ -1990,6 +1998,10 @@ struct xhci_command *xhci_alloc_command(struct xhci_hcd *xhci,void xhci_urb_free_priv (struct urb_priv *urb_priv);void xhci_free_command (struct xhci_hcd *xhci,struct xhci_command *command); +struct xhci_container_ctx *xhci_alloc_container_ctx (struct xhci_hcd *xhci, +int type,gfp_t flags); +void xhci_free_container_ctx (struct xhci_hcd *xhci, +struct xhci_container_ctx *ctx);/* xHCI host controller glue */ typedef void (*xhci_get_quirks_t )(struct device *,struct xhci_hcd *);
@@ -2064,6 +2076,8 @@ void xhci_handle_command_timeout(struct work_struct *work);void xhci_ring_ep_doorbell (struct xhci_hcd *xhci,unsigned int slot_id,unsigned int ep_index,unsigned int stream_id);void xhci_cleanup_command_queue (struct xhci_hcd *xhci); +void inc_deq (struct xhci_hcd *xhci,struct xhci_ring *ring); +unsigned int count_trbs (u64 addr,u64 len);/* xHCI roothub code */ void xhci_set_link_state(struct xhci_hcd *xhci, __le32 __iomem **port_array,
Signature · 1 line
2.7.4
PATCH 2/3 usb: xhci: Add DbC support in xHCI driver
In reply to Lu BaoluxHCI compatible USB host controllers(i.e. super-speed USB3 controllers) can be implemented with the Debug Capability(DbC). It presents a debug device which is fully compliant with the USB framework and provides the equivalent of a very high performance full-duplex serial link. The debug capability operation model and registers interface are defined in 7.6.8 of the xHCI specification, revision 1.1.
The DbC debug device shares a root port with the xHCI host. By default, the debug capability is disabled and the root port is assigned to xHCI. When the DbC is enabled, the root port will be assigned to the DbC debug device, and the xHCI sees nothing on this port. This implementation uses a sysfs node named <dbc> under the xHCI device to manage the enabling and disabling of the debug capability.
When the debug capability is enabled, it will present a debug device through the debug port. This debug device is fully compliant with the USB3 framework, and it can be enumerated by a debug host on the other end of the USB link. As soon as the debug device is configured, a TTY serial device named /dev/ttyGSn will be created.
One use of this link is running a login service on the debug target. Hence it can be remote accessed by a debug host. Another use case can probably be found in servers. It provides a peer-to-peer USB link between two host-only machines. This provides a reasonable out-of-band communication method between two servers.
--- .../ABI/testing/sysfs-bus-pci-drivers-xhci_hcd | 25 + drivers/usb/host/Kconfig | 10 + drivers/usb/host/Makefile | 5 + drivers/usb/host/xhci-dbgcap.c | 1128 ++++++++++++++++++++ drivers/usb/host/xhci-trace.h | 64 ++ drivers/usb/host/xhci.c | 9 + drivers/usb/host/xhci.h | 189 +++- 7 files changed, 1429 insertions(+), 1 deletion(-) create mode 100644 Documentation/ABI/testing/sysfs-bus-pci-drivers-xhci_hcd create mode 100644 drivers/usb/host/xhci-dbgcap.c
Documentation/ABI/testing/sysfs-bus-pci-drivers-xhci_hcd new file +25 -0
@@ -0,0 +1,25 @@ +What: /sys/bus/pci/drivers/xhci_hcd/.../dbc +Date: June 2017 +Contact: Lu Baolu <[email protected]> +Description: + xHCI compatible USB host controllers (i.e. super-speed + USB3 controllers) are often implemented with the Debug + Capability (DbC). It can present a debug device which + is fully compliant with the USB framework and provides + the equivalent of a very high performance full-duplex + serial link for debug purpose. + + The DbC debug device shares a root port with xHCI host. + When the DbC is enabled, the root port will be assigned + to the Debug Capability. Otherwise, it will be assigned + to xHCI. + + Writing "enable" to this attribute will enable the DbC + functionality and the shared root port will be assigned + to the DbC device. Writing "disable" to this attribute + will disable the DbC functionality and the shared root + port will roll back to the xHCI. + + Reading this attribute gives the state of the DbC. It + can be one of the following states: disabled, enabled, + initialized, connected, configured and stalled.
drivers/usb/host/Kconfig +10 -0
@@ -27,6 +27,16 @@ config USB_XHCI_HCD module will be called xhci-hcd. if USB_XHCI_HCD +config USB_XHCI_DBGCAP + bool "xHCI support for debug capability" + depends on TTY + depends on USB_GADGET=y + select USB_U_SERIAL + ---help--- + Say 'Y' to enable the support for the xHCI debug capability. Make + sure that your xHCI host supports the extended debug capability and + you want a TTY serial device based on the xHCI debug capability + before enabling this option. If unsure, say 'N'. config USB_XHCI_PCI tristate
drivers/usb/host/Makefile +5 -0
@@ -13,6 +13,11 @@ fhci-$(CONFIG_FHCI_DEBUG) += fhci-dbg.o xhci-hcd-y := xhci.o xhci-mem.o xhci-hcd-y += xhci-ring.o xhci-hub.o xhci-dbg.o xhci-hcd-y += xhci-trace.o + +ifneq ($(CONFIG_USB_XHCI_DBGCAP), ) + xhci-hcd-y += xhci-dbgcap.o +endif + ifneq ($(CONFIG_USB_XHCI_MTK), ) xhci-hcd-y += xhci-mtk-sch.o endif
drivers/usb/host/xhci-dbgcap.c new file +1128 -0
1,128 lines not on this page · raw message
drivers/usb/host/xhci-trace.h +64 -0
76 lines not on this page · raw message
drivers/usb/host/xhci.c +9 -0
@@ -627,6 +627,9 @@ int xhci_run(struct usb_hcd *hcd) }xhci_dbg_trace (xhci, trace_xhci_dbg_init,"Finished xhci_run for USB2 roothub" ); + +dbc_create_sysfs_file (xhci); +return 0 ; }EXPORT_SYMBOL_GPL (xhci_run);
@@ -655,6 +658,8 @@ static void xhci_stop(struct usb_hcd *hcd)return ; } +dbc_remove_sysfs_file (xhci); +spin_lock_irq (&xhci->lock); xhci->xhc_state |=XHCI_STATE_HALTED ; xhci->cmd_ring_state =CMD_RING_STATE_STOPPED ;
@@ -871,6 +876,8 @@ int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup) xhci->shared_hcd->state != HC_STATE_SUSPENDED)return -EINVAL ; +xhci_dbc_suspend (xhci); +/* Clear root port wake on bits if wakeup not allowed. */ if (!do_wakeup)xhci_disable_port_wake_on_bits (xhci);
@@ -1066,6 +1073,8 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)spin_unlock_irq (&xhci->lock); +xhci_dbc_resume (xhci); + done:if (retval ==0 ) {/* Resume root hubs only when have pending events. */
drivers/usb/host/xhci.h +188 -1
215 lines not on this page · raw message
Signature · 1 line
2.7.4
Re: [PATCH 2/3] usb: xhci: Add DbC support in xHCI driver
Hi,
drivers/usb/host/xhci-dbgcap.c line 686
Quoted 11 lines · Lu Baolu
drivers/usb/host/xhci-dbgcap.c new file +11
-0+static void xhci_dbc_stop (struct xhci_hcd *xhci) +{ +struct xhci_dbc *dbc = xhci->dbc; + +WARN_ON (!dbc); + +cancel_delayed_work_sync (&dbc->event_work); + +if (dbc->gs_port_num !=GSPORT_INVAL ) { +gserial_disconnect (&dbc->gs_port); +gserial_free_line (dbc->gs_port_num);
why are you tying host stack to the gadget framework?
With this, you're forcing every single PC in the world to compile the gadget framework, that's a bit much don't you think?
Signature · 1 line
balbi
Re: [PATCH 2/3] usb: xhci: Add DbC support in xHCI driver
Hi Felipe,
Quoted 15 lines · Felipe Balbi
Hi,
drivers/usb/host/xhci-dbgcap.c line 686
Quoted 11 lines · Lu Baolu
drivers/usb/host/xhci-dbgcap.c new file +11
-0+static void xhci_dbc_stop (struct xhci_hcd *xhci) +{ +struct xhci_dbc *dbc = xhci->dbc; + +WARN_ON (!dbc); + +cancel_delayed_work_sync (&dbc->event_work); + +if (dbc->gs_port_num !=GSPORT_INVAL ) { +gserial_disconnect (&dbc->gs_port); +gserial_free_line (dbc->gs_port_num);why are you tying host stack to the gadget framework?
XHCI debug capability is actually a debug device gadget. The hardware and firmware do everything of gadget work and leave the interface to xHCI for enabling/disabling and queuing transfer requests.
u_serial.c provides a generic layer between a USB gadget and the TTY layer. I used it to avoid duplicating code.
Quoted 4 lines
With this, you're forcing every single PC in the world to compile the gadget framework, that's a bit much don't you think?
Yes, you are right. Is it acceptable if I move u_serial.c from the current place to drivers/usb/common?
Best regards,
Lu Baolu
PATCH 3/3 usb: doc: Update document for USB3 debug port usage
In reply to Lu BaoluUpdate Documentation/driver-api/usb/usb3-debug-port.rst. This update includes the guide for using xHCI debug capability based TTY serial link.
--- Documentation/driver-api/usb/usb3-debug-port.rst | 68 ++++++++++++++++++++++++ 1 file changed, 68 insertions(+)
Documentation/driver-api/usb/usb3-debug-port.rst +68 -0
@@ -98,3 +98,71 @@ you to check the sanity of the setup. cat /dev/ttyUSB0 done ===== end of bash scripts =============== + +Serial TTY +========== + +DbC has also been designed for a serial TTY device at runtime. +One use of this is running a login service on the debug target. +Hence it can be remote accessed by the debug host. Another use +can probably be found in servers. It provides a peer-to-peer USB +link between two host-only machines. This provides a reasonable +out-of-band communication method between two servers. + +In order to use this, you need to make sure your kernel has been +configured to support USB_XHCI_DBGCAP. A sysfs attribute under +the xHCI device node is used to enable or disable DbC. By default, +DbC is disabled:: + + root@target:/sys/bus/pci/devices/0000:00:14.0# cat dbc + disabled + +Enable DbC with the following command:: + + root@target:/sys/bus/pci/devices/0000:00:14.0# echo enable > dbc + +You can check the DbC state at anytime:: + + root@target:/sys/bus/pci/devices/0000:00:14.0# cat dbc + enabled + +Connect the debug target to the debug host with a USB 3.0 super- +speed A-to-A debugging cable. You can see the /dev/ttyGSn created +on the debug target. You will see below kernel message lines:: + + root@target: tail -f /var/log/kern.log + [ 182.730103] xhci_hcd 0000:00:14.0: DbC connected + [ 191.169420] xhci_hcd 0000:00:14.0: DbC configured + [ 191.169597] xhci_hcd 0000:00:14.0: DbC now attached to /dev/ttyGS0 + +Accordingly, the DbC state has been brought up to:: + + root@host:/sys/bus/pci/devices/0000:00:14.0# cat dbc + configured + +On the debug host, you will see the debug device has been enumerated. +You will see below kernel message lines:: + + root@host: tail -f /var/log/kern.log + [ 79.454780] usb 2-2.1: new SuperSpeed USB device number 3 using xhci_hcd + [ 79.475003] usb 2-2.1: LPM exit latency is zeroed, disabling LPM. + [ 79.475389] usb 2-2.1: New USB device found, idVendor=1d6b, idProduct=0004 + [ 79.475390] usb 2-2.1: New USB device strings: Mfr=1, Product=2, SerialNumber=3 + [ 79.475391] usb 2-2.1: Product: Remote GDB + [ 79.475392] usb 2-2.1: Manufacturer: Linux + [ 79.475393] usb 2-2.1: SerialNumber: 0001 + [ 79.660368] usb_debug 2-2.1:1.0: xhci_dbc converter detected + [ 79.660439] usb 2-2.1: xhci_dbc converter now attached to ttyUSB0 + +You can simply verify whether it works by:: + + # On target side + root@target: echo "Hello world" > /dev/ttyGS0 + + # On host side + root@host: cat /dev/ttyUSB0 + Hello world + + # vice versa + +You have a workable serial link over USB now.
Signature · 1 line
2.7.4