Skip to content

Commit 1117621

Browse files
Xu Raoopsiff
authored andcommitted
usb: xhci: Add debugfs support for xHCI port bandwidth
[ Upstream commit 59d50e53e070ce03c811e31c4fb583d3b0f88cfc ] In many projects, you need to obtain the available bandwidth of the xhci roothub port. Refer to xhci rev1_2 and use the TRB_GET_BW command to obtain it. hardware tested: 03:00.3 USB controller: Advanced Micro Devices, Inc. [AMD] Raven USB 3.1 (prog-if 30 [XHCI]) Subsystem: Huawei Technologies Co., Ltd. Raven USB 3.1 Flags: bus master, fast devsel, latency 0, IRQ 30 Memory at c0300000 (64-bit, non-prefetchable) [size=1M] Capabilities: [48] Vendor Specific Information: Len=08 <?> Capabilities: [50] Power Management version 3 Capabilities: [64] Express Endpoint, MSI 00 Capabilities: [a0] MSI: Enable- Count=1/8 Maskable- 64bit+ Capabilities: [c0] MSI-X: Enable+ Count=8 Masked- Kernel driver in use: xhci_hcd test progress: 1. cd /sys/kernel/debug/usb/xhci/0000:03:00.3/port_bandwidth# ls FS_BW HS_BW SS_BW 2. test fs speed device cat FS_BW port[1] available bw: 90%. port[2] available bw: 90%. port[3] available bw: 90%. port[4] available bw: 90%. port[5] available bw: 0%. port[6] available bw: 0%. port[7] available bw: 0%. port[8] available bw: 0%. plug in fs usb audio ID 0d8c:013c cat FS_BW port[1] available bw: 76%. port[2] available bw: 76%. port[3] available bw: 76%. port[4] available bw: 76%. port[5] available bw: 0%. port[6] available bw: 0%. port[7] available bw: 0%. port[8] available bw: 0%. 3. test hs speed device cat HS_BW port[1] available bw: 79%. port[2] available bw: 79%. port[3] available bw: 79%. port[4] available bw: 79%. port[5] available bw: 0%. port[6] available bw: 0%. port[7] available bw: 0%. port[8] available bw: 0%. plug in hs usb video ID 0408:1040 cat HS_BW port[1] available bw: 39%. port[2] available bw: 39%. port[3] available bw: 39%. port[4] available bw: 39%. port[5] available bw: 0%. port[6] available bw: 0%. port[7] available bw: 0%. port[8] available bw: 0%. 4.cat SS_BW port[1] available bw: 0%. port[2] available bw: 0%. port[3] available bw: 0%. port[4] available bw: 0%. port[5] available bw: 90%. port[6] available bw: 90%. port[7] available bw: 90%. port[8] available bw: 90%. Signed-off-by: Xu Rao <[email protected]> Signed-off-by: Mathias Nyman <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]> [ Backport from v6.16 ] Signed-off-by: WangYuli <[email protected]>
1 parent ca8fba1 commit 1117621

File tree

5 files changed

+215
-1
lines changed

5 files changed

+215
-1
lines changed

drivers/usb/host/xhci-debugfs.c

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -651,6 +651,112 @@ static void xhci_debugfs_create_ports(struct xhci_hcd *xhci,
651651
}
652652
}
653653

