[PATCH] media: uvcvideo: Add bandwidth_cap module param

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Many UVC devices report larger values for dwMaxPayloadTransferSize than
appear to be required. This results in less bandwidth available for
other devices.

This problem is commonly observed when attempting to stream from multiple
UVC cameras with the host controller returning -ENOSPC and sometimes a
warning (XHCI controllers: "Not enough bandwidth for new device state.").

For uncompressed video, the UVC_QUIRK_FIX_BANDWIDTH works around this issue
by overriding the device provided dwMaxPayloadTransferSize with a
calculation of the actual bandwidth requirements from the requested frame
size and rate. However for compressed video formats it's not practical to
estimate the bandwidth required as the kernel doesn't have enough
information.

Let's provide a pragmatic solution by allowing the user to impose an upper
threshold to the amount of bandwidth each UVC device can reserve. If the
parameter isn't used then no threshold is imposed.

Signed-off-by: Andrew Murray <amurray@xxxxxxxxxxxxxxxxxxxx>
---
 drivers/media/usb/uvc/uvc_driver.c | 3 +++
 drivers/media/usb/uvc/uvc_video.c  | 8 ++++++++
 drivers/media/usb/uvc/uvcvideo.h   | 1 +
 3 files changed, 12 insertions(+)

diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
index 431d86e1c94b..d5ecac7fc264 100644
--- a/drivers/media/usb/uvc/uvc_driver.c
+++ b/drivers/media/usb/uvc/uvc_driver.c
@@ -33,6 +33,7 @@ unsigned int uvc_no_drop_param;
 static unsigned int uvc_quirks_param = -1;
 unsigned int uvc_trace_param;
 unsigned int uvc_timeout_param = UVC_CTRL_STREAMING_TIMEOUT;
+unsigned int uvc_bandwidth_cap_param;
 
 /* ------------------------------------------------------------------------
  * Video formats
@@ -2389,6 +2390,8 @@ module_param_named(trace, uvc_trace_param, uint, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(trace, "Trace level bitmask");
 module_param_named(timeout, uvc_timeout_param, uint, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(timeout, "Streaming control requests timeout");
+module_param_named(bandwidth_cap, uvc_bandwidth_cap_param, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(bandwidth_cap, "Maximum bandwidth per device");
 
 /* ------------------------------------------------------------------------
  * Driver initialization and cleanup
diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c
index a65d5353a441..74a0dc0614cf 100644
--- a/drivers/media/usb/uvc/uvc_video.c
+++ b/drivers/media/usb/uvc/uvc_video.c
@@ -196,6 +196,14 @@ static void uvc_fixup_video_ctrl(struct uvc_streaming *stream,
 
 		ctrl->dwMaxPayloadTransferSize = bandwidth;
 	}
+
+	if (uvc_bandwidth_cap_param &&
+	    ctrl->dwMaxPayloadTransferSize > uvc_bandwidth_cap_param) {
+		uvc_trace(UVC_TRACE_VIDEO,
+			"Bandwidth capped from %u to %u B/frame.\n",
+			ctrl->dwMaxPayloadTransferSize, uvc_bandwidth_cap_param);
+		ctrl->dwMaxPayloadTransferSize = uvc_bandwidth_cap_param;
+	}
 }
 
 static size_t uvc_video_ctrl_size(struct uvc_streaming *stream)
diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
index 6ab972c643e3..c7d9220c9a7a 100644
--- a/drivers/media/usb/uvc/uvcvideo.h
+++ b/drivers/media/usb/uvc/uvcvideo.h
@@ -718,6 +718,7 @@ extern unsigned int uvc_no_drop_param;
 extern unsigned int uvc_trace_param;
 extern unsigned int uvc_timeout_param;
 extern unsigned int uvc_hw_timestamps_param;
+extern unsigned int uvc_bandwidth_cap_param;
 
 #define uvc_trace(flag, msg...) \
 	do { \
-- 
2.17.1




[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]

  Powered by Linux