Re: [PATCH] UAS: fallback to storage if no streams are available

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

 



On Wed, 2014-02-05 at 22:08 +0100, Hans de Goede wrote:
> Hi Oliver,
> 
> On 02/05/2014 09:13 PM, oliver@xxxxxxxxxx wrote:
> > From: Oliver Neukum <oneukum@xxxxxxx>
> >
> > uas_probe() calls usb_alloc_streams(). That can fail on XHCI
> > with -ENOSYS if the controller doesn't support streams. In that
> > case devices should be handed over to storage. Thus the driver
> > needs to return -ENODEV so that the driver core will give other
> > drivers a chance.
> 
> I'm afraid that that won't work, it won't change the result of
> uas_use_uas_driver() so usb-storage still will fail to bind.
> 
> I'm not sure which version you're looking at, but the new
> re-enabled uas code as it will be going upstream for 3.15 is here:
> http://git.linuxtv.org/hgoede/gspca.git/shortlog/refs/heads/usb-next-for-sarah
> 
> For the above specifically see:
> http://git.linuxtv.org/hgoede/gspca.git/commitdiff/dda9e7db4e293defeff4956018183e06749528dc
> 
> So to fix this we would need to export if an hcd supports streams
> with some hcd flag / property and then as_use_uas_driver() can
> check this flag (in combination with connection speed).

Hi,

something like this?

	Regards
		Oliver

>From c04c3cf3a15162bae22e8dcc74dbf9449e822b56 Mon Sep 17 00:00:00 2001
From: Oliver Neukum <oneukum@xxxxxxx>
Date: Fri, 7 Feb 2014 10:57:44 +0100
Subject: [PATCH] USB:query streams support

This adds a method to query HCDs for their support for streams
and uses this in the storage driver to take devices which UAS
rejects due to a lack of streams support. This allows UAS devices
to work as storage devices with old XHCI chips.

Signed-off-by: Oliver Neukum <oliver@xxxxxxxxxx>
---
 drivers/usb/core/hcd.c           | 14 ++++++++++++++
 drivers/usb/host/xhci-pci.c      |  1 +
 drivers/usb/host/xhci-plat.c     |  1 +
 drivers/usb/host/xhci.c          |  7 +++++++
 drivers/usb/host/xhci.h          |  1 +
 drivers/usb/storage/uas-detect.h | 13 +++++++++++++
 include/linux/usb.h              |  4 ++++
 include/linux/usb/hcd.h          |  2 ++
 8 files changed, 43 insertions(+)

diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 9c4e292..efc16f0 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -2027,6 +2027,20 @@ void usb_hcd_reset_endpoint(struct usb_device *udev,
 			usb_settoggle(udev, epnum, !is_out, 0);
 	}
 }
