powerpc/hvsi: Fix endianness issues in the HVSI driver
[firefly-linux-kernel-4.4.55.git] / drivers / dma / mv_xor.c
index 669d0b5029d1c09b7df52aa160cd6cf9ea61c160..fbaf1ead25971542ca81acd9f7ddc14161acf340 100644 (file)
@@ -88,12 +88,6 @@ static void mv_desc_set_next_desc(struct mv_xor_desc_slot *desc,
        hw_desc->phy_next_desc = next_desc_addr;
 }
 
-static void mv_desc_clear_next_desc(struct mv_xor_desc_slot *desc)
-{
-       struct mv_xor_desc *hw_desc = desc->hw_desc;
-       hw_desc->phy_next_desc = 0;
-}
-
 static void mv_desc_set_src_addr(struct mv_xor_desc_slot *desc,
                                 int index, dma_addr_t addr)
 {
@@ -213,21 +207,6 @@ static char mv_chan_is_busy(struct mv_xor_chan *chan)
        return (state == 1) ? 1 : 0;
 }
 
-/**
- * mv_chan_free_slots - flags descriptor slots for reuse
- * @slot: Slot to free
- * Caller must hold &mv_chan->lock while calling this function
- */
-static void mv_chan_free_slots(struct mv_xor_chan *mv_chan,
-                              struct mv_xor_desc_slot *slot)
-{
-       dev_dbg(mv_chan_to_devp(mv_chan), "%s %d slot %p\n",
-               __func__, __LINE__, slot);
-
-       slot->slot_used = 0;
-
-}
-
 /*
  * mv_chan_start_new_chain - program the engine to operate on new
  * chain headed by sw_desc
@@ -279,12 +258,10 @@ mv_chan_clean_completed_slots(struct mv_xor_chan *mv_chan)
 
        dev_dbg(mv_chan_to_devp(mv_chan), "%s %d\n", __func__, __LINE__);
        list_for_each_entry_safe(iter, _iter, &mv_chan->completed_slots,
-                                completed_node) {
+                                node) {
 
-               if (async_tx_test_ack(&iter->async_tx)) {
-                       list_del(&iter->completed_node);
-                       mv_chan_free_slots(mv_chan, iter);
-               }
+               if (async_tx_test_ack(&iter->async_tx))
+                       list_move_tail(&iter->node, &mv_chan->free_slots);
        }
        return 0;
 }
@@ -295,17 +272,16 @@ mv_desc_clean_slot(struct mv_xor_desc_slot *desc,
 {
        dev_dbg(mv_chan_to_devp(mv_chan), "%s %d: desc %p flags %d\n",
                __func__, __LINE__, desc, desc->async_tx.flags);
-       list_del(&desc->chain_node);
+
        /* the client is allowed to attach dependent operations
         * until 'ack' is set
         */
-       if (!async_tx_test_ack(&desc->async_tx)) {
+       if (!async_tx_test_ack(&desc->async_tx))
                /* move this slot to the completed_slots */
-               list_add_tail(&desc->completed_node, &mv_chan->completed_slots);
-               return 0;
-       }
+               list_move_tail(&desc->node, &mv_chan->completed_slots);
+       else
+               list_move_tail(&desc->node, &mv_chan->free_slots);
 
-       mv_chan_free_slots(mv_chan, desc);
        return 0;
 }
 
