kernel: add uvc debug patch

This commit is contained in:
Brad Stein 2026-01-22 15:23:25 -03:00
parent 8855f9ab78
commit 48dfe4bae7
4 changed files with 353 additions and 1 deletions

View File

@ -20,6 +20,11 @@ PKGBUILD_REPO=${LESAVKA_KERNEL_PKG_REPO:-https://github.com/archlinuxarm/PKGBUIL
BUILD_ROOT=${LESAVKA_KERNEL_BUILD_ROOT:-/var/tmp/lesavka-linux-rpi} BUILD_ROOT=${LESAVKA_KERNEL_BUILD_ROOT:-/var/tmp/lesavka-linux-rpi}
PKGREL=${LESAVKA_KERNEL_PKGREL:-2} PKGREL=${LESAVKA_KERNEL_PKGREL:-2}
JOBS=${LESAVKA_KERNEL_JOBS:-2} JOBS=${LESAVKA_KERNEL_JOBS:-2}
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
PATCH_DIR=${LESAVKA_KERNEL_PATCH_DIR:-$SCRIPT_DIR}
PATCH_DWC2_FIFO=${LESAVKA_KERNEL_PATCH_DWC2_FIFO:-}
PATCH_UVC_BULK=${LESAVKA_KERNEL_PATCH_UVC_BULK:-}
PATCH_UVC_DEBUG=${LESAVKA_KERNEL_PATCH_UVC_DEBUG:-}
HEARTBEAT=/etc/lesavka/watchdog.touch HEARTBEAT=/etc/lesavka/watchdog.touch
if [[ -w $HEARTBEAT && -z ${LESAVKA_DISABLE_KEEPALIVE:-} ]]; then if [[ -w $HEARTBEAT && -z ${LESAVKA_DISABLE_KEEPALIVE:-} ]]; then
@ -94,10 +99,69 @@ for line in sums:
pkgbuild.write_text(text) pkgbuild.write_text(text)
PY PY
MAKEPKG_EXTRA=""
KERNEL_SRC="$BUILD_ROOT/linux-rpi/src/linux-$KERNEL_COMMIT"
PATCHES=()
if [[ -n $PATCH_DWC2_FIFO ]]; then
PATCHES+=("dwc2-fifo.patch")
fi
if [[ -n $PATCH_UVC_BULK ]]; then
PATCHES+=("uvc-bulk.patch")
fi
if [[ -n $PATCH_UVC_DEBUG ]]; then
PATCHES+=("uvc-debug.patch")
fi
if [[ ${#PATCHES[@]} -gt 0 ]]; then
sudo -u "$BUILD_USER" bash -c "
set -euo pipefail
cd '$BUILD_ROOT/linux-rpi'
MAKEFLAGS='-j$JOBS' makepkg -o --noconfirm
"
sudo -u "$BUILD_USER" bash -c "
set -euo pipefail
src='$KERNEL_SRC'
if [[ ! -d \$src ]]; then
echo \"missing kernel source \$src\" >&2
exit 1
fi
cd \"\$src\"
for patch in ${PATCHES[*]}; do
patch_file='$PATCH_DIR/'\"\$patch\"
if [[ ! -f \$patch_file ]]; then
echo \"missing patch \$patch_file\" >&2
exit 1
fi
case \"\$patch\" in
dwc2-fifo.patch)
if grep -q 'dwc2_check_param_fifo_total' \"drivers/usb/dwc2/params.c\"; then
echo \"dwc2-fifo patch already applied\"
continue
fi
;;
uvc-bulk.patch)
if grep -q 'streaming_bulk' \"drivers/usb/gadget/function/uvc_configfs.c\"; then
echo \"uvc-bulk patch already applied\"
continue
fi
;;
uvc-debug.patch)
if grep -q 'uvcg_video_enable: missing uvc/func/config' \
\"drivers/usb/gadget/function/uvc_video.c\"; then
echo \"uvc-debug patch already applied\"
continue
fi
;;
esac
patch -p1 < \"\$patch_file\"
done
"
MAKEPKG_EXTRA="-e"
fi
sudo -u "$BUILD_USER" bash -c " sudo -u "$BUILD_USER" bash -c "
set -euo pipefail set -euo pipefail
cd '$BUILD_ROOT/linux-rpi' cd '$BUILD_ROOT/linux-rpi'
MAKEFLAGS='-j$JOBS' makepkg -s --noconfirm MAKEFLAGS='-j$JOBS' makepkg -s --noconfirm $MAKEPKG_EXTRA
" "
mapfile -t PKGS < <(ls "$BUILD_ROOT/linux-rpi"/*.pkg.tar.* 2>/dev/null) mapfile -t PKGS < <(ls "$BUILD_ROOT/linux-rpi"/*.pkg.tar.* 2>/dev/null)

View File

@ -0,0 +1,68 @@
diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c
index 0a10aa2f8f5c..d7c5a3d1c4de 100644
--- a/drivers/usb/dwc2/gadget.c
+++ b/drivers/usb/dwc2/gadget.c
@@ -226,10 +226,7 @@ int dwc2_hsotg_tx_fifo_total_depth(struct dwc2_hsotg *hsotg)
{
int addr;
int tx_addr_max;
- u32 np_tx_fifo_size;
-
- np_tx_fifo_size = min_t(u32, hsotg->hw_params.dev_nperio_tx_fifo_size,
- hsotg->params.g_np_tx_fifo_size);
+ u32 np_tx_fifo_size = hsotg->params.g_np_tx_fifo_size;
/* Get Endpoint Info Control block size in DWORDs. */
tx_addr_max = hsotg->hw_params.total_fifo_size;
diff --git a/drivers/usb/dwc2/params.c b/drivers/usb/dwc2/params.c
index 5d29c2157fbe..b25f7399b41c 100644
--- a/drivers/usb/dwc2/params.c
+++ b/drivers/usb/dwc2/params.c
@@ -767,6 +767,35 @@ static void dwc2_check_param_tx_fifo_sizes(struct dwc2_hsotg *hsotg)
}
}
+static void dwc2_check_param_fifo_total(struct dwc2_hsotg *hsotg)
+{
+ struct dwc2_core_params *p = &hsotg->params;
+ u32 total_tx = 0;
+ u32 max_np;
+ int fifo_count;
+ int fifo;
+
+ fifo_count = dwc2_hsotg_tx_fifo_count(hsotg);
+ for (fifo = 1; fifo <= fifo_count; fifo++)
+ total_tx += p->g_tx_fifo_size[fifo];
+
+ if (p->g_rx_fifo_size + p->g_np_tx_fifo_size + total_tx <=
+ hsotg->hw_params.total_fifo_size)
+ return;
+
+ max_np = 16;
+ if (hsotg->hw_params.total_fifo_size > p->g_rx_fifo_size + total_tx)
+ max_np = hsotg->hw_params.total_fifo_size -
+ p->g_rx_fifo_size - total_tx;
+ if (max_np < 16)
+ max_np = 16;
+
+ dev_warn(hsotg->dev,
+ "%s: FIFO sizes exceed total, clamping g_np_tx_fifo_size to %u\n",
+ __func__, max_np);
+ p->g_np_tx_fifo_size = max_np;
+}
+
static void dwc2_check_param_eusb2_disc(struct dwc2_hsotg *hsotg)
{
u32 gsnpsid;
@@ -879,9 +879,10 @@ static void dwc2_check_params(struct dwc2_hsotg *hsotg)
CHECK_RANGE(g_rx_fifo_size,
16, hw->rx_fifo_size,
hw->rx_fifo_size);
CHECK_RANGE(g_np_tx_fifo_size,
- 16, hw->dev_nperio_tx_fifo_size,
+ 16, hw->total_fifo_size,
hw->dev_nperio_tx_fifo_size);
dwc2_check_param_tx_fifo_sizes(hsotg);
+ dwc2_check_param_fifo_total(hsotg);
}
}

