From 11c615d0b770bc57744e964891ba279c71878963 Mon Sep 17 00:00:00 2001 From: Brad Stein Date: Sat, 10 Jan 2026 13:08:38 -0300 Subject: [PATCH] uvc: read fifo caps from debugfs --- scripts/daemon/lesavka-core.sh | 48 ++++++++++++++++++++++--- server/src/bin/lesavka-uvc.rs | 64 ++++++++++++++++++++++++++++------ 2 files changed, 97 insertions(+), 15 deletions(-) diff --git a/scripts/daemon/lesavka-core.sh b/scripts/daemon/lesavka-core.sh index 75993c1..b9a385f 100644 --- a/scripts/daemon/lesavka-core.sh +++ b/scripts/daemon/lesavka-core.sh @@ -131,12 +131,50 @@ uvc_fifo_min() { END { if (min != "") print min }' } +uvc_fifo_min_debugfs() { + local path="$1" + awk -F': ' '/^g_tx_fifo_size\\[/{print $2}' "$path" 2>/dev/null | awk ' + $1 > 0 { if (min == "" || $1 < min) min = $1 } + END { if (min != "") print min }' +} + +uvc_fifo_np_debugfs() { + local path="$1" + awk -F': ' '/^g_np_tx_fifo_size/{print $2; exit}' "$path" 2>/dev/null +} + compute_uvc_payload_cap() { UVC_PAYLOAD_CAP="" UVC_PAYLOAD_SRC="" UVC_PAYLOAD_PCT="" UVC_FIFO_PERIODIC="$(uvc_fifo_min /sys/module/dwc2/parameters/g_tx_fifo_size)" UVC_FIFO_NP="$(uvc_fifo_min /sys/module/dwc2/parameters/g_np_tx_fifo_size)" + UVC_FIFO_SRC_PERIODIC="" + UVC_FIFO_SRC_NP="" + if [[ -n $UVC_FIFO_PERIODIC ]]; then + UVC_FIFO_SRC_PERIODIC="dwc2.params" + fi + if [[ -n $UVC_FIFO_NP ]]; then + UVC_FIFO_SRC_NP="dwc2.params" + fi + UVC_UDC="$(ls /sys/class/udc 2>/dev/null | head -n1 || true)" + if [[ -n $UVC_UDC ]]; then + local params="/sys/kernel/debug/usb/$UVC_UDC/params" + if [[ -r $params ]]; then + if [[ -z $UVC_FIFO_PERIODIC ]]; then + UVC_FIFO_PERIODIC="$(uvc_fifo_min_debugfs "$params")" + if [[ -n $UVC_FIFO_PERIODIC ]]; then + UVC_FIFO_SRC_PERIODIC="debugfs.params" + fi + fi + if [[ -z $UVC_FIFO_NP ]]; then + UVC_FIFO_NP="$(uvc_fifo_np_debugfs "$params")" + if [[ -n $UVC_FIFO_NP ]]; then + UVC_FIFO_SRC_NP="debugfs.params" + fi + fi + fi + fi if [[ -n ${LESAVKA_UVC_MAXPAYLOAD_LIMIT:-} ]]; then UVC_PAYLOAD_CAP="${LESAVKA_UVC_MAXPAYLOAD_LIMIT}" @@ -149,18 +187,18 @@ compute_uvc_payload_cap() { if [[ -n $UVC_BULK ]]; then if [[ -n $UVC_FIFO_NP ]]; then chosen="$UVC_FIFO_NP" - UVC_PAYLOAD_SRC="dwc2.g_np_tx_fifo_size" + UVC_PAYLOAD_SRC="${UVC_FIFO_SRC_NP:-dwc2.g_np_tx_fifo_size}" elif [[ -n $UVC_FIFO_PERIODIC ]]; then chosen="$UVC_FIFO_PERIODIC" - UVC_PAYLOAD_SRC="dwc2.g_tx_fifo_size" + UVC_PAYLOAD_SRC="${UVC_FIFO_SRC_PERIODIC:-dwc2.g_tx_fifo_size}" fi else if [[ -n $UVC_FIFO_PERIODIC ]]; then chosen="$UVC_FIFO_PERIODIC" - UVC_PAYLOAD_SRC="dwc2.g_tx_fifo_size" + UVC_PAYLOAD_SRC="${UVC_FIFO_SRC_PERIODIC:-dwc2.g_tx_fifo_size}" elif [[ -n $UVC_FIFO_NP ]]; then chosen="$UVC_FIFO_NP" - UVC_PAYLOAD_SRC="dwc2.g_np_tx_fifo_size" + UVC_PAYLOAD_SRC="${UVC_FIFO_SRC_NP:-dwc2.g_np_tx_fifo_size}" fi fi @@ -181,7 +219,7 @@ compute_uvc_payload_cap() { compute_uvc_payload_cap if [[ -n $UVC_PAYLOAD_CAP && $UVC_PAYLOAD_CAP -gt 0 ]]; then - log "UVC fifo periodic=${UVC_FIFO_PERIODIC:-?} np=${UVC_FIFO_NP:-?} cap=${UVC_PAYLOAD_CAP}B pct=${UVC_PAYLOAD_PCT:-?} src=${UVC_PAYLOAD_SRC:-?}" + log "UVC fifo periodic=${UVC_FIFO_PERIODIC:-?} np=${UVC_FIFO_NP:-?} cap=${UVC_PAYLOAD_CAP}B pct=${UVC_PAYLOAD_PCT:-?} src=${UVC_PAYLOAD_SRC:-?} udc=${UVC_UDC:-?}" if ((UVC_MAXPACKET > UVC_PAYLOAD_CAP)); then log "clamping UVC maxpacket $UVC_MAXPACKET -> $UVC_PAYLOAD_CAP" UVC_MAXPACKET=$UVC_PAYLOAD_CAP diff --git a/server/src/bin/lesavka-uvc.rs b/server/src/bin/lesavka-uvc.rs index 3eef994..f6113f7 100644 --- a/server/src/bin/lesavka-uvc.rs +++ b/server/src/bin/lesavka-uvc.rs @@ -807,21 +807,35 @@ fn compute_payload_cap(bulk: bool) -> Option { }); } - let periodic_dw = read_fifo_min("/sys/module/dwc2/parameters/g_tx_fifo_size"); - let non_periodic_dw = read_fifo_min("/sys/module/dwc2/parameters/g_np_tx_fifo_size"); + let mut periodic = read_fifo_min("/sys/module/dwc2/parameters/g_tx_fifo_size") + .map(|v| (v, "dwc2.params")); + let mut non_periodic = read_fifo_min("/sys/module/dwc2/parameters/g_np_tx_fifo_size") + .map(|v| (v, "dwc2.params")); + if periodic.is_none() || non_periodic.is_none() { + if let Some((p, np)) = read_debugfs_fifos() { + if periodic.is_none() { + periodic = p.map(|v| (v, "debugfs.params")); + } + if non_periodic.is_none() { + non_periodic = np.map(|v| (v, "debugfs.params")); + } + } + } + let periodic_dw = periodic.map(|(v, _)| v); + let non_periodic_dw = non_periodic.map(|(v, _)| v); let (fifo_dw, source) = if bulk { - if let Some(np) = non_periodic_dw { - (np, "dwc2.g_np_tx_fifo_size") - } else if let Some(p) = periodic_dw { - (p, "dwc2.g_tx_fifo_size") + if let Some((np, src)) = non_periodic { + (np, src) + } else if let Some((p, src)) = periodic { + (p, src) } else { return None; } - } else if let Some(p) = periodic_dw { - (p, "dwc2.g_tx_fifo_size") - } else if let Some(np) = non_periodic_dw { - (np, "dwc2.g_np_tx_fifo_size") + } else if let Some((p, src)) = periodic { + (p, src) + } else if let Some((np, src)) = non_periodic { + (np, src) } else { return None; }; @@ -855,6 +869,36 @@ fn read_fifo_min(path: &str) -> Option { .min() } +fn read_debugfs_fifos() -> Option<(Option, Option)> { + let udc = std::fs::read_dir("/sys/class/udc") + .ok()? + .filter_map(|e| e.ok()) + .filter_map(|e| e.file_name().into_string().ok()) + .next()?; + let path = format!("/sys/kernel/debug/usb/{udc}/params"); + let text = std::fs::read_to_string(path).ok()?; + let mut periodic: Option = None; + let mut non_periodic: Option = None; + for line in text.lines() { + let mut parts = line.splitn(2, ':'); + let key = parts.next()?.trim(); + let val = parts.next()?.trim().parse::().ok()?; + if key == "g_np_tx_fifo_size" { + non_periodic = Some(val); + } else if key.starts_with("g_tx_fifo_size[") && val > 0 { + periodic = Some(match periodic { + Some(prev) => prev.min(val), + None => val, + }); + } + } + if periodic.is_none() && non_periodic.is_none() { + None + } else { + Some((periodic, non_periodic)) + } +} + const IOC_NRBITS: u8 = 8; const IOC_TYPEBITS: u8 = 8; const IOC_SIZEBITS: u8 = 14;