654+
static int xhci_port_bw_show(struct xhci_hcd *xhci, u8 dev_speed,
655+
struct seq_file *s)
656+
{
657+
unsigned int num_ports;
658+
unsigned int i;
659+
int ret;
660+
struct xhci_container_ctx *ctx;
661+
struct usb_hcd *hcd = xhci_to_hcd(xhci);
662+
struct device *dev = hcd->self.controller;
663+
664+
ret = pm_runtime_get_sync(dev);
665+
if (ret < 0)
666+
return ret;
667+
668+
num_ports = HCS_MAX_PORTS(xhci->hcs_params1);
669+
670+
ctx = xhci_alloc_port_bw_ctx(xhci, 0);
671+
if (!ctx) {
672+
pm_runtime_put_sync(dev);
673+
return -ENOMEM;
674+
}
675+
676+
/* get roothub port bandwidth */
677+
ret = xhci_get_port_bandwidth(xhci, ctx, dev_speed);
678+
if (ret)
679+
goto err_out;
680+
681+
/* print all roothub ports available bandwidth
682+
* refer to xhci rev1_2 protocol 6.2.6 , byte 0 is reserved
683+
*/
684+
for (i = 1; i < num_ports+1; i++)
685+
seq_printf(s, "port[%d] available bw: %d%%.\n", i,
686+
ctx->bytes[i]);
687+
err_out:
688+
pm_runtime_put_sync(dev);
689+
xhci_free_port_bw_ctx(xhci, ctx);
690+
return ret;
691+
}
692+
693+
static int xhci_ss_bw_show(struct seq_file *s, void *unused)
694+
{
695+
int ret;
696+
struct xhci_hcd *xhci = (struct xhci_hcd *)s->private;
697+
698+
ret = xhci_port_bw_show(xhci, USB_SPEED_SUPER, s);
699+
return ret;
700+
}
701+
702+
static int xhci_hs_bw_show(struct seq_file *s, void *unused)
703+
{
704+
int ret;
705+
struct xhci_hcd *xhci = (struct xhci_hcd *)s->private;
706+
707+
ret = xhci_port_bw_show(xhci, USB_SPEED_HIGH, s);
708+
return ret;
709+
}
710+
711+
static int xhci_fs_bw_show(struct seq_file *s, void *unused)
712+
{
713+
int ret;
714+
struct xhci_hcd *xhci = (struct xhci_hcd *)s->private;
715+
716+
ret = xhci_port_bw_show(xhci, USB_SPEED_FULL, s);
717+
return ret;
718+
}
719+
720+
static struct xhci_file_map bw_context_files[] = {
721+
{"SS_BW", xhci_ss_bw_show, },
722+
{"HS_BW", xhci_hs_bw_show, },
723+
{"FS_BW", xhci_fs_bw_show, },
724+
};
725+
726+
static int bw_context_open(struct inode *inode, struct file *file)
727+
{
728+
int i;
729+
struct xhci_file_map *f_map;
730+
const char *file_name = file_dentry(file)->d_iname;
731+
732+
for (i = 0; i < ARRAY_SIZE(bw_context_files); i++) {
733+
f_map = &bw_context_files[i];
734+
735+
if (strcmp(f_map->name, file_name) == 0)
736+
break;
737+
}
738+
739+
return single_open(file, f_map->show, inode->i_private);
740+
}
741+
742+
static const struct file_operations bw_fops = {
743+
.open = bw_context_open,
744+
.read = seq_read,
745+
.llseek = seq_lseek,
746+
.release = single_release,
747+
};
748+
749+
static void xhci_debugfs_create_bandwidth(struct xhci_hcd *xhci,
750+
struct dentry *parent)
751+
{
752+
parent = debugfs_create_dir("port_bandwidth", parent);
753+
754+
xhci_debugfs_create_files(xhci, bw_context_files,
755+
ARRAY_SIZE(bw_context_files),
756+
xhci,
757+
parent, &bw_fops);
758+
}
759+
654760
void xhci_debugfs_init(struct xhci_hcd *xhci)
655761
{
656762
struct device *dev = xhci_to_hcd(xhci)->self.controller;
@@ -701,6 +807,8 @@ void xhci_debugfs_init(struct xhci_hcd *xhci)
701807
xhci->debugfs_slots = debugfs_create_dir("devices", xhci->debugfs_root);
702808

703809
xhci_debugfs_create_ports(xhci, xhci->debugfs_root);
810+
811+
xhci_debugfs_create_bandwidth(xhci, xhci->debugfs_root);
704812
}
705813

706814
void xhci_debugfs_exit(struct xhci_hcd *xhci)

drivers/usb/host/xhci-mem.c

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -497,6 +497,35 @@ void xhci_free_container_ctx(struct xhci_hcd *xhci,
497497
kfree(ctx);
498498
}
499499