+/**
+ * usb_query_stream_support - query whether a HC supports streams
+ * @hcd:		HC to query
+ *
+ * Return: 1 for support; 0 for no support
+ */
+int usb_query_stream_support(struct usb_hcd *hcd)
+{
+	if (!hcd->driver->query_streams)
+		return 0;
+	else
+		return hcd->driver->query_streams(hcd);
+}
+EXPORT_SYMBOL_GPL(usb_query_stream_support);
 
 /**
  * usb_alloc_streams - allocate bulk endpoint stream IDs.
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index 04f986d..f9f770d 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -334,6 +334,7 @@ static const struct hc_driver xhci_pci_hc_driver = {
 	.alloc_dev =		xhci_alloc_dev,
 	.free_dev =		xhci_free_dev,
 	.alloc_streams =	xhci_alloc_streams,
+	.query_streams =	xhci_query_streams,
 	.free_streams =		xhci_free_streams,
 	.add_endpoint =		xhci_add_endpoint,
 	.drop_endpoint =	xhci_drop_endpoint,
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
index 8abda5c..3d96517 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -62,6 +62,7 @@ static const struct hc_driver xhci_plat_xhci_driver = {
 	.alloc_dev =		xhci_alloc_dev,
 	.free_dev =		xhci_free_dev,
 	.alloc_streams =	xhci_alloc_streams,
+	.query_streams =	xhci_query_streams,
 	.free_streams =		xhci_free_streams,
 	.add_endpoint =		xhci_add_endpoint,
 	.drop_endpoint =	xhci_drop_endpoint,
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 1f15830..f77b29e 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -3267,6 +3267,13 @@ cleanup:
 	return -ENOMEM;
 }
 
+int xhci_query_streams(struct usb_hcd *hcd)
+{
+	struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+
+	return HCC_MAX_PSA(xhci->hcc_params) >= 4;
+}
+
 /* Transition the endpoint from using streams to being a "normal" endpoint
  * without streams.
  *
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 08d669c..8c449e7 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1707,6 +1707,7 @@ void xhci_free_or_cache_endpoint_ring(struct xhci_hcd *xhci,
 struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci,
 		unsigned int num_stream_ctxs,
 		unsigned int num_streams, gfp_t flags);
+int xhci_query_streams(struct usb_hcd *hcd);
 void xhci_free_stream_info(struct xhci_hcd *xhci,
 		struct xhci_stream_info *stream_info);
 void xhci_setup_streams_ep_input_ctx(struct xhci_hcd *xhci,
diff --git a/drivers/usb/storage/uas-detect.h b/drivers/usb/storage/uas-detect.h
index b8a02e1..73a4478 100644
--- a/drivers/usb/storage/uas-detect.h
+++ b/drivers/usb/storage/uas-detect.h
@@ -9,6 +9,13 @@ static int uas_is_interface(struct usb_host_interface *intf)
 		intf->desc.bInterfaceProtocol == USB_PR_UAS);
 }
 
+static int uas_find_streams(struct usb_device *udev)
+{
+	struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+
+	return usb_query_stream_support(hcd) ? 0 : -ENODEV;
+}
+
 static int uas_isnt_supported(struct usb_device *udev)
 {
 	struct usb_hcd *hcd = bus_to_hcd(udev->bus);
@@ -80,6 +87,12 @@ static int uas_use_uas_driver(struct usb_interface *intf,
 	if (flags & US_FL_IGNORE_UAS)
 		return 0;
 
+	if (udev->speed >= USB_SPEED_SUPER) {
+		r = uas_find_streams(udev);
+		if (r < 0)
+			return 0;
+	}
+
 	alt = uas_find_uas_alt_setting(intf);
 	if (alt < 0)
 		return 0;
diff --git a/include/linux/usb.h b/include/linux/usb.h
index e644923..f435113 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -25,6 +25,7 @@
 struct usb_device;
 struct usb_driver;
 struct wusb_dev;
+struct usb_hcd;
 
 /*-------------------------------------------------------------------------*/
 
@@ -707,6 +708,9 @@ extern int usb_alloc_streams(struct usb_interface *interface,
 		struct usb_host_endpoint **eps, unsigned int num_eps,
 		unsigned int num_streams, gfp_t mem_flags);
 
+/* Can a HC support streams for a given device */
+extern int usb_query_stream_support(struct usb_hcd *hcd);
+
 /* Reverts a group of bulk endpoints back to not using stream IDs. */
 extern int usb_free_streams(struct usb_interface *interface,
 		struct usb_host_endpoint **eps, unsigned int num_eps,
diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
index efe8d8a..6a12152 100644
--- a/include/linux/usb/hcd.h
+++ b/include/linux/usb/hcd.h
@@ -310,6 +310,8 @@ struct hc_driver {
 	int	(*alloc_dev)(struct usb_hcd *, struct usb_device *);
 		/* Called by usb_disconnect to free HC device structures */
 	void	(*free_dev)(struct usb_hcd *, struct usb_device *);
+	/* query for stream support */
+	int	(*query_streams) (struct usb_hcd *hcd);
 	/* Change a group of bulk endpoints to support multiple stream IDs */
 	int	(*alloc_streams)(struct usb_hcd *hcd, struct usb_device *udev,
 		struct usb_host_endpoint **eps, unsigned int num_eps,
-- 
1.8.4


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux