| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * DMA driver for Xilinx ZynqMP DMA Engine |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright (C) 2016 Xilinx, Inc. All rights reserved. |
|---|
| 5 | | - * |
|---|
| 6 | | - * This program is free software: you can redistribute it and/or modify |
|---|
| 7 | | - * it under the terms of the GNU General Public License as published by |
|---|
| 8 | | - * the Free Software Foundation, either version 2 of the License, or |
|---|
| 9 | | - * (at your option) any later version. |
|---|
| 10 | 6 | */ |
|---|
| 11 | 7 | |
|---|
| 12 | 8 | #include <linux/bitops.h> |
|---|
| .. | .. |
|---|
| 236 | 232 | bool is_dmacoherent; |
|---|
| 237 | 233 | struct tasklet_struct tasklet; |
|---|
| 238 | 234 | bool idle; |
|---|
| 239 | | - u32 desc_size; |
|---|
| 235 | + size_t desc_size; |
|---|
| 240 | 236 | bool err; |
|---|
| 241 | 237 | u32 bus_width; |
|---|
| 242 | 238 | u32 src_burst_len; |
|---|
| .. | .. |
|---|
| 377 | 373 | struct zynqmp_dma_chan *chan = to_chan(tx->chan); |
|---|
| 378 | 374 | struct zynqmp_dma_desc_sw *desc, *new; |
|---|
| 379 | 375 | dma_cookie_t cookie; |
|---|
| 376 | + unsigned long irqflags; |
|---|
| 380 | 377 | |
|---|
| 381 | 378 | new = tx_to_desc(tx); |
|---|
| 382 | | - spin_lock_bh(&chan->lock); |
|---|
| 379 | + spin_lock_irqsave(&chan->lock, irqflags); |
|---|
| 383 | 380 | cookie = dma_cookie_assign(tx); |
|---|
| 384 | 381 | |
|---|
| 385 | 382 | if (!list_empty(&chan->pending_list)) { |
|---|
| .. | .. |
|---|
| 395 | 392 | } |
|---|
| 396 | 393 | |
|---|
| 397 | 394 | list_add_tail(&new->node, &chan->pending_list); |
|---|
| 398 | | - spin_unlock_bh(&chan->lock); |
|---|
| 395 | + spin_unlock_irqrestore(&chan->lock, irqflags); |
|---|
| 399 | 396 | |
|---|
| 400 | 397 | return cookie; |
|---|
| 401 | 398 | } |
|---|
| .. | .. |
|---|
| 410 | 407 | zynqmp_dma_get_descriptor(struct zynqmp_dma_chan *chan) |
|---|
| 411 | 408 | { |
|---|
| 412 | 409 | struct zynqmp_dma_desc_sw *desc; |
|---|
| 410 | + unsigned long irqflags; |
|---|
| 413 | 411 | |
|---|
| 414 | | - spin_lock_bh(&chan->lock); |
|---|
| 412 | + spin_lock_irqsave(&chan->lock, irqflags); |
|---|
| 415 | 413 | desc = list_first_entry(&chan->free_list, |
|---|
| 416 | 414 | struct zynqmp_dma_desc_sw, node); |
|---|
| 417 | 415 | list_del(&desc->node); |
|---|
| 418 | | - spin_unlock_bh(&chan->lock); |
|---|
| 416 | + spin_unlock_irqrestore(&chan->lock, irqflags); |
|---|
| 419 | 417 | |
|---|
| 420 | 418 | INIT_LIST_HEAD(&desc->tx_list); |
|---|
| 421 | 419 | /* Clear the src and dst descriptor memory */ |
|---|
| .. | .. |
|---|
| 436 | 434 | struct zynqmp_dma_desc_sw *child, *next; |
|---|
| 437 | 435 | |
|---|
| 438 | 436 | chan->desc_free_cnt++; |
|---|
| 437 | + list_del(&sdesc->node); |
|---|
| 439 | 438 | list_add_tail(&sdesc->node, &chan->free_list); |
|---|
| 440 | 439 | list_for_each_entry_safe(child, next, &sdesc->tx_list, node) { |
|---|
| 441 | 440 | chan->desc_free_cnt++; |
|---|
| .. | .. |
|---|
| 469 | 468 | struct zynqmp_dma_desc_sw *desc; |
|---|
| 470 | 469 | int i, ret; |
|---|
| 471 | 470 | |
|---|
| 472 | | - ret = pm_runtime_get_sync(chan->dev); |
|---|
| 471 | + ret = pm_runtime_resume_and_get(chan->dev); |
|---|
| 473 | 472 | if (ret < 0) |
|---|
| 474 | 473 | return ret; |
|---|
| 475 | 474 | |
|---|
| .. | .. |
|---|
| 490 | 489 | list_add_tail(&desc->node, &chan->free_list); |
|---|
| 491 | 490 | } |
|---|
| 492 | 491 | |
|---|
| 493 | | - chan->desc_pool_v = dma_zalloc_coherent(chan->dev, |
|---|
| 494 | | - (2 * chan->desc_size * ZYNQMP_DMA_NUM_DESCS), |
|---|
| 495 | | - &chan->desc_pool_p, GFP_KERNEL); |
|---|
| 492 | + chan->desc_pool_v = dma_alloc_coherent(chan->dev, |
|---|
| 493 | + (2 * ZYNQMP_DMA_DESC_SIZE(chan) * |
|---|
| 494 | + ZYNQMP_DMA_NUM_DESCS), |
|---|
| 495 | + &chan->desc_pool_p, GFP_KERNEL); |
|---|
| 496 | 496 | if (!chan->desc_pool_v) |
|---|
| 497 | 497 | return -ENOMEM; |
|---|
| 498 | 498 | |
|---|
| .. | .. |
|---|
| 610 | 610 | dma_async_tx_callback callback; |
|---|
| 611 | 611 | void *callback_param; |
|---|
| 612 | 612 | |
|---|
| 613 | | - list_del(&desc->node); |
|---|
| 614 | | - |
|---|
| 615 | 613 | callback = desc->async_tx.callback; |
|---|
| 616 | 614 | callback_param = desc->async_tx.callback_param; |
|---|
| 617 | 615 | if (callback) { |
|---|
| .. | .. |
|---|
| 649 | 647 | static void zynqmp_dma_issue_pending(struct dma_chan *dchan) |
|---|
| 650 | 648 | { |
|---|
| 651 | 649 | struct zynqmp_dma_chan *chan = to_chan(dchan); |
|---|
| 650 | + unsigned long irqflags; |
|---|
| 652 | 651 | |
|---|
| 653 | | - spin_lock_bh(&chan->lock); |
|---|
| 652 | + spin_lock_irqsave(&chan->lock, irqflags); |
|---|
| 654 | 653 | zynqmp_dma_start_transfer(chan); |
|---|
| 655 | | - spin_unlock_bh(&chan->lock); |
|---|
| 654 | + spin_unlock_irqrestore(&chan->lock, irqflags); |
|---|
| 656 | 655 | } |
|---|
| 657 | 656 | |
|---|
| 658 | 657 | /** |
|---|
| .. | .. |
|---|
| 673 | 672 | static void zynqmp_dma_free_chan_resources(struct dma_chan *dchan) |
|---|
| 674 | 673 | { |
|---|
| 675 | 674 | struct zynqmp_dma_chan *chan = to_chan(dchan); |
|---|
| 675 | + unsigned long irqflags; |
|---|
| 676 | 676 | |
|---|
| 677 | | - spin_lock_bh(&chan->lock); |
|---|
| 677 | + spin_lock_irqsave(&chan->lock, irqflags); |
|---|
| 678 | 678 | zynqmp_dma_free_descriptors(chan); |
|---|
| 679 | | - spin_unlock_bh(&chan->lock); |
|---|
| 679 | + spin_unlock_irqrestore(&chan->lock, irqflags); |
|---|
| 680 | 680 | dma_free_coherent(chan->dev, |
|---|
| 681 | 681 | (2 * ZYNQMP_DMA_DESC_SIZE(chan) * ZYNQMP_DMA_NUM_DESCS), |
|---|
| 682 | 682 | chan->desc_pool_v, chan->desc_pool_p); |
|---|
| .. | .. |
|---|
| 743 | 743 | |
|---|
| 744 | 744 | /** |
|---|
| 745 | 745 | * zynqmp_dma_do_tasklet - Schedule completion tasklet |
|---|
| 746 | | - * @data: Pointer to the ZynqMP DMA channel structure |
|---|
| 746 | + * @t: Pointer to the ZynqMP DMA channel structure |
|---|
| 747 | 747 | */ |
|---|
| 748 | | -static void zynqmp_dma_do_tasklet(unsigned long data) |
|---|
| 748 | +static void zynqmp_dma_do_tasklet(struct tasklet_struct *t) |
|---|
| 749 | 749 | { |
|---|
| 750 | | - struct zynqmp_dma_chan *chan = (struct zynqmp_dma_chan *)data; |
|---|
| 750 | + struct zynqmp_dma_chan *chan = from_tasklet(chan, t, tasklet); |
|---|
| 751 | 751 | u32 count; |
|---|
| 752 | + unsigned long irqflags; |
|---|
| 752 | 753 | |
|---|
| 753 | | - spin_lock(&chan->lock); |
|---|
| 754 | + spin_lock_irqsave(&chan->lock, irqflags); |
|---|
| 754 | 755 | |
|---|
| 755 | 756 | if (chan->err) { |
|---|
| 756 | 757 | zynqmp_dma_reset(chan); |
|---|
| .. | .. |
|---|
| 770 | 771 | zynqmp_dma_start_transfer(chan); |
|---|
| 771 | 772 | |
|---|
| 772 | 773 | unlock: |
|---|
| 773 | | - spin_unlock(&chan->lock); |
|---|
| 774 | + spin_unlock_irqrestore(&chan->lock, irqflags); |
|---|
| 774 | 775 | } |
|---|
| 775 | 776 | |
|---|
| 776 | 777 | /** |
|---|
| .. | .. |
|---|
| 782 | 783 | static int zynqmp_dma_device_terminate_all(struct dma_chan *dchan) |
|---|
| 783 | 784 | { |
|---|
| 784 | 785 | struct zynqmp_dma_chan *chan = to_chan(dchan); |
|---|
| 786 | + unsigned long irqflags; |
|---|
| 785 | 787 | |
|---|
| 786 | | - spin_lock_bh(&chan->lock); |
|---|
| 788 | + spin_lock_irqsave(&chan->lock, irqflags); |
|---|
| 787 | 789 | writel(ZYNQMP_DMA_IDS_DEFAULT_MASK, chan->regs + ZYNQMP_DMA_IDS); |
|---|
| 788 | 790 | zynqmp_dma_free_descriptors(chan); |
|---|
| 789 | | - spin_unlock_bh(&chan->lock); |
|---|
| 791 | + spin_unlock_irqrestore(&chan->lock, irqflags); |
|---|
| 790 | 792 | |
|---|
| 791 | 793 | return 0; |
|---|
| 792 | 794 | } |
|---|
| .. | .. |
|---|
| 810 | 812 | void *desc = NULL, *prev = NULL; |
|---|
| 811 | 813 | size_t copy; |
|---|
| 812 | 814 | u32 desc_cnt; |
|---|
| 815 | + unsigned long irqflags; |
|---|
| 813 | 816 | |
|---|
| 814 | 817 | chan = to_chan(dchan); |
|---|
| 815 | 818 | |
|---|
| 816 | 819 | desc_cnt = DIV_ROUND_UP(len, ZYNQMP_DMA_MAX_TRANS_LEN); |
|---|
| 817 | 820 | |
|---|
| 818 | | - spin_lock_bh(&chan->lock); |
|---|
| 821 | + spin_lock_irqsave(&chan->lock, irqflags); |
|---|
| 819 | 822 | if (desc_cnt > chan->desc_free_cnt) { |
|---|
| 820 | | - spin_unlock_bh(&chan->lock); |
|---|
| 823 | + spin_unlock_irqrestore(&chan->lock, irqflags); |
|---|
| 821 | 824 | dev_dbg(chan->dev, "chan %p descs are not available\n", chan); |
|---|
| 822 | 825 | return NULL; |
|---|
| 823 | 826 | } |
|---|
| 824 | 827 | chan->desc_free_cnt = chan->desc_free_cnt - desc_cnt; |
|---|
| 825 | | - spin_unlock_bh(&chan->lock); |
|---|
| 828 | + spin_unlock_irqrestore(&chan->lock, irqflags); |
|---|
| 826 | 829 | |
|---|
| 827 | 830 | do { |
|---|
| 828 | 831 | /* Allocate and populate the descriptor */ |
|---|
| .. | .. |
|---|
| 906 | 909 | |
|---|
| 907 | 910 | chan->is_dmacoherent = of_property_read_bool(node, "dma-coherent"); |
|---|
| 908 | 911 | zdev->chan = chan; |
|---|
| 909 | | - tasklet_init(&chan->tasklet, zynqmp_dma_do_tasklet, (ulong)chan); |
|---|
| 912 | + tasklet_setup(&chan->tasklet, zynqmp_dma_do_tasklet); |
|---|
| 910 | 913 | spin_lock_init(&chan->lock); |
|---|
| 911 | 914 | INIT_LIST_HEAD(&chan->active_list); |
|---|
| 912 | 915 | INIT_LIST_HEAD(&chan->pending_list); |
|---|