usb: wusbcore: set pointers to NULL after freeing in error cases
[platform/adaptation/renesas_rcar/renesas_kernel.git] / drivers / usb / wusbcore / wa-xfer.c
index d2c7b2b..0b27146 100644 (file)
@@ -520,6 +520,10 @@ static void wa_seg_dto_cb(struct urb *urb)
        unsigned rpipe_ready = 0;
        u8 done = 0;
 
+       /* free the sg if it was used. */
+       kfree(urb->sg);
+       urb->sg = NULL;
+
        switch (urb->status) {
        case 0:
                spin_lock_irqsave(&xfer->lock, flags);
@@ -635,9 +639,11 @@ static void wa_seg_tr_cb(struct urb *urb)
        }
 }
 
-/* allocate an SG list to store bytes_to_transfer bytes and copy the
+/*
+ * Allocate an SG list to store bytes_to_transfer bytes and copy the
  * subset of the in_sg that matches the buffer subset
- * we are about to transfer. */
+ * we are about to transfer.
+ */
 static struct scatterlist *wa_xfer_create_subset_sg(struct scatterlist *in_sg,
        const unsigned int bytes_transferred,
        const unsigned int bytes_to_transfer, unsigned int *out_num_sgs)
@@ -716,6 +722,55 @@ static struct scatterlist *wa_xfer_create_subset_sg(struct scatterlist *in_sg,
 }
 
 /*
+ * Populate buffer ptr and size, DMA buffer or SG list for the dto urb.
+ */
+static int __wa_populate_dto_urb(struct wa_xfer *xfer,
+       struct wa_seg *seg, size_t buf_itr_offset, size_t buf_itr_size)
+{
+       int result = 0;
+
+       if (xfer->is_dma) {
+               seg->dto_urb->transfer_dma =
+                       xfer->urb->transfer_dma + buf_itr_offset;
+               seg->dto_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+               seg->dto_urb->sg = NULL;
+               seg->dto_urb->num_sgs = 0;
+       } else {
+               /* do buffer or SG processing. */
+               seg->dto_urb->transfer_flags &=
+                       ~URB_NO_TRANSFER_DMA_MAP;
+               /* this should always be 0 before a resubmit. */
+               seg->dto_urb->num_mapped_sgs = 0;
+
+               if (xfer->urb->transfer_buffer) {
+                       seg->dto_urb->transfer_buffer =
+                               xfer->urb->transfer_buffer +
+                               buf_itr_offset;
+                       seg->dto_urb->sg = NULL;
+                       seg->dto_urb->num_sgs = 0;
+               } else {
+                       seg->dto_urb->transfer_buffer = NULL;
+
+                       /*
+                        * allocate an SG list to store seg_size bytes
+                        * and copy the subset of the xfer->urb->sg that
+                        * matches the buffer subset we are about to
+                        * read.
+                        */
+                       seg->dto_urb->sg = wa_xfer_create_subset_sg(
+                               xfer->urb->sg,
+                               buf_itr_offset, buf_itr_size,
+                               &(seg->dto_urb->num_sgs));
+                       if (!(seg->dto_urb->sg))
+                               result = -ENOMEM;
+               }
+       }
+       seg->dto_urb->transfer_buffer_length = buf_itr_size;
+
+       return result;
+}
+
+/*
  * Allocate the segs array and initialize each of them
  *
  * The segments are freed by wa_xfer_destroy() when the xfer use count
@@ -762,48 +817,13 @@ static int __wa_xfer_setup_segs(struct wa_xfer *xfer, size_t xfer_hdr_size)
                                usb_sndbulkpipe(usb_dev,
                                                dto_epd->bEndpointAddress),
                                NULL, 0, wa_seg_dto_cb, seg);
-                       if (xfer->is_dma) {
-                               seg->dto_urb->transfer_dma =
-                                       xfer->urb->transfer_dma + buf_itr;
-                               seg->dto_urb->transfer_flags |=
-                                       URB_NO_TRANSFER_DMA_MAP;
-                               seg->dto_urb->transfer_buffer = NULL;
-                               seg->dto_urb->sg = NULL;
-                               seg->dto_urb->num_sgs = 0;
-                       } else {
-                               /* do buffer or SG processing. */
-                               seg->dto_urb->transfer_flags &=
-                                       ~URB_NO_TRANSFER_DMA_MAP;
-                               /* this should always be 0 before a resubmit. */
-                               seg->dto_urb->num_mapped_sgs = 0;
-
-                               if (xfer->urb->transfer_buffer) {
-                                       seg->dto_urb->transfer_buffer =
-                                               xfer->urb->transfer_buffer +
-                                               buf_itr;
-                                       seg->dto_urb->sg = NULL;
-                                       seg->dto_urb->num_sgs = 0;
-                               } else {
-                                       /* allocate an SG list to store seg_size
-                                           bytes and copy the subset of the
-                                           xfer->urb->sg that matches the
-                                           buffer subset we are about to read.
-                                       */
-                                       seg->dto_urb->sg =
-                                               wa_xfer_create_subset_sg(
-                                               xfer->urb->sg,
-                                               buf_itr, buf_itr_size,
-                                               &(seg->dto_urb->num_sgs));
-
-                                       if (!(seg->dto_urb->sg)) {
-                                               seg->dto_urb->num_sgs   = 0;
-                                               goto error_sg_alloc;
-                                       }
-
-                                       seg->dto_urb->transfer_buffer = NULL;
-                               }
-                       }
-                       seg->dto_urb->transfer_buffer_length = buf_itr_size;
+
+                       /* fill in the xfer buffer information. */
+                       result = __wa_populate_dto_urb(xfer, seg,
+                                               buf_itr, buf_itr_size);
+
+                       if (result < 0)
+                               goto error_seg_outbound_populate;
                }
                seg->status = WA_SEG_READY;
                buf_itr += buf_itr_size;
@@ -811,20 +831,17 @@ static int __wa_xfer_setup_segs(struct wa_xfer *xfer, size_t xfer_hdr_size)
        }
        return 0;
 
-error_sg_alloc:
+       /*
+        * Free the memory for the current segment which failed to init.
+        * Use the fact that cnt is left at were it failed.  The remaining
+        * segments will be cleaned up by wa_xfer_destroy.
+        */
+error_seg_outbound_populate:
        usb_free_urb(xfer->seg[cnt]->dto_urb);
 error_dto_alloc:
        kfree(xfer->seg[cnt]);
-       cnt--;
+       xfer->seg[cnt] = NULL;
 error_seg_kmalloc:
-       /* use the fact that cnt is left at were it failed */
-       for (; cnt >= 0; cnt--) {
-               if (xfer->seg[cnt] && xfer->is_inbound == 0) {
-                       usb_free_urb(xfer->seg[cnt]->dto_urb);
-                       kfree(xfer->seg[cnt]->dto_urb->sg);
-               }
-               kfree(xfer->seg[cnt]);
-       }
 error_segs_kzalloc:
        return result;
 }
@@ -1543,6 +1560,7 @@ error_submit_buf_in:
                        xfer, seg_idx, result);
        seg->result = result;
        kfree(wa->buf_in_urb->sg);
+       wa->buf_in_urb->sg = NULL;
 error_sg_alloc:
        __wa_xfer_abort(xfer);
 error_complete:
@@ -1842,6 +1860,7 @@ out:
 
 error_dti_urb_submit:
        usb_put_urb(wa->buf_in_urb);
+       wa->buf_in_urb = NULL;
 error_buf_in_urb_alloc:
        usb_put_urb(wa->dti_urb);
        wa->dti_urb = NULL;