View File

@ -0,0 +1,173 @@
diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c
index aa6ab666741a..7fb30b09e980 100644
--- a/drivers/usb/gadget/function/f_uvc.c
+++ b/drivers/usb/gadget/function/f_uvc.c
@@ -652,22 +652,32 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
unsigned int max_packet_size;
struct usb_ep *ep;
struct f_uvc_opts *opts;
+ bool bulk;
int ret = -EINVAL;
uvcg_info(f, "%s()\n", __func__);
opts = fi_to_f_uvc_opts(f->fi);
+ bulk = opts->streaming_bulk;
/* Sanity check the streaming endpoint module parameters. */
opts->streaming_interval = clamp(opts->streaming_interval, 1U, 16U);
- opts->streaming_maxpacket = clamp(opts->streaming_maxpacket, 1U, 3072U);
opts->streaming_maxburst = min(opts->streaming_maxburst, 15U);
- /* For SS, wMaxPacketSize has to be 1024 if bMaxBurst is not 0 */
- if (opts->streaming_maxburst &&
- (opts->streaming_maxpacket % 1024) != 0) {
- opts->streaming_maxpacket = roundup(opts->streaming_maxpacket, 1024);
- uvcg_info(f, "overriding streaming_maxpacket to %d\n",
- opts->streaming_maxpacket);
+ if (bulk) {
+ opts->streaming_maxpacket =
+ clamp(opts->streaming_maxpacket, 1U, 1024U);
+ } else {
+ opts->streaming_maxpacket =
+ clamp(opts->streaming_maxpacket, 1U, 3072U);
+ /* For SS, wMaxPacketSize has to be 1024 if bMaxBurst is not 0 */
+ if (opts->streaming_maxburst &&
+ (opts->streaming_maxpacket % 1024) != 0) {
+ opts->streaming_maxpacket =
+ roundup(opts->streaming_maxpacket, 1024);
+ uvcg_info(f,
+ "overriding streaming_maxpacket to %d\n",
+ opts->streaming_maxpacket);
+ }
}
/*
@@ -677,37 +687,70 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
* NOTE: We assume that the user knows what they are doing and won't
* give parameters that their UDC doesn't support.
*/
- if (opts->streaming_maxpacket <= 1024) {
+ if (bulk) {
max_packet_mult = 1;
max_packet_size = opts->streaming_maxpacket;
- } else if (opts->streaming_maxpacket <= 2048) {
- max_packet_mult = 2;
- max_packet_size = opts->streaming_maxpacket / 2;
- } else {
- max_packet_mult = 3;
- max_packet_size = opts->streaming_maxpacket / 3;
- }
- uvc_fs_streaming_ep.wMaxPacketSize =
- cpu_to_le16(min(opts->streaming_maxpacket, 1023U));
- uvc_fs_streaming_ep.bInterval = opts->streaming_interval;
+ uvc_fs_streaming_ep.bmAttributes = USB_ENDPOINT_XFER_BULK;
+ uvc_hs_streaming_ep.bmAttributes = USB_ENDPOINT_XFER_BULK;
+ uvc_ss_streaming_ep.bmAttributes = USB_ENDPOINT_XFER_BULK;
- uvc_hs_streaming_ep.wMaxPacketSize =
- cpu_to_le16(max_packet_size | ((max_packet_mult - 1) << 11));
+ uvc_fs_streaming_ep.wMaxPacketSize =
+ cpu_to_le16(min(opts->streaming_maxpacket, 64U));
+ uvc_fs_streaming_ep.bInterval = 0;
- /* A high-bandwidth endpoint must specify a bInterval value of 1 */
- if (max_packet_mult > 1)
- uvc_hs_streaming_ep.bInterval = 1;
- else
- uvc_hs_streaming_ep.bInterval = opts->streaming_interval;
-
- uvc_ss_streaming_ep.wMaxPacketSize = cpu_to_le16(max_packet_size);
- uvc_ss_streaming_ep.bInterval = opts->streaming_interval;
- uvc_ss_streaming_comp.bmAttributes = max_packet_mult - 1;
- uvc_ss_streaming_comp.bMaxBurst = opts->streaming_maxburst;
- uvc_ss_streaming_comp.wBytesPerInterval =
- cpu_to_le16(max_packet_size * max_packet_mult *
- (opts->streaming_maxburst + 1));
+ uvc_hs_streaming_ep.wMaxPacketSize =
+ cpu_to_le16(min(opts->streaming_maxpacket, 512U));
+ uvc_hs_streaming_ep.bInterval = 0;
+
+ uvc_ss_streaming_ep.wMaxPacketSize =
+ cpu_to_le16(min(opts->streaming_maxpacket, 1024U));
+ uvc_ss_streaming_ep.bInterval = 0;
+ uvc_ss_streaming_comp.bmAttributes = 0;
+ uvc_ss_streaming_comp.bMaxBurst = opts->streaming_maxburst;
+ uvc_ss_streaming_comp.wBytesPerInterval = cpu_to_le16(0);
+ } else {
+ if (opts->streaming_maxpacket <= 1024) {
+ max_packet_mult = 1;
+ max_packet_size = opts->streaming_maxpacket;
+ } else if (opts->streaming_maxpacket <= 2048) {
+ max_packet_mult = 2;
+ max_packet_size = opts->streaming_maxpacket / 2;
+ } else {
+ max_packet_mult = 3;
+ max_packet_size = opts->streaming_maxpacket / 3;
+ }
+
+ uvc_fs_streaming_ep.bmAttributes =
+ USB_ENDPOINT_SYNC_ASYNC | USB_ENDPOINT_XFER_ISOC;
+ uvc_hs_streaming_ep.bmAttributes =
+ USB_ENDPOINT_SYNC_ASYNC | USB_ENDPOINT_XFER_ISOC;
+ uvc_ss_streaming_ep.bmAttributes =
+ USB_ENDPOINT_SYNC_ASYNC | USB_ENDPOINT_XFER_ISOC;
+
+ uvc_fs_streaming_ep.wMaxPacketSize =
+ cpu_to_le16(min(opts->streaming_maxpacket, 1023U));
+ uvc_fs_streaming_ep.bInterval = opts->streaming_interval;
+
+ uvc_hs_streaming_ep.wMaxPacketSize =
+ cpu_to_le16(max_packet_size |
+ ((max_packet_mult - 1) << 11));
+
+ /* A high-bandwidth endpoint must specify a bInterval value of 1 */
+ if (max_packet_mult > 1)
+ uvc_hs_streaming_ep.bInterval = 1;
+ else
+ uvc_hs_streaming_ep.bInterval = opts->streaming_interval;
+
+ uvc_ss_streaming_ep.wMaxPacketSize =
+ cpu_to_le16(max_packet_size);
+ uvc_ss_streaming_ep.bInterval = opts->streaming_interval;
+ uvc_ss_streaming_comp.bmAttributes = max_packet_mult - 1;
+ uvc_ss_streaming_comp.bMaxBurst = opts->streaming_maxburst;
+ uvc_ss_streaming_comp.wBytesPerInterval =
+ cpu_to_le16(max_packet_size * max_packet_mult *
+ (opts->streaming_maxburst + 1));
+ }
/* Allocate endpoints. */
if (opts->enable_interrupt_ep) {
diff --git a/drivers/usb/gadget/function/u_uvc.h b/drivers/usb/gadget/function/u_uvc.h
index 3ac392cbb779..b57e2d10ddcd 100644
--- a/drivers/usb/gadget/function/u_uvc.h
+++ b/drivers/usb/gadget/function/u_uvc.h
@@ -24,6 +24,7 @@ struct f_uvc_opts {
unsigned int streaming_interval;
unsigned int streaming_maxpacket;
unsigned int streaming_maxburst;
+ unsigned int streaming_bulk;
unsigned int control_interface;
unsigned int streaming_interface;
diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c
index a4a2d3dcb0d6..80817ff1b6fe 100644
--- a/drivers/usb/gadget/function/uvc_configfs.c
+++ b/drivers/usb/gadget/function/uvc_configfs.c
@@ -3751,6 +3751,7 @@ UVC_ATTR(f_uvc_opts_, cname, cname)
UVCG_OPTS_ATTR(streaming_interval, streaming_interval, 16);
UVCG_OPTS_ATTR(streaming_maxpacket, streaming_maxpacket, 3072);
UVCG_OPTS_ATTR(streaming_maxburst, streaming_maxburst, 15);
+UVCG_OPTS_ATTR(streaming_bulk, streaming_bulk, 1);
#undef UVCG_OPTS_ATTR
@@ -3800,6 +3801,7 @@ static struct configfs_attribute *uvc_attrs[] = {
&f_uvc_opts_attr_streaming_interval,
&f_uvc_opts_attr_streaming_maxpacket,
&f_uvc_opts_attr_streaming_maxburst,
+ &f_uvc_opts_attr_streaming_bulk,
&f_uvc_opts_string_attr_function_name,
NULL,
};

View File

@ -0,0 +1,47 @@
--- a/drivers/usb/gadget/function/uvc_video.c
+++ b/drivers/usb/gadget/function/uvc_video.c
@@
int uvcg_video_enable(struct uvc_video *video)
{
int ret;
+ if (!video) {
+ pr_err("uvcg_video_enable: missing video\n");
+ return -EINVAL;
+ }
+
+ if (!video->uvc || !video->uvc->func.config ||
+ !video->uvc->func.config->cdev) {
+ pr_err("uvcg_video_enable: missing uvc/func/config video=%p uvc=%p\n",
+ video, video->uvc);
+ return -ENODEV;
+ }
+
if (video->ep == NULL) {
uvcg_info(&video->uvc->func,
"Video enable failed, device is uninitialized.\n");
return -ENODEV;
}
+
+ if (!video->kworker || !video->async_wq) {
+ uvcg_err(&video->uvc->func,
+ "Video enable failed, missing worker(s) kworker=%p async_wq=%p\n",
+ video->kworker, video->async_wq);
+ return -EINVAL;
+ }
+
+ if (!video->queue.queue.dev) {
+ uvcg_err(&video->uvc->func,
+ "Video enable failed, missing queue device\n");
+ return -EINVAL;
+ }
+
+ uvcg_info(&video->uvc->func,
+ "Video enable start: video=%p ep=%p kworker=%p async_wq=%p req_size=%u max_payload=%u requests=%u reqs_per_frame=%u use_sg=%u flags=0x%x\n",
+ video, video->ep, video->kworker, video->async_wq,
+ video->req_size, video->max_payload_size,
+ video->uvc_num_requests, video->reqs_per_frame,
+ video->queue.use_sg, video->queue.flags);
/*
* Safe to access request related fields without req_lock because