aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/dma/ioat/dma.c
diff options
context:
space:
mode:
authorDan Williams <dan.j.williams@intel.com>2009-07-28 17:44:04 -0400
committerDan Williams <dan.j.williams@intel.com>2009-09-08 20:29:55 -0400
commita0587bcf3e64029a4da2a5666cad18df38db0d56 (patch)
tree475b3a2a7cd102f40d7c16fed431c227576c255a /drivers/dma/ioat/dma.c
parentc7984f4e4e3af3bf8027d636283ea8658c7f80b9 (diff)
ioat1: move descriptor allocation from submit to prep
The async_tx api assumes that after a successful ->prep a subsequent ->submit will not fail due to a lack of resources. This also fixes a bug in the allocation failure case. Previously the descriptors allocated prior to the allocation failure would not be returned to the free list. Signed-off-by: Maciej Sosnowski <maciej.sosnowski@intel.com> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Diffstat (limited to 'drivers/dma/ioat/dma.c')
-rw-r--r--drivers/dma/ioat/dma.c154
1 files changed, 65 insertions, 89 deletions
diff --git a/drivers/dma/ioat/dma.c b/drivers/dma/ioat/dma.c
index 4840d4805d8c..c4333be07608 100644
--- a/drivers/dma/ioat/dma.c
+++ b/drivers/dma/ioat/dma.c
@@ -420,95 +420,29 @@ static void ioat_dma_chan_watchdog(struct work_struct *work)
420static dma_cookie_t ioat1_tx_submit(struct dma_async_tx_descriptor *tx) 420static dma_cookie_t ioat1_tx_submit(struct dma_async_tx_descriptor *tx)
421{ 421{
422 struct ioat_dma_chan *ioat_chan = to_ioat_chan(tx->chan); 422 struct ioat_dma_chan *ioat_chan = to_ioat_chan(tx->chan);
423 struct ioat_desc_sw *first = tx_to_ioat_desc(tx); 423 struct ioat_desc_sw *desc = tx_to_ioat_desc(tx);
424 struct ioat_desc_sw *prev, *new; 424 struct ioat_desc_sw *first;
425 struct ioat_dma_descriptor *hw; 425 struct ioat_desc_sw *chain_tail;
426 dma_cookie_t cookie; 426 dma_cookie_t cookie;
427 LIST_HEAD(new_chain);
428 u32 copy;
429 size_t len;
430 dma_addr_t src, dst;
431 unsigned long orig_flags;
432 unsigned int desc_count = 0;
433
434 /* src and dest and len are stored in the initial descriptor */
435 len = first->len;
436 src = first->src;
437 dst = first->dst;
438 orig_flags = first->txd.flags;
439 new = first;
440 427
441 spin_lock_bh(&ioat_chan->desc_lock); 428 spin_lock_bh(&ioat_chan->desc_lock);
442 prev = to_ioat_desc(ioat_chan->used_desc.prev);
443 prefetch(prev->hw);
444 do {
445 copy = min_t(size_t, len, ioat_chan->xfercap);
446
447 async_tx_ack(&new->txd);
448
449 hw = new->hw;
450 hw->size = copy;
451 hw->ctl = 0;
452 hw->src_addr = src;
453 hw->dst_addr = dst;
454 hw->next = 0;
455
456 /* chain together the physical address list for the HW */
457 wmb();
458 prev->hw->next = (u64) new->txd.phys;
459
460 len -= copy;
461 dst += copy;
462 src += copy;
463
464 list_add_tail(&new->node, &new_chain);
465 desc_count++;
466 prev = new;
467 } while (len && (new = ioat1_dma_get_next_descriptor(ioat_chan)));
468
469 if (!new) {
470 dev_err(to_dev(ioat_chan), "tx submit failed\n");
471 spin_unlock_bh(&ioat_chan->desc_lock);
472 return -ENOMEM;
473 }
474
475 hw->ctl_f.compl_write = 1;
476 if (first->txd.callback) {
477 hw->ctl_f.int_en = 1;
478 if (first != new) {
479 /* move callback into to last desc */
480 new->txd.callback = first->txd.callback;
481 new->txd.callback_param
482 = first->txd.callback_param;
483 first->txd.callback = NULL;
484 first->txd.callback_param = NULL;
485 }
486 }
487
488 new->tx_cnt = desc_count;
489 new->txd.flags = orig_flags; /* client is in control of this ack */
490
491 /* store the original values for use in later cleanup */
492 if (new != first) {
493 new->src = first->src;
494 new->dst = first->dst;
495 new->len = first->len;
496 }
497
498 /* cookie incr and addition to used_list must be atomic */ 429 /* cookie incr and addition to used_list must be atomic */
499 cookie = ioat_chan->common.cookie; 430 cookie = ioat_chan->common.cookie;
500 cookie++; 431 cookie++;
501 if (cookie < 0) 432 if (cookie < 0)
502 cookie = 1; 433 cookie = 1;
503 ioat_chan->common.cookie = new->txd.cookie = cookie; 434 ioat_chan->common.cookie = tx->cookie = cookie;
504 435
505 /* write address into NextDescriptor field of last desc in chain */ 436 /* write address into NextDescriptor field of last desc in chain */
506 to_ioat_desc(ioat_chan->used_desc.prev)->hw->next = 437 first = to_ioat_desc(tx->tx_list.next);
507 first->txd.phys; 438 chain_tail = to_ioat_desc(ioat_chan->used_desc.prev);
508 list_splice_tail(&new_chain, &ioat_chan->used_desc); 439 /* make descriptor updates globally visible before chaining */
509 440 wmb();
510 ioat_chan->dmacount += desc_count; 441 chain_tail->hw->next = first->txd.phys;
511 ioat_chan->pending += desc_count; 442 list_splice_tail_init(&tx->tx_list, &ioat_chan->used_desc);
443
444 ioat_chan->dmacount += desc->tx_cnt;
445 ioat_chan->pending += desc->tx_cnt;
512 if (ioat_chan->pending >= ioat_pending_level) 446 if (ioat_chan->pending >= ioat_pending_level)
513 __ioat1_dma_memcpy_issue_pending(ioat_chan); 447 __ioat1_dma_memcpy_issue_pending(ioat_chan);
514 spin_unlock_bh(&ioat_chan->desc_lock); 448 spin_unlock_bh(&ioat_chan->desc_lock);
@@ -937,24 +871,66 @@ ioat1_dma_prep_memcpy(struct dma_chan *chan, dma_addr_t dma_dest,
937 dma_addr_t dma_src, size_t len, unsigned long flags) 871 dma_addr_t dma_src, size_t len, unsigned long flags)
938{ 872{
939 struct ioat_dma_chan *ioat_chan = to_ioat_chan(chan); 873 struct ioat_dma_chan *ioat_chan = to_ioat_chan(chan);
940 struct ioat_desc_sw *new; 874 struct ioat_desc_sw *desc;
875 size_t copy;
876 LIST_HEAD(chain);
877 dma_addr_t src = dma_src;
878 dma_addr_t dest = dma_dest;
879 size_t total_len = len;
880 struct ioat_dma_descriptor *hw = NULL;
881 int tx_cnt = 0;
941 882
942 spin_lock_bh(&ioat_chan->desc_lock); 883 spin_lock_bh(&ioat_chan->desc_lock);
943 new = ioat_dma_get_next_descriptor(ioat_chan); 884 desc = ioat_dma_get_next_descriptor(ioat_chan);
944 spin_unlock_bh(&ioat_chan->desc_lock); 885 do {
886 if (!desc)
887 break;
945 888
946 if (new) { 889 tx_cnt++;
947 new->len = len; 890 copy = min_t(size_t, len, ioat_chan->xfercap);
948 new->dst = dma_dest; 891
949 new->src = dma_src; 892 hw = desc->hw;
950 new->txd.flags = flags; 893 hw->size = copy;
951 return &new->txd; 894 hw->ctl = 0;
952 } else { 895 hw->src_addr = src;
896 hw->dst_addr = dest;
897
898 list_add_tail(&desc->node, &chain);
899
900 len -= copy;
901 dest += copy;
902 src += copy;
903 if (len) {
904 struct ioat_desc_sw *next;
905
906 async_tx_ack(&desc->txd);
907 next = ioat_dma_get_next_descriptor(ioat_chan);
908 hw->next = next ? next->txd.phys : 0;
909 desc = next;
910 } else
911 hw->next = 0;
912 } while (len);
913
914 if (!desc) {
953 dev_err(to_dev(ioat_chan), 915 dev_err(to_dev(ioat_chan),
954 "chan%d - get_next_desc failed: %d descs waiting, %d total desc\n", 916 "chan%d - get_next_desc failed: %d descs waiting, %d total desc\n",
955 chan_num(ioat_chan), ioat_chan->dmacount, ioat_chan->desccount); 917 chan_num(ioat_chan), ioat_chan->dmacount, ioat_chan->desccount);
918 list_splice(&chain, &ioat_chan->free_desc);
919 spin_unlock_bh(&ioat_chan->desc_lock);
956 return NULL; 920 return NULL;
957 } 921 }
922 spin_unlock_bh(&ioat_chan->desc_lock);
923
924 desc->txd.flags = flags;
925 desc->tx_cnt = tx_cnt;
926 desc->src = dma_src;
927 desc->dst = dma_dest;
928 desc->len = total_len;
929 list_splice(&chain, &desc->txd.tx_list);
930 hw->ctl_f.int_en = !!(flags & DMA_PREP_INTERRUPT);
931 hw->ctl_f.compl_write = 1;
932
933 return &desc->txd;
958} 934}
959 935
960static struct dma_async_tx_descriptor * 936static struct dma_async_tx_descriptor *