Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux...
[firefly-linux-kernel-4.4.55.git] / drivers / usb / host / xhci-mem.c
index bce4391a0e7d708873180ab40f3ef17737f148a1..c089668308ad181fa68a02e9f80d80440612fa7f 100644 (file)
@@ -149,14 +149,140 @@ static void xhci_link_rings(struct xhci_hcd *xhci, struct xhci_ring *ring,
        }
 }
 
+/*
+ * We need a radix tree for mapping physical addresses of TRBs to which stream
+ * ID they belong to.  We need to do this because the host controller won't tell
+ * us which stream ring the TRB came from.  We could store the stream ID in an
+ * event data TRB, but that doesn't help us for the cancellation case, since the
+ * endpoint may stop before it reaches that event data TRB.
+ *
+ * The radix tree maps the upper portion of the TRB DMA address to a ring
+ * segment that has the same upper portion of DMA addresses.  For example, say I
+ * have segments of size 1KB, that are always 1KB aligned.  A segment may
+ * start at 0x10c91000 and end at 0x10c913f0.  If I use the upper 10 bits, the
+ * key to the stream ID is 0x43244.  I can use the DMA address of the TRB to
+ * pass the radix tree a key to get the right stream ID:
+ *
+ *     0x10c90fff >> 10 = 0x43243
+ *     0x10c912c0 >> 10 = 0x43244
+ *     0x10c91400 >> 10 = 0x43245
+ *
+ * Obviously, only those TRBs with DMA addresses that are within the segment
+ * will make the radix tree return the stream ID for that ring.
+ *
+ * Caveats for the radix tree:
+ *
+ * The radix tree uses an unsigned long as a key pair.  On 32-bit systems, an
+ * unsigned long will be 32-bits; on a 64-bit system an unsigned long will be
+ * 64-bits.  Since we only request 32-bit DMA addresses, we can use that as the
+ * key on 32-bit or 64-bit systems (it would also be fine if we asked for 64-bit
+ * PCI DMA addresses on a 64-bit system).  There might be a problem on 32-bit
+ * extended systems (where the DMA address can be bigger than 32-bits),
+ * if we allow the PCI dma mask to be bigger than 32-bits.  So don't do that.
+ */
+static int xhci_insert_segment_mapping(struct radix_tree_root *trb_address_map,
+               struct xhci_ring *ring,
+               struct xhci_segment *seg,
+               gfp_t mem_flags)
+{
+       unsigned long key;
+       int ret;
+
+       key = (unsigned long)(seg->dma >> TRB_SEGMENT_SHIFT);
+       /* Skip any segments that were already added. */
+       if (radix_tree_lookup(trb_address_map, key))
+               return 0;
+
+       ret = radix_tree_maybe_preload(mem_flags);
+       if (ret)
+               return ret;
+       ret = radix_tree_insert(trb_address_map,
+                       key, ring);
+       radix_tree_preload_end();
+       return ret;
+}
+
+static void xhci_remove_segment_mapping(struct radix_tree_root *trb_address_map,
+               struct xhci_segment *seg)
+{
+       unsigned long key;
+
+       key = (unsigned long)(seg->dma >> TRB_SEGMENT_SHIFT);
+       if (radix_tree_lookup(trb_address_map, key))
+               radix_tree_delete(trb_address_map, key);
+}
+
+static int xhci_update_stream_segment_mapping(
+               struct radix_tree_root *trb_address_map,
+               struct xhci_ring *ring,
+               struct xhci_segment *first_seg,
+               struct xhci_segment *last_seg,
+               gfp_t mem_flags)
+{
+       struct xhci_segment *seg;
+       struct xhci_segment *failed_seg;
+       int ret;
+
+       if (WARN_ON_ONCE(trb_address_map == NULL))
+               return 0;
+
+       seg = first_seg;
+       do {
+               ret = xhci_insert_segment_mapping(trb_address_map,
+                               ring, seg, mem_flags);
+               if (ret)
+                       goto remove_streams;
+               if (seg == last_seg)
+                       return 0;
+               seg = seg->next;
+       } while (seg != first_seg);
+
+       return 0;
+
+remove_streams:
+       failed_seg = seg;
+       seg = first_seg;
+       do {
+               xhci_remove_segment_mapping(trb_address_map, seg);
+               if (seg == failed_seg)
+                       return ret;
+               seg = seg->next;
+       } while (seg != first_seg);
+
+       return ret;
+}
+
+static void xhci_remove_stream_mapping(struct xhci_ring *ring)
+{
+       struct xhci_segment *seg;
+
+       if (WARN_ON_ONCE(ring->trb_address_map == NULL))
+               return;
+
+       seg = ring->first_seg;
+       do {
+               xhci_remove_segment_mapping(ring->trb_address_map, seg);
+               seg = seg->next;
+       } while (seg != ring->first_seg);
+}
+
+static int xhci_update_stream_mapping(struct xhci_ring *ring, gfp_t mem_flags)
+{
+       return xhci_update_stream_segment_mapping(ring->trb_address_map, ring,
+                       ring->first_seg, ring->last_seg, mem_flags);
+}
+
 /* XXX: Do we need the hcd structure in all these functions? */
 void xhci_ring_free(struct xhci_hcd *xhci, struct xhci_ring *ring)
 {
        if (!ring)
                return;
 
-       if (ring->first_seg)
+       if (ring->first_seg) {
+               if (ring->type == TYPE_STREAM)
+                       xhci_remove_stream_mapping(ring);
                xhci_free_segments_for_ring(xhci, ring->first_seg);
+       }
 
        kfree(ring);
 }