@@ -328,7 +304,7 @@ static void mv_chan_slot_cleanup(struct mv_xor_chan *mv_chan)
         */
 
        list_for_each_entry_safe(iter, _iter, &mv_chan->chain,
-                                       chain_node) {
+                                node) {
 
                /* clean finished descriptors */
                hw_desc = iter->hw_desc;
@@ -360,17 +336,17 @@ static void mv_chan_slot_cleanup(struct mv_xor_chan *mv_chan)
                         */
                        iter = list_entry(mv_chan->chain.next,
                                          struct mv_xor_desc_slot,
-                                         chain_node);
+                                         node);
                        mv_chan_start_new_chain(mv_chan, iter);
                } else {
-                       if (!list_is_last(&iter->chain_node, &mv_chan->chain)) {
+                       if (!list_is_last(&iter->node, &mv_chan->chain)) {
                                /*
                                 * descriptors are still waiting after
                                 * current, trigger them
                                 */
-                               iter = list_entry(iter->chain_node.next,
+                               iter = list_entry(iter->node.next,
                                                  struct mv_xor_desc_slot,
-                                                 chain_node);
+                                                 node);
                                mv_chan_start_new_chain(mv_chan, iter);
                        } else {
                                /*
@@ -398,49 +374,28 @@ static void mv_xor_tasklet(unsigned long data)
 static struct mv_xor_desc_slot *
 mv_chan_alloc_slot(struct mv_xor_chan *mv_chan)
 {
-       struct mv_xor_desc_slot *iter, *_iter;
-       int retry = 0;
+       struct mv_xor_desc_slot *iter;
 
-       /* start search from the last allocated descrtiptor
-        * if a contiguous allocation can not be found start searching
-        * from the beginning of the list
-        */
-retry:
-       if (retry == 0)
-               iter = mv_chan->last_used;
-       else
-               iter = list_entry(&mv_chan->all_slots,
-                       struct mv_xor_desc_slot,
-                       slot_node);
-
-       list_for_each_entry_safe_continue(
-               iter, _iter, &mv_chan->all_slots, slot_node) {
-
-               prefetch(_iter);
-               prefetch(&_iter->async_tx);
-               if (iter->slot_used) {
-                       /* give up after finding the first busy slot
-                        * on the second pass through the list
-                        */
-                       if (retry)
-                               break;
-                       continue;
-               }
+       spin_lock_bh(&mv_chan->lock);
+
+       if (!list_empty(&mv_chan->free_slots)) {
+               iter = list_first_entry(&mv_chan->free_slots,
+                                       struct mv_xor_desc_slot,
+                                       node);
+
+               list_move_tail(&iter->node, &mv_chan->allocated_slots);
+
+               spin_unlock_bh(&mv_chan->lock);
 
                /* pre-ack descriptor */
                async_tx_ack(&iter->async_tx);
-
-               iter->slot_used = 1;
-               INIT_LIST_HEAD(&iter->chain_node);
                iter->async_tx.cookie = -EBUSY;
-               mv_chan->last_used = iter;
-               mv_desc_clear_next_desc(iter);
 
                return iter;
 
        }
-       if (!retry++)
-               goto retry;
+
+       spin_unlock_bh(&mv_chan->lock);
 
        /* try to free some slots if the allocation fails */
        tasklet_schedule(&mv_chan->irq_tasklet);
@@ -466,14 +421,14 @@ mv_xor_tx_submit(struct dma_async_tx_descriptor *tx)
        cookie = dma_cookie_assign(tx);
 
        if (list_empty(&mv_chan->chain))
-               list_add_tail(&sw_desc->chain_node, &mv_chan->chain);
+               list_move_tail(&sw_desc->node, &mv_chan->chain);
        else {
                new_hw_chain = 0;
 
                old_chain_tail = list_entry(mv_chan->chain.prev,
                                            struct mv_xor_desc_slot,
-                                           chain_node);
-               list_add_tail(&sw_desc->chain_node, &mv_chan->chain);
+                                           node);
+               list_move_tail(&sw_desc->node, &mv_chan->chain);
 
                dev_dbg(mv_chan_to_devp(mv_chan), "Append to last desc %pa\n",
                        &old_chain_tail->async_tx.phys);
@@ -526,26 +481,20 @@ static int mv_xor_alloc_chan_resources(struct dma_chan *chan)
 
                dma_async_tx_descriptor_init(&slot->async_tx, chan);
                slot->async_tx.tx_submit = mv_xor_tx_submit;
-               INIT_LIST_HEAD(&slot->chain_node);
-               INIT_LIST_HEAD(&slot->slot_node);
+               INIT_LIST_HEAD(&slot->node);
                dma_desc = mv_chan->dma_desc_pool;
                slot->async_tx.phys = dma_desc + idx * MV_XOR_SLOT_SIZE;
                slot->idx = idx++;
 
                spin_lock_bh(&mv_chan->lock);
                mv_chan->slots_allocated = idx;
-               list_add_tail(&slot->slot_node, &mv_chan->all_slots);
+               list_add_tail(&slot->node, &mv_chan->free_slots);
                spin_unlock_bh(&mv_chan->lock);
        }
 
-       if (mv_chan->slots_allocated && !mv_chan->last_used)
-               mv_chan->last_used = list_entry(mv_chan->all_slots.next,
-                                       struct mv_xor_desc_slot,
-                                       slot_node);
-
        dev_dbg(mv_chan_to_devp(mv_chan),
-               "allocated %d descriptor slots last_used: %p\n",
-               mv_chan->slots_allocated, mv_chan->last_used);
+               "allocated %d descriptor slots\n",
+               mv_chan->slots_allocated);
 
        return mv_chan->slots_allocated ? : -ENOMEM;
 }
@@ -566,7 +515,6 @@ mv_xor_prep_dma_xor(struct dma_chan *chan, dma_addr_t dest, dma_addr_t *src,
                "%s src_cnt: %d len: %u dest %pad flags: %ld\n",
                __func__, src_cnt, len, &dest, flags);
 
-       spin_lock_bh(&mv_chan->lock);
        sw_desc = mv_chan_alloc_slot(mv_chan);
        if (sw_desc) {
                sw_desc->type = DMA_XOR;
@@ -577,7 +525,7 @@ mv_xor_prep_dma_xor(struct dma_chan *chan, dma_addr_t dest, dma_addr_t *src,
                while (src_cnt--)
                        mv_desc_set_src_addr(sw_desc, src_cnt, src[src_cnt]);
        }
-       spin_unlock_bh(&mv_chan->lock);
+
        dev_dbg(mv_chan_to_devp(mv_chan),
                "%s sw_desc %p async_tx %p \n",
                __func__, sw_desc, &sw_desc->async_tx);
@@ -624,22 +572,26 @@ static void mv_xor_free_chan_resources(struct dma_chan *chan)
        mv_chan_slot_cleanup(mv_chan);
 
        list_for_each_entry_safe(iter, _iter, &mv_chan->chain,
-                                       chain_node) {
+                                       node) {
                in_use_descs++;
-               list_del(&iter->chain_node);
+               list_move_tail(&iter->node, &mv_chan->free_slots);
        }
        list_for_each_entry_safe(iter, _iter, &mv_chan->completed_slots,
-                                completed_node) {
+                                node) {
+               in_use_descs++;
+               list_move_tail(&iter->node, &mv_chan->free_slots);
+       }
+       list_for_each_entry_safe(iter, _iter, &mv_chan->allocated_slots,
+                                node) {
                in_use_descs++;
-               list_del(&iter->completed_node);
+               list_move_tail(&iter->node, &mv_chan->free_slots);
        }
        list_for_each_entry_safe_reverse(
-               iter, _iter, &mv_chan->all_slots, slot_node) {
-               list_del(&iter->slot_node);
+               iter, _iter, &mv_chan->free_slots, node) {
+               list_del(&iter->node);
                kfree(iter);
                mv_chan->slots_allocated--;
        }
-       mv_chan->last_used = NULL;
 
        dev_dbg(mv_chan_to_devp(mv_chan), "%s slots_allocated %d\n",
                __func__, mv_chan->slots_allocated);
@@ -1097,7 +1049,8 @@ mv_xor_channel_add(struct mv_xor_device *xordev,
        spin_lock_init(&mv_chan->lock);
        INIT_LIST_HEAD(&mv_chan->chain);
        INIT_LIST_HEAD(&mv_chan->completed_slots);
-       INIT_LIST_HEAD(&mv_chan->all_slots);
+       INIT_LIST_HEAD(&mv_chan->free_slots);
+       INIT_LIST_HEAD(&mv_chan->allocated_slots);
        mv_chan->dmachan.device = dma_dev;
        dma_cookie_init(&mv_chan->dmachan);