500+
struct xhci_container_ctx *xhci_alloc_port_bw_ctx(struct xhci_hcd *xhci,
501+
gfp_t flags)
502+
{
503+
struct xhci_container_ctx *ctx;
504+
struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
505+
506+
ctx = kzalloc_node(sizeof(*ctx), flags, dev_to_node(dev));
507+
if (!ctx)
508+
return NULL;
509+
510+
ctx->size = GET_PORT_BW_ARRAY_SIZE;
511+
512+
ctx->bytes = dma_pool_zalloc(xhci->port_bw_pool, flags, &ctx->dma);
513+
if (!ctx->bytes) {
514+
kfree(ctx);
515+
return NULL;
516+
}
517+
return ctx;
518+
}
519+
520+
void xhci_free_port_bw_ctx(struct xhci_hcd *xhci,
521+
struct xhci_container_ctx *ctx)
522+
{
523+
if (!ctx)
524+
return;
525+
dma_pool_free(xhci->port_bw_pool, ctx->bytes, ctx->dma);
526+
kfree(ctx);
527+
}
528+
500529
struct xhci_input_control_ctx *xhci_get_input_control_ctx(
501530
struct xhci_container_ctx *ctx)
502531
{
@@ -1942,6 +1971,11 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
19421971
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
19431972
"Freed small stream array pool");
19441973

1974+
dma_pool_destroy(xhci->port_bw_pool);
1975+
xhci->port_bw_pool = NULL;
1976+
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
1977+
"Freed xhci port bw array pool");
1978+
19451979
dma_pool_destroy(xhci->medium_streams_pool);
19461980
xhci->medium_streams_pool = NULL;
19471981
xhci_dbg_trace(xhci, trace_xhci_dbg_init,
@@ -2510,7 +2544,16 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
25102544
* will be allocated with dma_alloc_coherent()
25112545
*/
25122546

2513-
if (!xhci->small_streams_pool || !xhci->medium_streams_pool)
2547+
/* refer to xhci rev1_2 protocol 5.3.3 max ports is 255.
2548+
* refer to xhci rev1_2 protocol 6.4.3.14 port bandwidth buffer need
2549+
* to be 16-byte aligned.
2550+
*/
2551+
xhci->port_bw_pool =
2552+
dma_pool_create("xHCI 256 port bw ctx arrays",
2553+
dev, GET_PORT_BW_ARRAY_SIZE, 16, 0);
2554+
2555+
if (!xhci->small_streams_pool || !xhci->medium_streams_pool ||
2556+
!xhci->port_bw_pool)
25142557
goto fail;
25152558

25162559
/* Set up the command ring to have one segments for now. */

drivers/usb/host/xhci-ring.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1891,6 +1891,8 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,
18911891
case TRB_NEC_GET_FW:
18921892
xhci_handle_cmd_nec_get_fw(xhci, event);
18931893
break;
1894+
case TRB_GET_BW:
1895+
break;
18941896
default:
18951897
/* Skip over unknown commands on the event ring */
18961898
xhci_info(xhci, "INFO unknown command type %d\n", cmd_type);
@@ -4552,6 +4554,17 @@ int xhci_queue_configure_endpoint(struct xhci_hcd *xhci,
45524554
command_must_succeed);
45534555
}
45544556

4557+
/* Queue a get root hub port bandwidth command TRB */
4558+
int xhci_queue_get_port_bw(struct xhci_hcd *xhci,
4559+
struct xhci_command *cmd, dma_addr_t in_ctx_ptr,
4560+
u8 dev_speed, bool command_must_succeed)
4561+
{
4562+
return queue_command(xhci, cmd, lower_32_bits(in_ctx_ptr),
4563+
upper_32_bits(in_ctx_ptr), 0,
4564+
TRB_TYPE(TRB_GET_BW) | DEV_SPEED_FOR_TRB(dev_speed),
4565+
command_must_succeed);
4566+
}
4567+
45554568
/* Queue an evaluate context command TRB */
45564569
int xhci_queue_evaluate_context(struct xhci_hcd *xhci, struct xhci_command *cmd,
45574570
dma_addr_t in_ctx_ptr, u32 slot_id, bool command_must_succeed)

drivers/usb/host/xhci.c

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3084,6 +3084,42 @@ void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
30843084
}
30853085
EXPORT_SYMBOL_GPL(xhci_reset_bandwidth);
30863086

