162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * xhci-debugfs.c - xHCI debugfs interface 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2017 Intel Corporation 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Author: Lu Baolu <baolu.lu@linux.intel.com> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/slab.h> 1162306a36Sopenharmony_ci#include <linux/uaccess.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include "xhci.h" 1462306a36Sopenharmony_ci#include "xhci-debugfs.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_cistatic const struct debugfs_reg32 xhci_cap_regs[] = { 1762306a36Sopenharmony_ci dump_register(CAPLENGTH), 1862306a36Sopenharmony_ci dump_register(HCSPARAMS1), 1962306a36Sopenharmony_ci dump_register(HCSPARAMS2), 2062306a36Sopenharmony_ci dump_register(HCSPARAMS3), 2162306a36Sopenharmony_ci dump_register(HCCPARAMS1), 2262306a36Sopenharmony_ci dump_register(DOORBELLOFF), 2362306a36Sopenharmony_ci dump_register(RUNTIMEOFF), 2462306a36Sopenharmony_ci dump_register(HCCPARAMS2), 2562306a36Sopenharmony_ci}; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistatic const struct debugfs_reg32 xhci_op_regs[] = { 2862306a36Sopenharmony_ci dump_register(USBCMD), 2962306a36Sopenharmony_ci dump_register(USBSTS), 3062306a36Sopenharmony_ci dump_register(PAGESIZE), 3162306a36Sopenharmony_ci dump_register(DNCTRL), 3262306a36Sopenharmony_ci dump_register(CRCR), 3362306a36Sopenharmony_ci dump_register(DCBAAP_LOW), 3462306a36Sopenharmony_ci dump_register(DCBAAP_HIGH), 3562306a36Sopenharmony_ci dump_register(CONFIG), 3662306a36Sopenharmony_ci}; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_cistatic const struct debugfs_reg32 xhci_runtime_regs[] = { 3962306a36Sopenharmony_ci dump_register(MFINDEX), 4062306a36Sopenharmony_ci dump_register(IR0_IMAN), 4162306a36Sopenharmony_ci dump_register(IR0_IMOD), 4262306a36Sopenharmony_ci dump_register(IR0_ERSTSZ), 4362306a36Sopenharmony_ci dump_register(IR0_ERSTBA_LOW), 4462306a36Sopenharmony_ci dump_register(IR0_ERSTBA_HIGH), 4562306a36Sopenharmony_ci dump_register(IR0_ERDP_LOW), 4662306a36Sopenharmony_ci dump_register(IR0_ERDP_HIGH), 4762306a36Sopenharmony_ci}; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_cistatic const struct debugfs_reg32 xhci_extcap_legsup[] = { 5062306a36Sopenharmony_ci dump_register(EXTCAP_USBLEGSUP), 5162306a36Sopenharmony_ci dump_register(EXTCAP_USBLEGCTLSTS), 5262306a36Sopenharmony_ci}; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_cistatic const struct debugfs_reg32 xhci_extcap_protocol[] = { 5562306a36Sopenharmony_ci dump_register(EXTCAP_REVISION), 5662306a36Sopenharmony_ci dump_register(EXTCAP_NAME), 5762306a36Sopenharmony_ci dump_register(EXTCAP_PORTINFO), 5862306a36Sopenharmony_ci dump_register(EXTCAP_PORTTYPE), 5962306a36Sopenharmony_ci dump_register(EXTCAP_MANTISSA1), 6062306a36Sopenharmony_ci dump_register(EXTCAP_MANTISSA2), 6162306a36Sopenharmony_ci dump_register(EXTCAP_MANTISSA3), 6262306a36Sopenharmony_ci dump_register(EXTCAP_MANTISSA4), 6362306a36Sopenharmony_ci dump_register(EXTCAP_MANTISSA5), 6462306a36Sopenharmony_ci dump_register(EXTCAP_MANTISSA6), 6562306a36Sopenharmony_ci}; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_cistatic const struct debugfs_reg32 xhci_extcap_dbc[] = { 6862306a36Sopenharmony_ci dump_register(EXTCAP_DBC_CAPABILITY), 6962306a36Sopenharmony_ci dump_register(EXTCAP_DBC_DOORBELL), 7062306a36Sopenharmony_ci dump_register(EXTCAP_DBC_ERSTSIZE), 7162306a36Sopenharmony_ci dump_register(EXTCAP_DBC_ERST_LOW), 7262306a36Sopenharmony_ci dump_register(EXTCAP_DBC_ERST_HIGH), 7362306a36Sopenharmony_ci dump_register(EXTCAP_DBC_ERDP_LOW), 7462306a36Sopenharmony_ci dump_register(EXTCAP_DBC_ERDP_HIGH), 7562306a36Sopenharmony_ci dump_register(EXTCAP_DBC_CONTROL), 7662306a36Sopenharmony_ci dump_register(EXTCAP_DBC_STATUS), 7762306a36Sopenharmony_ci dump_register(EXTCAP_DBC_PORTSC), 7862306a36Sopenharmony_ci dump_register(EXTCAP_DBC_CONT_LOW), 7962306a36Sopenharmony_ci dump_register(EXTCAP_DBC_CONT_HIGH), 8062306a36Sopenharmony_ci dump_register(EXTCAP_DBC_DEVINFO1), 8162306a36Sopenharmony_ci dump_register(EXTCAP_DBC_DEVINFO2), 8262306a36Sopenharmony_ci}; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_cistatic struct dentry *xhci_debugfs_root; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_cistatic struct xhci_regset *xhci_debugfs_alloc_regset(struct xhci_hcd *xhci) 8762306a36Sopenharmony_ci{ 8862306a36Sopenharmony_ci struct xhci_regset *regset; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci regset = kzalloc(sizeof(*regset), GFP_KERNEL); 9162306a36Sopenharmony_ci if (!regset) 9262306a36Sopenharmony_ci return NULL; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci /* 9562306a36Sopenharmony_ci * The allocation and free of regset are executed in order. 9662306a36Sopenharmony_ci * We needn't a lock here. 9762306a36Sopenharmony_ci */ 9862306a36Sopenharmony_ci INIT_LIST_HEAD(®set->list); 9962306a36Sopenharmony_ci list_add_tail(®set->list, &xhci->regset_list); 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci return regset; 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_cistatic void xhci_debugfs_free_regset(struct xhci_regset *regset) 10562306a36Sopenharmony_ci{ 10662306a36Sopenharmony_ci if (!regset) 10762306a36Sopenharmony_ci return; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci list_del(®set->list); 11062306a36Sopenharmony_ci kfree(regset); 11162306a36Sopenharmony_ci} 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci__printf(6, 7) 11462306a36Sopenharmony_cistatic void xhci_debugfs_regset(struct xhci_hcd *xhci, u32 base, 11562306a36Sopenharmony_ci const struct debugfs_reg32 *regs, 11662306a36Sopenharmony_ci size_t nregs, struct dentry *parent, 11762306a36Sopenharmony_ci const char *fmt, ...) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci struct xhci_regset *rgs; 12062306a36Sopenharmony_ci va_list args; 12162306a36Sopenharmony_ci struct debugfs_regset32 *regset; 12262306a36Sopenharmony_ci struct usb_hcd *hcd = xhci_to_hcd(xhci); 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci rgs = xhci_debugfs_alloc_regset(xhci); 12562306a36Sopenharmony_ci if (!rgs) 12662306a36Sopenharmony_ci return; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci va_start(args, fmt); 12962306a36Sopenharmony_ci vsnprintf(rgs->name, sizeof(rgs->name), fmt, args); 13062306a36Sopenharmony_ci va_end(args); 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci regset = &rgs->regset; 13362306a36Sopenharmony_ci regset->regs = regs; 13462306a36Sopenharmony_ci regset->nregs = nregs; 13562306a36Sopenharmony_ci regset->base = hcd->regs + base; 13662306a36Sopenharmony_ci regset->dev = hcd->self.controller; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci debugfs_create_regset32((const char *)rgs->name, 0444, parent, regset); 13962306a36Sopenharmony_ci} 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_cistatic void xhci_debugfs_extcap_regset(struct xhci_hcd *xhci, int cap_id, 14262306a36Sopenharmony_ci const struct debugfs_reg32 *regs, 14362306a36Sopenharmony_ci size_t n, const char *cap_name) 14462306a36Sopenharmony_ci{ 14562306a36Sopenharmony_ci u32 offset; 14662306a36Sopenharmony_ci int index = 0; 14762306a36Sopenharmony_ci size_t psic, nregs = n; 14862306a36Sopenharmony_ci void __iomem *base = &xhci->cap_regs->hc_capbase; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci offset = xhci_find_next_ext_cap(base, 0, cap_id); 15162306a36Sopenharmony_ci while (offset) { 15262306a36Sopenharmony_ci if (cap_id == XHCI_EXT_CAPS_PROTOCOL) { 15362306a36Sopenharmony_ci psic = XHCI_EXT_PORT_PSIC(readl(base + offset + 8)); 15462306a36Sopenharmony_ci nregs = min(4 + psic, n); 15562306a36Sopenharmony_ci } 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci xhci_debugfs_regset(xhci, offset, regs, nregs, 15862306a36Sopenharmony_ci xhci->debugfs_root, "%s:%02d", 15962306a36Sopenharmony_ci cap_name, index); 16062306a36Sopenharmony_ci offset = xhci_find_next_ext_cap(base, offset, cap_id); 16162306a36Sopenharmony_ci index++; 16262306a36Sopenharmony_ci } 16362306a36Sopenharmony_ci} 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_cistatic int xhci_ring_enqueue_show(struct seq_file *s, void *unused) 16662306a36Sopenharmony_ci{ 16762306a36Sopenharmony_ci dma_addr_t dma; 16862306a36Sopenharmony_ci struct xhci_ring *ring = *(struct xhci_ring **)s->private; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci dma = xhci_trb_virt_to_dma(ring->enq_seg, ring->enqueue); 17162306a36Sopenharmony_ci seq_printf(s, "%pad\n", &dma); 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci return 0; 17462306a36Sopenharmony_ci} 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_cistatic int xhci_ring_dequeue_show(struct seq_file *s, void *unused) 17762306a36Sopenharmony_ci{ 17862306a36Sopenharmony_ci dma_addr_t dma; 17962306a36Sopenharmony_ci struct xhci_ring *ring = *(struct xhci_ring **)s->private; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci dma = xhci_trb_virt_to_dma(ring->deq_seg, ring->dequeue); 18262306a36Sopenharmony_ci seq_printf(s, "%pad\n", &dma); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci return 0; 18562306a36Sopenharmony_ci} 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_cistatic int xhci_ring_cycle_show(struct seq_file *s, void *unused) 18862306a36Sopenharmony_ci{ 18962306a36Sopenharmony_ci struct xhci_ring *ring = *(struct xhci_ring **)s->private; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci seq_printf(s, "%d\n", ring->cycle_state); 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci return 0; 19462306a36Sopenharmony_ci} 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_cistatic void xhci_ring_dump_segment(struct seq_file *s, 19762306a36Sopenharmony_ci struct xhci_segment *seg) 19862306a36Sopenharmony_ci{ 19962306a36Sopenharmony_ci int i; 20062306a36Sopenharmony_ci dma_addr_t dma; 20162306a36Sopenharmony_ci union xhci_trb *trb; 20262306a36Sopenharmony_ci char str[XHCI_MSG_MAX]; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci for (i = 0; i < TRBS_PER_SEGMENT; i++) { 20562306a36Sopenharmony_ci trb = &seg->trbs[i]; 20662306a36Sopenharmony_ci dma = seg->dma + i * sizeof(*trb); 20762306a36Sopenharmony_ci seq_printf(s, "%pad: %s\n", &dma, 20862306a36Sopenharmony_ci xhci_decode_trb(str, XHCI_MSG_MAX, le32_to_cpu(trb->generic.field[0]), 20962306a36Sopenharmony_ci le32_to_cpu(trb->generic.field[1]), 21062306a36Sopenharmony_ci le32_to_cpu(trb->generic.field[2]), 21162306a36Sopenharmony_ci le32_to_cpu(trb->generic.field[3]))); 21262306a36Sopenharmony_ci } 21362306a36Sopenharmony_ci} 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_cistatic int xhci_ring_trb_show(struct seq_file *s, void *unused) 21662306a36Sopenharmony_ci{ 21762306a36Sopenharmony_ci int i; 21862306a36Sopenharmony_ci struct xhci_ring *ring = *(struct xhci_ring **)s->private; 21962306a36Sopenharmony_ci struct xhci_segment *seg = ring->first_seg; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci for (i = 0; i < ring->num_segs; i++) { 22262306a36Sopenharmony_ci xhci_ring_dump_segment(s, seg); 22362306a36Sopenharmony_ci seg = seg->next; 22462306a36Sopenharmony_ci } 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci return 0; 22762306a36Sopenharmony_ci} 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_cistatic struct xhci_file_map ring_files[] = { 23062306a36Sopenharmony_ci {"enqueue", xhci_ring_enqueue_show, }, 23162306a36Sopenharmony_ci {"dequeue", xhci_ring_dequeue_show, }, 23262306a36Sopenharmony_ci {"cycle", xhci_ring_cycle_show, }, 23362306a36Sopenharmony_ci {"trbs", xhci_ring_trb_show, }, 23462306a36Sopenharmony_ci}; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_cistatic int xhci_ring_open(struct inode *inode, struct file *file) 23762306a36Sopenharmony_ci{ 23862306a36Sopenharmony_ci int i; 23962306a36Sopenharmony_ci struct xhci_file_map *f_map; 24062306a36Sopenharmony_ci const char *file_name = file_dentry(file)->d_iname; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ring_files); i++) { 24362306a36Sopenharmony_ci f_map = &ring_files[i]; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci if (strcmp(f_map->name, file_name) == 0) 24662306a36Sopenharmony_ci break; 24762306a36Sopenharmony_ci } 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci return single_open(file, f_map->show, inode->i_private); 25062306a36Sopenharmony_ci} 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_cistatic const struct file_operations xhci_ring_fops = { 25362306a36Sopenharmony_ci .open = xhci_ring_open, 25462306a36Sopenharmony_ci .read = seq_read, 25562306a36Sopenharmony_ci .llseek = seq_lseek, 25662306a36Sopenharmony_ci .release = single_release, 25762306a36Sopenharmony_ci}; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_cistatic int xhci_slot_context_show(struct seq_file *s, void *unused) 26062306a36Sopenharmony_ci{ 26162306a36Sopenharmony_ci struct xhci_hcd *xhci; 26262306a36Sopenharmony_ci struct xhci_slot_ctx *slot_ctx; 26362306a36Sopenharmony_ci struct xhci_slot_priv *priv = s->private; 26462306a36Sopenharmony_ci struct xhci_virt_device *dev = priv->dev; 26562306a36Sopenharmony_ci char str[XHCI_MSG_MAX]; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci xhci = hcd_to_xhci(bus_to_hcd(dev->udev->bus)); 26862306a36Sopenharmony_ci slot_ctx = xhci_get_slot_ctx(xhci, dev->out_ctx); 26962306a36Sopenharmony_ci seq_printf(s, "%pad: %s\n", &dev->out_ctx->dma, 27062306a36Sopenharmony_ci xhci_decode_slot_context(str, 27162306a36Sopenharmony_ci le32_to_cpu(slot_ctx->dev_info), 27262306a36Sopenharmony_ci le32_to_cpu(slot_ctx->dev_info2), 27362306a36Sopenharmony_ci le32_to_cpu(slot_ctx->tt_info), 27462306a36Sopenharmony_ci le32_to_cpu(slot_ctx->dev_state))); 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci return 0; 27762306a36Sopenharmony_ci} 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_cistatic int xhci_endpoint_context_show(struct seq_file *s, void *unused) 28062306a36Sopenharmony_ci{ 28162306a36Sopenharmony_ci int ep_index; 28262306a36Sopenharmony_ci dma_addr_t dma; 28362306a36Sopenharmony_ci struct xhci_hcd *xhci; 28462306a36Sopenharmony_ci struct xhci_ep_ctx *ep_ctx; 28562306a36Sopenharmony_ci struct xhci_slot_priv *priv = s->private; 28662306a36Sopenharmony_ci struct xhci_virt_device *dev = priv->dev; 28762306a36Sopenharmony_ci char str[XHCI_MSG_MAX]; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci xhci = hcd_to_xhci(bus_to_hcd(dev->udev->bus)); 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci for (ep_index = 0; ep_index < 31; ep_index++) { 29262306a36Sopenharmony_ci ep_ctx = xhci_get_ep_ctx(xhci, dev->out_ctx, ep_index); 29362306a36Sopenharmony_ci dma = dev->out_ctx->dma + (ep_index + 1) * CTX_SIZE(xhci->hcc_params); 29462306a36Sopenharmony_ci seq_printf(s, "%pad: %s\n", &dma, 29562306a36Sopenharmony_ci xhci_decode_ep_context(str, 29662306a36Sopenharmony_ci le32_to_cpu(ep_ctx->ep_info), 29762306a36Sopenharmony_ci le32_to_cpu(ep_ctx->ep_info2), 29862306a36Sopenharmony_ci le64_to_cpu(ep_ctx->deq), 29962306a36Sopenharmony_ci le32_to_cpu(ep_ctx->tx_info))); 30062306a36Sopenharmony_ci } 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci return 0; 30362306a36Sopenharmony_ci} 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_cistatic int xhci_device_name_show(struct seq_file *s, void *unused) 30662306a36Sopenharmony_ci{ 30762306a36Sopenharmony_ci struct xhci_slot_priv *priv = s->private; 30862306a36Sopenharmony_ci struct xhci_virt_device *dev = priv->dev; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci seq_printf(s, "%s\n", dev_name(&dev->udev->dev)); 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci return 0; 31362306a36Sopenharmony_ci} 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_cistatic struct xhci_file_map context_files[] = { 31662306a36Sopenharmony_ci {"name", xhci_device_name_show, }, 31762306a36Sopenharmony_ci {"slot-context", xhci_slot_context_show, }, 31862306a36Sopenharmony_ci {"ep-context", xhci_endpoint_context_show, }, 31962306a36Sopenharmony_ci}; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_cistatic int xhci_context_open(struct inode *inode, struct file *file) 32262306a36Sopenharmony_ci{ 32362306a36Sopenharmony_ci int i; 32462306a36Sopenharmony_ci struct xhci_file_map *f_map; 32562306a36Sopenharmony_ci const char *file_name = file_dentry(file)->d_iname; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(context_files); i++) { 32862306a36Sopenharmony_ci f_map = &context_files[i]; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci if (strcmp(f_map->name, file_name) == 0) 33162306a36Sopenharmony_ci break; 33262306a36Sopenharmony_ci } 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci return single_open(file, f_map->show, inode->i_private); 33562306a36Sopenharmony_ci} 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_cistatic const struct file_operations xhci_context_fops = { 33862306a36Sopenharmony_ci .open = xhci_context_open, 33962306a36Sopenharmony_ci .read = seq_read, 34062306a36Sopenharmony_ci .llseek = seq_lseek, 34162306a36Sopenharmony_ci .release = single_release, 34262306a36Sopenharmony_ci}; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_cistatic int xhci_portsc_show(struct seq_file *s, void *unused) 34762306a36Sopenharmony_ci{ 34862306a36Sopenharmony_ci struct xhci_port *port = s->private; 34962306a36Sopenharmony_ci u32 portsc; 35062306a36Sopenharmony_ci char str[XHCI_MSG_MAX]; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci portsc = readl(port->addr); 35362306a36Sopenharmony_ci seq_printf(s, "%s\n", xhci_decode_portsc(str, portsc)); 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci return 0; 35662306a36Sopenharmony_ci} 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_cistatic int xhci_port_open(struct inode *inode, struct file *file) 35962306a36Sopenharmony_ci{ 36062306a36Sopenharmony_ci return single_open(file, xhci_portsc_show, inode->i_private); 36162306a36Sopenharmony_ci} 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_cistatic ssize_t xhci_port_write(struct file *file, const char __user *ubuf, 36462306a36Sopenharmony_ci size_t count, loff_t *ppos) 36562306a36Sopenharmony_ci{ 36662306a36Sopenharmony_ci struct seq_file *s = file->private_data; 36762306a36Sopenharmony_ci struct xhci_port *port = s->private; 36862306a36Sopenharmony_ci struct xhci_hcd *xhci = hcd_to_xhci(port->rhub->hcd); 36962306a36Sopenharmony_ci char buf[32]; 37062306a36Sopenharmony_ci u32 portsc; 37162306a36Sopenharmony_ci unsigned long flags; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) 37462306a36Sopenharmony_ci return -EFAULT; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci if (!strncmp(buf, "compliance", 10)) { 37762306a36Sopenharmony_ci /* If CTC is clear, compliance is enabled by default */ 37862306a36Sopenharmony_ci if (!HCC2_CTC(xhci->hcc_params2)) 37962306a36Sopenharmony_ci return count; 38062306a36Sopenharmony_ci spin_lock_irqsave(&xhci->lock, flags); 38162306a36Sopenharmony_ci /* compliance mode can only be enabled on ports in RxDetect */ 38262306a36Sopenharmony_ci portsc = readl(port->addr); 38362306a36Sopenharmony_ci if ((portsc & PORT_PLS_MASK) != XDEV_RXDETECT) { 38462306a36Sopenharmony_ci spin_unlock_irqrestore(&xhci->lock, flags); 38562306a36Sopenharmony_ci return -EPERM; 38662306a36Sopenharmony_ci } 38762306a36Sopenharmony_ci portsc = xhci_port_state_to_neutral(portsc); 38862306a36Sopenharmony_ci portsc &= ~PORT_PLS_MASK; 38962306a36Sopenharmony_ci portsc |= PORT_LINK_STROBE | XDEV_COMP_MODE; 39062306a36Sopenharmony_ci writel(portsc, port->addr); 39162306a36Sopenharmony_ci spin_unlock_irqrestore(&xhci->lock, flags); 39262306a36Sopenharmony_ci } else { 39362306a36Sopenharmony_ci return -EINVAL; 39462306a36Sopenharmony_ci } 39562306a36Sopenharmony_ci return count; 39662306a36Sopenharmony_ci} 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_cistatic const struct file_operations port_fops = { 39962306a36Sopenharmony_ci .open = xhci_port_open, 40062306a36Sopenharmony_ci .write = xhci_port_write, 40162306a36Sopenharmony_ci .read = seq_read, 40262306a36Sopenharmony_ci .llseek = seq_lseek, 40362306a36Sopenharmony_ci .release = single_release, 40462306a36Sopenharmony_ci}; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_cistatic void xhci_debugfs_create_files(struct xhci_hcd *xhci, 40762306a36Sopenharmony_ci struct xhci_file_map *files, 40862306a36Sopenharmony_ci size_t nentries, void *data, 40962306a36Sopenharmony_ci struct dentry *parent, 41062306a36Sopenharmony_ci const struct file_operations *fops) 41162306a36Sopenharmony_ci{ 41262306a36Sopenharmony_ci int i; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci for (i = 0; i < nentries; i++) 41562306a36Sopenharmony_ci debugfs_create_file(files[i].name, 0444, parent, data, fops); 41662306a36Sopenharmony_ci} 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_cistatic struct dentry *xhci_debugfs_create_ring_dir(struct xhci_hcd *xhci, 41962306a36Sopenharmony_ci struct xhci_ring **ring, 42062306a36Sopenharmony_ci const char *name, 42162306a36Sopenharmony_ci struct dentry *parent) 42262306a36Sopenharmony_ci{ 42362306a36Sopenharmony_ci struct dentry *dir; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci dir = debugfs_create_dir(name, parent); 42662306a36Sopenharmony_ci xhci_debugfs_create_files(xhci, ring_files, ARRAY_SIZE(ring_files), 42762306a36Sopenharmony_ci ring, dir, &xhci_ring_fops); 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci return dir; 43062306a36Sopenharmony_ci} 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_cistatic void xhci_debugfs_create_context_files(struct xhci_hcd *xhci, 43362306a36Sopenharmony_ci struct dentry *parent, 43462306a36Sopenharmony_ci int slot_id) 43562306a36Sopenharmony_ci{ 43662306a36Sopenharmony_ci struct xhci_virt_device *dev = xhci->devs[slot_id]; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci xhci_debugfs_create_files(xhci, context_files, 43962306a36Sopenharmony_ci ARRAY_SIZE(context_files), 44062306a36Sopenharmony_ci dev->debugfs_private, 44162306a36Sopenharmony_ci parent, &xhci_context_fops); 44262306a36Sopenharmony_ci} 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_civoid xhci_debugfs_create_endpoint(struct xhci_hcd *xhci, 44562306a36Sopenharmony_ci struct xhci_virt_device *dev, 44662306a36Sopenharmony_ci int ep_index) 44762306a36Sopenharmony_ci{ 44862306a36Sopenharmony_ci struct xhci_ep_priv *epriv; 44962306a36Sopenharmony_ci struct xhci_slot_priv *spriv = dev->debugfs_private; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci if (!spriv) 45262306a36Sopenharmony_ci return; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci if (spriv->eps[ep_index]) 45562306a36Sopenharmony_ci return; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci epriv = kzalloc(sizeof(*epriv), GFP_KERNEL); 45862306a36Sopenharmony_ci if (!epriv) 45962306a36Sopenharmony_ci return; 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci epriv->show_ring = dev->eps[ep_index].ring; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci snprintf(epriv->name, sizeof(epriv->name), "ep%02d", ep_index); 46462306a36Sopenharmony_ci epriv->root = xhci_debugfs_create_ring_dir(xhci, 46562306a36Sopenharmony_ci &epriv->show_ring, 46662306a36Sopenharmony_ci epriv->name, 46762306a36Sopenharmony_ci spriv->root); 46862306a36Sopenharmony_ci spriv->eps[ep_index] = epriv; 46962306a36Sopenharmony_ci} 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_civoid xhci_debugfs_remove_endpoint(struct xhci_hcd *xhci, 47262306a36Sopenharmony_ci struct xhci_virt_device *dev, 47362306a36Sopenharmony_ci int ep_index) 47462306a36Sopenharmony_ci{ 47562306a36Sopenharmony_ci struct xhci_ep_priv *epriv; 47662306a36Sopenharmony_ci struct xhci_slot_priv *spriv = dev->debugfs_private; 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci if (!spriv || !spriv->eps[ep_index]) 47962306a36Sopenharmony_ci return; 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci epriv = spriv->eps[ep_index]; 48262306a36Sopenharmony_ci debugfs_remove_recursive(epriv->root); 48362306a36Sopenharmony_ci spriv->eps[ep_index] = NULL; 48462306a36Sopenharmony_ci kfree(epriv); 48562306a36Sopenharmony_ci} 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_cistatic int xhci_stream_id_show(struct seq_file *s, void *unused) 48862306a36Sopenharmony_ci{ 48962306a36Sopenharmony_ci struct xhci_ep_priv *epriv = s->private; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci if (!epriv->stream_info) 49262306a36Sopenharmony_ci return -EPERM; 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci seq_printf(s, "Show stream ID %d trb ring, supported [1 - %d]\n", 49562306a36Sopenharmony_ci epriv->stream_id, epriv->stream_info->num_streams - 1); 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci return 0; 49862306a36Sopenharmony_ci} 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_cistatic int xhci_stream_id_open(struct inode *inode, struct file *file) 50162306a36Sopenharmony_ci{ 50262306a36Sopenharmony_ci return single_open(file, xhci_stream_id_show, inode->i_private); 50362306a36Sopenharmony_ci} 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_cistatic ssize_t xhci_stream_id_write(struct file *file, const char __user *ubuf, 50662306a36Sopenharmony_ci size_t count, loff_t *ppos) 50762306a36Sopenharmony_ci{ 50862306a36Sopenharmony_ci struct seq_file *s = file->private_data; 50962306a36Sopenharmony_ci struct xhci_ep_priv *epriv = s->private; 51062306a36Sopenharmony_ci int ret; 51162306a36Sopenharmony_ci u16 stream_id; /* MaxPStreams + 1 <= 16 */ 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci if (!epriv->stream_info) 51462306a36Sopenharmony_ci return -EPERM; 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci /* Decimal number */ 51762306a36Sopenharmony_ci ret = kstrtou16_from_user(ubuf, count, 10, &stream_id); 51862306a36Sopenharmony_ci if (ret) 51962306a36Sopenharmony_ci return ret; 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci if (stream_id == 0 || stream_id >= epriv->stream_info->num_streams) 52262306a36Sopenharmony_ci return -EINVAL; 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci epriv->stream_id = stream_id; 52562306a36Sopenharmony_ci epriv->show_ring = epriv->stream_info->stream_rings[stream_id]; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci return count; 52862306a36Sopenharmony_ci} 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_cistatic const struct file_operations stream_id_fops = { 53162306a36Sopenharmony_ci .open = xhci_stream_id_open, 53262306a36Sopenharmony_ci .write = xhci_stream_id_write, 53362306a36Sopenharmony_ci .read = seq_read, 53462306a36Sopenharmony_ci .llseek = seq_lseek, 53562306a36Sopenharmony_ci .release = single_release, 53662306a36Sopenharmony_ci}; 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_cistatic int xhci_stream_context_array_show(struct seq_file *s, void *unused) 53962306a36Sopenharmony_ci{ 54062306a36Sopenharmony_ci struct xhci_ep_priv *epriv = s->private; 54162306a36Sopenharmony_ci struct xhci_stream_ctx *stream_ctx; 54262306a36Sopenharmony_ci dma_addr_t dma; 54362306a36Sopenharmony_ci int id; 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci if (!epriv->stream_info) 54662306a36Sopenharmony_ci return -EPERM; 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci seq_printf(s, "Allocated %d streams and %d stream context array entries\n", 54962306a36Sopenharmony_ci epriv->stream_info->num_streams, 55062306a36Sopenharmony_ci epriv->stream_info->num_stream_ctxs); 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci for (id = 0; id < epriv->stream_info->num_stream_ctxs; id++) { 55362306a36Sopenharmony_ci stream_ctx = epriv->stream_info->stream_ctx_array + id; 55462306a36Sopenharmony_ci dma = epriv->stream_info->ctx_array_dma + id * 16; 55562306a36Sopenharmony_ci if (id < epriv->stream_info->num_streams) 55662306a36Sopenharmony_ci seq_printf(s, "%pad stream id %d deq %016llx\n", &dma, 55762306a36Sopenharmony_ci id, le64_to_cpu(stream_ctx->stream_ring)); 55862306a36Sopenharmony_ci else 55962306a36Sopenharmony_ci seq_printf(s, "%pad stream context entry not used deq %016llx\n", 56062306a36Sopenharmony_ci &dma, le64_to_cpu(stream_ctx->stream_ring)); 56162306a36Sopenharmony_ci } 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci return 0; 56462306a36Sopenharmony_ci} 56562306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(xhci_stream_context_array); 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_civoid xhci_debugfs_create_stream_files(struct xhci_hcd *xhci, 56862306a36Sopenharmony_ci struct xhci_virt_device *dev, 56962306a36Sopenharmony_ci int ep_index) 57062306a36Sopenharmony_ci{ 57162306a36Sopenharmony_ci struct xhci_slot_priv *spriv = dev->debugfs_private; 57262306a36Sopenharmony_ci struct xhci_ep_priv *epriv; 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci if (!spriv || !spriv->eps[ep_index] || 57562306a36Sopenharmony_ci !dev->eps[ep_index].stream_info) 57662306a36Sopenharmony_ci return; 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci epriv = spriv->eps[ep_index]; 57962306a36Sopenharmony_ci epriv->stream_info = dev->eps[ep_index].stream_info; 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci /* Show trb ring of stream ID 1 by default */ 58262306a36Sopenharmony_ci epriv->stream_id = 1; 58362306a36Sopenharmony_ci epriv->show_ring = epriv->stream_info->stream_rings[1]; 58462306a36Sopenharmony_ci debugfs_create_file("stream_id", 0644, 58562306a36Sopenharmony_ci epriv->root, epriv, 58662306a36Sopenharmony_ci &stream_id_fops); 58762306a36Sopenharmony_ci debugfs_create_file("stream_context_array", 0444, 58862306a36Sopenharmony_ci epriv->root, epriv, 58962306a36Sopenharmony_ci &xhci_stream_context_array_fops); 59062306a36Sopenharmony_ci} 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_civoid xhci_debugfs_create_slot(struct xhci_hcd *xhci, int slot_id) 59362306a36Sopenharmony_ci{ 59462306a36Sopenharmony_ci struct xhci_slot_priv *priv; 59562306a36Sopenharmony_ci struct xhci_virt_device *dev = xhci->devs[slot_id]; 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci priv = kzalloc(sizeof(*priv), GFP_KERNEL); 59862306a36Sopenharmony_ci if (!priv) 59962306a36Sopenharmony_ci return; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci snprintf(priv->name, sizeof(priv->name), "%02d", slot_id); 60262306a36Sopenharmony_ci priv->root = debugfs_create_dir(priv->name, xhci->debugfs_slots); 60362306a36Sopenharmony_ci priv->dev = dev; 60462306a36Sopenharmony_ci dev->debugfs_private = priv; 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci xhci_debugfs_create_ring_dir(xhci, &dev->eps[0].ring, 60762306a36Sopenharmony_ci "ep00", priv->root); 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci xhci_debugfs_create_context_files(xhci, priv->root, slot_id); 61062306a36Sopenharmony_ci} 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_civoid xhci_debugfs_remove_slot(struct xhci_hcd *xhci, int slot_id) 61362306a36Sopenharmony_ci{ 61462306a36Sopenharmony_ci int i; 61562306a36Sopenharmony_ci struct xhci_slot_priv *priv; 61662306a36Sopenharmony_ci struct xhci_virt_device *dev = xhci->devs[slot_id]; 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci if (!dev || !dev->debugfs_private) 61962306a36Sopenharmony_ci return; 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci priv = dev->debugfs_private; 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci debugfs_remove_recursive(priv->root); 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci for (i = 0; i < 31; i++) 62662306a36Sopenharmony_ci kfree(priv->eps[i]); 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci kfree(priv); 62962306a36Sopenharmony_ci dev->debugfs_private = NULL; 63062306a36Sopenharmony_ci} 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_cistatic void xhci_debugfs_create_ports(struct xhci_hcd *xhci, 63362306a36Sopenharmony_ci struct dentry *parent) 63462306a36Sopenharmony_ci{ 63562306a36Sopenharmony_ci unsigned int num_ports; 63662306a36Sopenharmony_ci char port_name[8]; 63762306a36Sopenharmony_ci struct xhci_port *port; 63862306a36Sopenharmony_ci struct dentry *dir; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci num_ports = HCS_MAX_PORTS(xhci->hcs_params1); 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci parent = debugfs_create_dir("ports", parent); 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci while (num_ports--) { 64562306a36Sopenharmony_ci scnprintf(port_name, sizeof(port_name), "port%02d", 64662306a36Sopenharmony_ci num_ports + 1); 64762306a36Sopenharmony_ci dir = debugfs_create_dir(port_name, parent); 64862306a36Sopenharmony_ci port = &xhci->hw_ports[num_ports]; 64962306a36Sopenharmony_ci debugfs_create_file("portsc", 0644, dir, port, &port_fops); 65062306a36Sopenharmony_ci } 65162306a36Sopenharmony_ci} 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_civoid xhci_debugfs_init(struct xhci_hcd *xhci) 65462306a36Sopenharmony_ci{ 65562306a36Sopenharmony_ci struct device *dev = xhci_to_hcd(xhci)->self.controller; 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci xhci->debugfs_root = debugfs_create_dir(dev_name(dev), 65862306a36Sopenharmony_ci xhci_debugfs_root); 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci INIT_LIST_HEAD(&xhci->regset_list); 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci xhci_debugfs_regset(xhci, 66362306a36Sopenharmony_ci 0, 66462306a36Sopenharmony_ci xhci_cap_regs, ARRAY_SIZE(xhci_cap_regs), 66562306a36Sopenharmony_ci xhci->debugfs_root, "reg-cap"); 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci xhci_debugfs_regset(xhci, 66862306a36Sopenharmony_ci HC_LENGTH(readl(&xhci->cap_regs->hc_capbase)), 66962306a36Sopenharmony_ci xhci_op_regs, ARRAY_SIZE(xhci_op_regs), 67062306a36Sopenharmony_ci xhci->debugfs_root, "reg-op"); 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci xhci_debugfs_regset(xhci, 67362306a36Sopenharmony_ci readl(&xhci->cap_regs->run_regs_off) & RTSOFF_MASK, 67462306a36Sopenharmony_ci xhci_runtime_regs, ARRAY_SIZE(xhci_runtime_regs), 67562306a36Sopenharmony_ci xhci->debugfs_root, "reg-runtime"); 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci xhci_debugfs_extcap_regset(xhci, XHCI_EXT_CAPS_LEGACY, 67862306a36Sopenharmony_ci xhci_extcap_legsup, 67962306a36Sopenharmony_ci ARRAY_SIZE(xhci_extcap_legsup), 68062306a36Sopenharmony_ci "reg-ext-legsup"); 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci xhci_debugfs_extcap_regset(xhci, XHCI_EXT_CAPS_PROTOCOL, 68362306a36Sopenharmony_ci xhci_extcap_protocol, 68462306a36Sopenharmony_ci ARRAY_SIZE(xhci_extcap_protocol), 68562306a36Sopenharmony_ci "reg-ext-protocol"); 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci xhci_debugfs_extcap_regset(xhci, XHCI_EXT_CAPS_DEBUG, 68862306a36Sopenharmony_ci xhci_extcap_dbc, 68962306a36Sopenharmony_ci ARRAY_SIZE(xhci_extcap_dbc), 69062306a36Sopenharmony_ci "reg-ext-dbc"); 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci xhci_debugfs_create_ring_dir(xhci, &xhci->cmd_ring, 69362306a36Sopenharmony_ci "command-ring", 69462306a36Sopenharmony_ci xhci->debugfs_root); 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci xhci_debugfs_create_ring_dir(xhci, &xhci->interrupter->event_ring, 69762306a36Sopenharmony_ci "event-ring", 69862306a36Sopenharmony_ci xhci->debugfs_root); 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci xhci->debugfs_slots = debugfs_create_dir("devices", xhci->debugfs_root); 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci xhci_debugfs_create_ports(xhci, xhci->debugfs_root); 70362306a36Sopenharmony_ci} 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_civoid xhci_debugfs_exit(struct xhci_hcd *xhci) 70662306a36Sopenharmony_ci{ 70762306a36Sopenharmony_ci struct xhci_regset *rgs, *tmp; 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci debugfs_remove_recursive(xhci->debugfs_root); 71062306a36Sopenharmony_ci xhci->debugfs_root = NULL; 71162306a36Sopenharmony_ci xhci->debugfs_slots = NULL; 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci list_for_each_entry_safe(rgs, tmp, &xhci->regset_list, list) 71462306a36Sopenharmony_ci xhci_debugfs_free_regset(rgs); 71562306a36Sopenharmony_ci} 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_civoid __init xhci_debugfs_create_root(void) 71862306a36Sopenharmony_ci{ 71962306a36Sopenharmony_ci xhci_debugfs_root = debugfs_create_dir("xhci", usb_debug_root); 72062306a36Sopenharmony_ci} 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_civoid __exit xhci_debugfs_remove_root(void) 72362306a36Sopenharmony_ci{ 72462306a36Sopenharmony_ci debugfs_remove_recursive(xhci_debugfs_root); 72562306a36Sopenharmony_ci xhci_debugfs_root = NULL; 72662306a36Sopenharmony_ci} 727