RE: [PATCH] xhci: remove endpoint ring cache

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

 



Hi Mathias,

I have tested this patch with my platform and it works fine

Thanks,
Anurag Kumar Vulisha

>-----Original Message-----
>From: Mathias Nyman [mailto:mathias.nyman@xxxxxxxxxxxxxxx]
>Sent: Friday, June 02, 2017 4:51 PM
>To: Anurag Kumar Vulisha <anuragku@xxxxxxxxxx>
>Cc: gregkh@xxxxxxxxxxxxxxxxxxx; Anirudha Sarangi <anirudh@xxxxxxxxxx>;
>Anurag Kumar Vulisha <anuragku@xxxxxxxxxx>; linux-usb@xxxxxxxxxxxxxxx;
>Mathias Nyman <mathias.nyman@xxxxxxxxxxxxxxx>
>Subject: [PATCH] xhci: remove endpoint ring cache
>
>Having a properly working ring cache could ease a bit the memory
>reallocation, but this current implemetation isn't the correct way.
>It's faulty and hogs a lot of memory.
>
>A pool of cached rings that any device could use would be more useful,
>but xhci driver isn't there yet, just keeping the basic functionality
>working is already a handful.
>
>How about your case, does removing the cache work instead with your setup?
>
>8<-------
>
>Anurag Kumar Vulisha reported several issues with xhci endpoint
>ring caching.
>
>31 Rings are cached per device before a ring is freed.
>These cached rings are not used as default if a new ring is needed.
>They are only used if the drive fails to allocate memory for a ring.
>
>The current ring cache is more a reason to why we run out memry than a
>help when we actually do so.
>
>Anurag Kumar Vulisha tried to use cached rings as a first option and
>found new issues with cached ring initialization.
>Cached rings were first zeroed and then manually reinitialized with link
>rbs etc, but forgetting to set some important bits like cycle toggle bit.
>
>Remove the ring cache completely as it's a faulty premature optimization
>eating memory
>
>Reported-by: Anurag Kumar Vulisha <anuragku@xxxxxxxxxx>
>Signed-off-by: Mathias Nyman <mathias.nyman@xxxxxxxxxxxxxxx>
>---
> drivers/usb/host/xhci-mem.c | 81 ++++-----------------------------------------
> drivers/usb/host/xhci.c     | 17 +++++-----
> drivers/usb/host/xhci.h     |  6 +---
> 3 files changed, 15 insertions(+), 89 deletions(-)
>
>diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
>index 1f1687e..7c2501a 100644
>--- a/drivers/usb/host/xhci-mem.c
>+++ b/drivers/usb/host/xhci-mem.c
>@@ -407,64 +407,17 @@ static struct xhci_ring *xhci_ring_alloc(struct xhci_hcd
>*xhci,
> 	return NULL;
> }
>
>-void xhci_free_or_cache_endpoint_ring(struct xhci_hcd *xhci,
>+void xhci_free_endpoint_ring(struct xhci_hcd *xhci,
> 		struct xhci_virt_device *virt_dev,
> 		unsigned int ep_index)
> {
>-	int rings_cached;
>-
>-	rings_cached = virt_dev->num_rings_cached;
>-	if (rings_cached < XHCI_MAX_RINGS_CACHED) {
>-		virt_dev->ring_cache[rings_cached] =
>-			virt_dev->eps[ep_index].ring;
>-		virt_dev->num_rings_cached++;
>-		xhci_dbg(xhci, "Cached old ring, "
>-				"%d ring%s cached\n",
>-				virt_dev->num_rings_cached,
>-				(virt_dev->num_rings_cached > 1) ? "s" : "");
>-	} else {
>-		xhci_ring_free(xhci, virt_dev->eps[ep_index].ring);
>-		xhci_dbg(xhci, "Ring cache full (%d rings), "
>-				"freeing ring\n",
>-				virt_dev->num_rings_cached);
>-	}
>+	xhci_ring_free(xhci, virt_dev->eps[ep_index].ring);
> 	virt_dev->eps[ep_index].ring = NULL;
> }
>
>-/* Zero an endpoint ring (except for link TRBs) and move the enqueue and
>dequeue
>- * pointers to the beginning of the ring.
>- */
>-static void xhci_reinit_cached_ring(struct xhci_hcd *xhci,
>-			struct xhci_ring *ring, unsigned int cycle_state,
>-			enum xhci_ring_type type)
>-{
>-	struct xhci_segment	*seg = ring->first_seg;
>-	int i;
>-
>-	do {
>-		memset(seg->trbs, 0,
>-				sizeof(union xhci_trb)*TRBS_PER_SEGMENT);
>-		if (cycle_state == 0) {
>-			for (i = 0; i < TRBS_PER_SEGMENT; i++)
>-				seg->trbs[i].link.control |=
>-					cpu_to_le32(TRB_CYCLE);
>-		}
>-		/* All endpoint rings have link TRBs */
>-		xhci_link_segments(xhci, seg, seg->next, type);
>-		seg = seg->next;
>-	} while (seg != ring->first_seg);
>-	ring->type = type;
>-	xhci_initialize_ring_info(ring, cycle_state);
>-	/* td list should be empty since all URBs have been cancelled,
>-	 * but just in case...
>-	 */
>-	INIT_LIST_HEAD(&ring->td_list);
>-}
>-
> /*
>  * Expand an existing ring.
>- * Look for a cached ring or allocate a new ring which has same segment
>numbers
>- * and link the two rings.
>+ * Allocate a new ring which has same segment numbers and link the two rings.
>  */
> int xhci_ring_expansion(struct xhci_hcd *xhci, struct xhci_ring *ring,
> 				unsigned int num_trbs, gfp_t flags)
>@@ -968,12 +921,6 @@ void xhci_free_virt_device(struct xhci_hcd *xhci, int
>slot_id)
> 	/* If necessary, update the number of active TTs on this root port */
> 	xhci_update_tt_active_eps(xhci, dev, old_active_eps);
>
>-	if (dev->ring_cache) {
>-		for (i = 0; i < dev->num_rings_cached; i++)
>-			xhci_ring_free(xhci, dev->ring_cache[i]);
>-		kfree(dev->ring_cache);
>-	}
>-
> 	if (dev->in_ctx)
> 		xhci_free_container_ctx(xhci, dev->in_ctx);
> 	if (dev->out_ctx)
>@@ -1062,14 +1009,6 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int
>slot_id,
> 	if (!dev->eps[0].ring)
> 		goto fail;
>
>-	/* Allocate pointers to the ring cache */
>-	dev->ring_cache = kzalloc(
>-			sizeof(struct xhci_ring *)*XHCI_MAX_RINGS_CACHED,
>-			flags);
>-	if (!dev->ring_cache)
>-		goto fail;
>-	dev->num_rings_cached = 0;
>-
> 	dev->udev = udev;
>
> 	/* Point to output device context in dcbaa. */
>@@ -1537,17 +1476,9 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
> 	/* Set up the endpoint ring */
> 	virt_dev->eps[ep_index].new_ring =
> 		xhci_ring_alloc(xhci, 2, 1, ring_type, max_packet, mem_flags);
>-	if (!virt_dev->eps[ep_index].new_ring) {
>-		/* Attempt to use the ring cache */
>-		if (virt_dev->num_rings_cached == 0)
>-			return -ENOMEM;
>-		virt_dev->num_rings_cached--;
>-		virt_dev->eps[ep_index].new_ring =
>-			virt_dev->ring_cache[virt_dev->num_rings_cached];
>-		virt_dev->ring_cache[virt_dev->num_rings_cached] = NULL;
>-		xhci_reinit_cached_ring(xhci, virt_dev->eps[ep_index].new_ring,
>-					1, ring_type);
>-	}
>+	if (!virt_dev->eps[ep_index].new_ring)
>+		return -ENOMEM;
>+
> 	virt_dev->eps[ep_index].skip = false;
> 	ep_ring = virt_dev->eps[ep_index].new_ring;
>
>diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
>index 2d6a98c..ddeb943 100644
>--- a/drivers/usb/host/xhci.c
>+++ b/drivers/usb/host/xhci.c
>@@ -1695,8 +1695,7 @@ static int xhci_add_endpoint(struct usb_hcd *hcd,
>struct usb_device *udev,
> 	if (xhci->quirks & XHCI_MTK_HOST) {
> 		ret = xhci_mtk_add_ep_quirk(hcd, udev, ep);
> 		if (ret < 0) {
>-			xhci_free_or_cache_endpoint_ring(xhci,
>-				virt_dev, ep_index);
>+			xhci_free_endpoint_ring(xhci, virt_dev, ep_index);
> 			return ret;
> 		}
> 	}
>@@ -2720,23 +2719,23 @@ static int xhci_check_bandwidth(struct usb_hcd
>*hcd, struct usb_device *udev)
> 	for (i = 1; i < 31; i++) {
> 		if ((le32_to_cpu(ctrl_ctx->drop_flags) & (1 << (i + 1))) &&
> 		    !(le32_to_cpu(ctrl_ctx->add_flags) & (1 << (i + 1)))) {
>-			xhci_free_or_cache_endpoint_ring(xhci, virt_dev, i);
>+			xhci_free_endpoint_ring(xhci, virt_dev, i);
> 			xhci_check_bw_drop_ep_streams(xhci, virt_dev, i);
> 		}
> 	}
> 	xhci_zero_in_ctx(xhci, virt_dev);
> 	/*
> 	 * Install any rings for completely new endpoints or changed endpoints,
>-	 * and free or cache any old rings from changed endpoints.
>+	 * and free any old rings from changed endpoints.
> 	 */
> 	for (i = 1; i < 31; i++) {
> 		if (!virt_dev->eps[i].new_ring)
> 			continue;
>-		/* Only cache or free the old ring if it exists.
>+		/* Only free the old ring if it exists.
> 		 * It may not if this is the first add of an endpoint.
> 		 */
> 		if (virt_dev->eps[i].ring) {
>-			xhci_free_or_cache_endpoint_ring(xhci, virt_dev, i);
>+			xhci_free_endpoint_ring(xhci, virt_dev, i);
> 		}
> 		xhci_check_bw_drop_ep_streams(xhci, virt_dev, i);
> 		virt_dev->eps[i].ring = virt_dev->eps[i].new_ring;
>@@ -3336,7 +3335,7 @@ void xhci_free_device_endpoint_resources(struct
>xhci_hcd *xhci,
>  *
>  * Wait for the Reset Device command to finish.  Remove all structures
>  * associated with the endpoints that were disabled.  Clear the input device
>- * structure?  Cache the rings?  Reset the control endpoint 0 max packet size?
>+ * structure? Reset the control endpoint 0 max packet size?
>  *
>  * If the virt_dev to be reset does not exist or does not match the udev,
>  * it means the device is lost, possibly due to the xHC restore error and
>@@ -3466,7 +3465,7 @@ static int xhci_discover_or_reset_device(struct
>usb_hcd *hcd,
> 		spin_unlock_irqrestore(&xhci->lock, flags);
> 	}
>
>-	/* Everything but endpoint 0 is disabled, so free or cache the rings. */
>+	/* Everything but endpoint 0 is disabled, so free the rings. */
> 	last_freed_endpoint = 1;
> 	for (i = 1; i < 31; i++) {
> 		struct xhci_virt_ep *ep = &virt_dev->eps[i];
>@@ -3480,7 +3479,7 @@ static int xhci_discover_or_reset_device(struct
>usb_hcd *hcd,
> 		}
>
> 		if (ep->ring) {
>-			xhci_free_or_cache_endpoint_ring(xhci, virt_dev, i);
>+			xhci_free_endpoint_ring(xhci, virt_dev, i);
> 			last_freed_endpoint = i;
> 		}
> 		if (!list_empty(&virt_dev->eps[i].bw_endpoint_list))
>diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
>index 3ef9a8a..acd66f7 100644
>--- a/drivers/usb/host/xhci.h
>+++ b/drivers/usb/host/xhci.h
>@@ -992,10 +992,6 @@ struct xhci_virt_device {
> 	struct xhci_container_ctx       *out_ctx;
> 	/* Used for addressing devices and configuration changes */
> 	struct xhci_container_ctx       *in_ctx;
>-	/* Rings saved to ensure old alt settings can be re-instated */
>-	struct xhci_ring		**ring_cache;
>-	int				num_rings_cached;
>-#define	XHCI_MAX_RINGS_CACHED	31
> 	struct xhci_virt_ep		eps[31];
> 	u8				fake_port;
> 	u8				real_port;
>@@ -1965,7 +1961,7 @@ int xhci_endpoint_init(struct xhci_hcd *xhci, struct
>xhci_virt_device *virt_dev,
> void xhci_ring_free(struct xhci_hcd *xhci, struct xhci_ring *ring);
> int xhci_ring_expansion(struct xhci_hcd *xhci, struct xhci_ring *ring,
> 				unsigned int num_trbs, gfp_t flags);
>-void xhci_free_or_cache_endpoint_ring(struct xhci_hcd *xhci,
>+void xhci_free_endpoint_ring(struct xhci_hcd *xhci,
> 		struct xhci_virt_device *virt_dev,
> 		unsigned int ep_index);
> struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci,
>--
>1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




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

  Powered by Linux