@@ -349,6 +475,21 @@ int xhci_ring_expansion(struct xhci_hcd *xhci, struct xhci_ring *ring,
        if (ret)
                return -ENOMEM;
 
+       if (ring->type == TYPE_STREAM)
+               ret = xhci_update_stream_segment_mapping(ring->trb_address_map,
+                                               ring, first, last, flags);
+       if (ret) {
+               struct xhci_segment *next;
+               do {
+                       next = first->next;
+                       xhci_segment_free(xhci, first);
+                       if (first == last)
+                               break;
+                       first = next;
+               } while (true);
+               return ret;
+       }
+
        xhci_link_rings(xhci, ring, first, last, num_segs);
        xhci_dbg_trace(xhci, trace_xhci_dbg_ring_expansion,
                        "ring expansion succeed, now has %d segments",
@@ -434,12 +575,12 @@ static void xhci_free_stream_ctx(struct xhci_hcd *xhci,
                struct xhci_stream_ctx *stream_ctx, dma_addr_t dma)
 {
        struct device *dev = xhci_to_hcd(xhci)->self.controller;
+       size_t size = sizeof(struct xhci_stream_ctx) * num_stream_ctxs;
 
-       if (num_stream_ctxs > MEDIUM_STREAM_ARRAY_SIZE)
-               dma_free_coherent(dev,
-                               sizeof(struct xhci_stream_ctx)*num_stream_ctxs,
+       if (size > MEDIUM_STREAM_ARRAY_SIZE)
+               dma_free_coherent(dev, size,
                                stream_ctx, dma);
-       else if (num_stream_ctxs <= SMALL_STREAM_ARRAY_SIZE)
+       else if (size <= SMALL_STREAM_ARRAY_SIZE)
                return dma_pool_free(xhci->small_streams_pool,
                                stream_ctx, dma);
        else
@@ -462,12 +603,12 @@ static struct xhci_stream_ctx *xhci_alloc_stream_ctx(struct xhci_hcd *xhci,
                gfp_t mem_flags)
 {
        struct device *dev = xhci_to_hcd(xhci)->self.controller;
+       size_t size = sizeof(struct xhci_stream_ctx) * num_stream_ctxs;
 
-       if (num_stream_ctxs > MEDIUM_STREAM_ARRAY_SIZE)
-               return dma_alloc_coherent(dev,
-                               sizeof(struct xhci_stream_ctx)*num_stream_ctxs,
+       if (size > MEDIUM_STREAM_ARRAY_SIZE)
+               return dma_alloc_coherent(dev, size,
                                dma, mem_flags);
-       else if (num_stream_ctxs <= SMALL_STREAM_ARRAY_SIZE)
+       else if (size <= SMALL_STREAM_ARRAY_SIZE)
                return dma_pool_alloc(xhci->small_streams_pool,
                                mem_flags, dma);
        else
@@ -510,36 +651,6 @@ struct xhci_ring *xhci_stream_id_to_ring(
  * The number of stream contexts in the stream context array may be bigger than
  * the number of streams the driver wants to use.  This is because the number of
  * stream context array entries must be a power of two.
- *
- * We need a radix tree for mapping physical addresses of TRBs to which stream
- * ID they belong to.  We need to do this because the host controller won't tell
- * us which stream ring the TRB came from.  We could store the stream ID in an
- * event data TRB, but that doesn't help us for the cancellation case, since the
- * endpoint may stop before it reaches that event data TRB.
- *
- * The radix tree maps the upper portion of the TRB DMA address to a ring
- * segment that has the same upper portion of DMA addresses.  For example, say I
- * have segments of size 1KB, that are always 64-byte aligned.  A segment may
- * start at 0x10c91000 and end at 0x10c913f0.  If I use the upper 10 bits, the
- * key to the stream ID is 0x43244.  I can use the DMA address of the TRB to
- * pass the radix tree a key to get the right stream ID:
- *
- *     0x10c90fff >> 10 = 0x43243
- *     0x10c912c0 >> 10 = 0x43244
- *     0x10c91400 >> 10 = 0x43245
- *
- * Obviously, only those TRBs with DMA addresses that are within the segment
- * will make the radix tree return the stream ID for that ring.
- *
- * Caveats for the radix tree:
- *
- * The radix tree uses an unsigned long as a key pair.  On 32-bit systems, an
- * unsigned long will be 32-bits; on a 64-bit system an unsigned long will be
- * 64-bits.  Since we only request 32-bit DMA addresses, we can use that as the
- * key on 32-bit or 64-bit systems (it would also be fine if we asked for 64-bit
- * PCI DMA addresses on a 64-bit system).  There might be a problem on 32-bit
- * extended systems (where the DMA address can be bigger than 32-bits),
- * if we allow the PCI dma mask to be bigger than 32-bits.  So don't do that.
  */
 struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci,
                unsigned int num_stream_ctxs,
@@ -548,7 +659,6 @@ struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci,
        struct xhci_stream_info *stream_info;
        u32 cur_stream;
        struct xhci_ring *cur_ring;
-       unsigned long key;
        u64 addr;
        int ret;
 
@@ -603,6 +713,7 @@ struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci,
                if (!cur_ring)
                        goto cleanup_rings;
                cur_ring->stream_id = cur_stream;
+               cur_ring->trb_address_map = &stream_info->trb_address_map;
                /* Set deq ptr, cycle bit, and stream context type */
                addr = cur_ring->first_seg->dma |
                        SCT_FOR_CTX(SCT_PRI_TR) |
@@ -612,10 +723,7 @@ struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci,
                xhci_dbg(xhci, "Setting stream %d ring ptr to 0x%08llx\n",
                                cur_stream, (unsigned long long) addr);
 
-               key = (unsigned long)
-                       (cur_ring->first_seg->dma >> TRB_SEGMENT_SHIFT);
-               ret = radix_tree_insert(&stream_info->trb_address_map,
-                               key, cur_ring);
+               ret = xhci_update_stream_mapping(cur_ring, mem_flags);
                if (ret) {
                        xhci_ring_free(xhci, cur_ring);
                        stream_info->stream_rings[cur_stream] = NULL;
@@ -635,9 +743,6 @@ cleanup_rings:
        for (cur_stream = 1; cur_stream < num_streams; cur_stream++) {
                cur_ring = stream_info->stream_rings[cur_stream];
                if (cur_ring) {
-                       addr = cur_ring->first_seg->dma;
-                       radix_tree_delete(&stream_info->trb_address_map,
-                                       addr >> TRB_SEGMENT_SHIFT);
                        xhci_ring_free(xhci, cur_ring);
                        stream_info->stream_rings[cur_stream] = NULL;
                }
@@ -698,7 +803,6 @@ void xhci_free_stream_info(struct xhci_hcd *xhci,
 {
        int cur_stream;
        struct xhci_ring *cur_ring;
-       dma_addr_t addr;
 
        if (!stream_info)
                return;
@@ -707,9 +811,6 @@ void xhci_free_stream_info(struct xhci_hcd *xhci,
                        cur_stream++) {
                cur_ring = stream_info->stream_rings[cur_stream];
                if (cur_ring) {
-                       addr = cur_ring->first_seg->dma;
-                       radix_tree_delete(&stream_info->trb_address_map,
-                                       addr >> TRB_SEGMENT_SHIFT);
                        xhci_ring_free(xhci, cur_ring);
                        stream_info->stream_rings[cur_stream] = NULL;
                }
@@ -1711,7 +1812,6 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
 
        if (xhci->lpm_command)
                xhci_free_command(xhci, xhci->lpm_command);
-       xhci->cmd_ring_reserved_trbs = 0;
        if (xhci->cmd_ring)
                xhci_ring_free(xhci, xhci->cmd_ring);
        xhci->cmd_ring = NULL;
@@ -1776,6 +1876,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
        }
 
 no_bw:
+       xhci->cmd_ring_reserved_trbs = 0;
        xhci->num_usb2_ports = 0;
        xhci->num_usb3_ports = 0;
        xhci->num_active_eps = 0;
@@ -2274,11 +2375,12 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
        /*
         * Initialize the ring segment pool.  The ring must be a contiguous
         * structure comprised of TRBs.  The TRBs must be 16 byte aligned,
-        * however, the command ring segment needs 64-byte aligned segments,
-        * so we pick the greater alignment need.
+        * however, the command ring segment needs 64-byte aligned segments
+        * and our use of dma addresses in the trb_address_map radix tree needs
+        * TRB_SEGMENT_SIZE alignment, so we pick the greater alignment need.
         */
        xhci->segment_pool = dma_pool_create("xHCI ring segments", dev,
-                       TRB_SEGMENT_SIZE, 64, xhci->page_size);
+                       TRB_SEGMENT_SIZE, TRB_SEGMENT_SIZE, xhci->page_size);
 
        /* See Table 46 and Note on Figure 55 */
        xhci->device_pool = dma_pool_create("xHCI input/output contexts", dev,