3087+
/* Get the available bandwidth of the ports under the xhci roothub */
3088+
int xhci_get_port_bandwidth(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx,
3089+
u8 dev_speed)
3090+
{
3091+
struct xhci_command *cmd;
3092+
unsigned long flags;
3093+
int ret;
3094+
3095+
if (!ctx || !xhci)
3096+
return -EINVAL;
3097+
3098+
cmd = xhci_alloc_command(xhci, true, GFP_KERNEL);
3099+
if (!cmd)
3100+
return -ENOMEM;
3101+
3102+
cmd->in_ctx = ctx;
3103+
3104+
/* get xhci port bandwidth, refer to xhci rev1_2 protocol 4.6.15 */
3105+
spin_lock_irqsave(&xhci->lock, flags);
3106+
3107+
ret = xhci_queue_get_port_bw(xhci, cmd, ctx->dma, dev_speed, 0);
3108+
if (ret) {
3109+
spin_unlock_irqrestore(&xhci->lock, flags);
3110+
goto err_out;
3111+
}
3112+
xhci_ring_cmd_db(xhci);
3113+
spin_unlock_irqrestore(&xhci->lock, flags);
3114+
3115+
wait_for_completion(cmd->completion);
3116+
err_out:
3117+
kfree(cmd->completion);
3118+
kfree(cmd);
3119+
3120+
return ret;
3121+
}
3122+
30873123
static void xhci_setup_input_ctx_for_config_ep(struct xhci_hcd *xhci,
30883124
struct xhci_container_ctx *in_ctx,
30893125
struct xhci_container_ctx *out_ctx,

drivers/usb/host/xhci.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -613,6 +613,7 @@ struct xhci_stream_info {
613613

614614
#define SMALL_STREAM_ARRAY_SIZE 256
615615
#define MEDIUM_STREAM_ARRAY_SIZE 1024
616+
#define GET_PORT_BW_ARRAY_SIZE 256
616617

617618
/* Some Intel xHCI host controllers need software to keep track of the bus
618619
* bandwidth. Keep track of endpoint info here. Each root port is allocated
@@ -1023,6 +1024,9 @@ enum xhci_setup_dev {
10231024
#define TRB_TO_SLOT_ID(p) (((p) & (0xff<<24)) >> 24)
10241025
#define SLOT_ID_FOR_TRB(p) (((p) & 0xff) << 24)
10251026

1027+
/* bits 19:16 are the dev speed */
1028+
#define DEV_SPEED_FOR_TRB(p) ((p) << 16)
1029+
10261030
/* Stop Endpoint TRB - ep_index to endpoint ID for this TRB */
10271031
#define TRB_TO_EP_INDEX(p) ((((p) & (0x1f << 16)) >> 16) - 1)
10281032
#define EP_ID_FOR_TRB(p) ((((p) + 1) & 0x1f) << 16)
@@ -1579,6 +1583,7 @@ struct xhci_hcd {
15791583
struct dma_pool *device_pool;
15801584
struct dma_pool *segment_pool;
15811585
struct dma_pool *small_streams_pool;
1586+
struct dma_pool *port_bw_pool;
15821587
struct dma_pool *medium_streams_pool;
15831588

15841589
/* Host controller watchdog timer structures */
@@ -1870,6 +1875,10 @@ struct xhci_container_ctx *xhci_alloc_container_ctx(struct xhci_hcd *xhci,
18701875
int type, gfp_t flags);
18711876
void xhci_free_container_ctx(struct xhci_hcd *xhci,
18721877
struct xhci_container_ctx *ctx);
1878+
struct xhci_container_ctx *xhci_alloc_port_bw_ctx(struct xhci_hcd *xhci,
1879+
gfp_t flags);
1880+
void xhci_free_port_bw_ctx(struct xhci_hcd *xhci,
1881+
struct xhci_container_ctx *ctx);
18731882
struct xhci_interrupter *
18741883
xhci_create_secondary_interrupter(struct usb_hcd *hcd, unsigned int segs,
18751884
u32 imod_interval);
@@ -1941,6 +1950,11 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags,
19411950
int xhci_queue_configure_endpoint(struct xhci_hcd *xhci,
19421951
struct xhci_command *cmd, dma_addr_t in_ctx_ptr, u32 slot_id,
19431952
bool command_must_succeed);
1953+
int xhci_queue_get_port_bw(struct xhci_hcd *xhci,
1954+
struct xhci_command *cmd, dma_addr_t in_ctx_ptr,
1955+
u8 dev_speed, bool command_must_succeed);
1956+
int xhci_get_port_bandwidth(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx,
1957+
u8 dev_speed);
19441958
int xhci_queue_evaluate_context(struct xhci_hcd *xhci, struct xhci_command *cmd,
19451959
dma_addr_t in_ctx_ptr, u32 slot_id, bool command_must_succeed);
19461960
int xhci_queue_reset_ep(struct xhci_hcd *xhci, struct xhci_command *cmd,

0 commit comments

Comments
 (0)