Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

dmaengine: qcom_hidma: introduce memset support

HIDMA HW supports memset operation in addition to memcpy.
Since the memset API is present on the kernel now, bring the
memset feature into life.

The descriptor format is the same for both memcpy and memset.
Type of the descriptor is 4 when memset is requested.
The lowest 8 bits of the source DMA argument is used as a
fill pattern.

Signed-off-by: Sinan Kaya <okaya@codeaurora.org>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>

authored by

Sinan Kaya and committed by
Vinod Koul
5e2db086 5771a8c0

+46 -9
+36 -1
drivers/dma/qcom/hidma.c
··· 411 411 return NULL; 412 412 413 413 hidma_ll_set_transfer_params(mdma->lldev, mdesc->tre_ch, 414 - src, dest, len, flags); 414 + src, dest, len, flags, 415 + HIDMA_TRE_MEMCPY); 416 + 417 + /* Place descriptor in prepared list */ 418 + spin_lock_irqsave(&mchan->lock, irqflags); 419 + list_add_tail(&mdesc->node, &mchan->prepared); 420 + spin_unlock_irqrestore(&mchan->lock, irqflags); 421 + 422 + return &mdesc->desc; 423 + } 424 + 425 + static struct dma_async_tx_descriptor * 426 + hidma_prep_dma_memset(struct dma_chan *dmach, dma_addr_t dest, int value, 427 + size_t len, unsigned long flags) 428 + { 429 + struct hidma_chan *mchan = to_hidma_chan(dmach); 430 + struct hidma_desc *mdesc = NULL; 431 + struct hidma_dev *mdma = mchan->dmadev; 432 + unsigned long irqflags; 433 + 434 + /* Get free descriptor */ 435 + spin_lock_irqsave(&mchan->lock, irqflags); 436 + if (!list_empty(&mchan->free)) { 437 + mdesc = list_first_entry(&mchan->free, struct hidma_desc, node); 438 + list_del(&mdesc->node); 439 + } 440 + spin_unlock_irqrestore(&mchan->lock, irqflags); 441 + 442 + if (!mdesc) 443 + return NULL; 444 + 445 + hidma_ll_set_transfer_params(mdma->lldev, mdesc->tre_ch, 446 + value, dest, len, flags, 447 + HIDMA_TRE_MEMSET); 415 448 416 449 /* Place descriptor in prepared list */ 417 450 spin_lock_irqsave(&mchan->lock, irqflags); ··· 809 776 pm_runtime_get_sync(dmadev->ddev.dev); 810 777 811 778 dma_cap_set(DMA_MEMCPY, dmadev->ddev.cap_mask); 779 + dma_cap_set(DMA_MEMSET, dmadev->ddev.cap_mask); 812 780 if (WARN_ON(!pdev->dev.dma_mask)) { 813 781 rc = -ENXIO; 814 782 goto dmafree; ··· 820 786 dmadev->dev_trca = trca; 821 787 dmadev->trca_resource = trca_resource; 822 788 dmadev->ddev.device_prep_dma_memcpy = hidma_prep_dma_memcpy; 789 + dmadev->ddev.device_prep_dma_memset = hidma_prep_dma_memset; 823 790 dmadev->ddev.device_alloc_chan_resources = hidma_alloc_chan_resources; 824 791 dmadev->ddev.device_free_chan_resources = hidma_free_chan_resources; 825 792 dmadev->ddev.device_tx_status = hidma_tx_status;
+6 -1
drivers/dma/qcom/hidma.h
··· 28 28 #define HIDMA_TRE_DEST_LOW_IDX 4 29 29 #define HIDMA_TRE_DEST_HI_IDX 5 30 30 31 + enum tre_type { 32 + HIDMA_TRE_MEMCPY = 3, 33 + HIDMA_TRE_MEMSET = 4, 34 + }; 35 + 31 36 struct hidma_tre { 32 37 atomic_t allocated; /* if this channel is allocated */ 33 38 bool queued; /* flag whether this is pending */ ··· 155 150 int hidma_ll_disable(struct hidma_lldev *lldev); 156 151 int hidma_ll_enable(struct hidma_lldev *llhndl); 157 152 void hidma_ll_set_transfer_params(struct hidma_lldev *llhndl, u32 tre_ch, 158 - dma_addr_t src, dma_addr_t dest, u32 len, u32 flags); 153 + dma_addr_t src, dma_addr_t dest, u32 len, u32 flags, u32 txntype); 159 154 void hidma_ll_setup_irq(struct hidma_lldev *lldev, bool msi); 160 155 int hidma_ll_setup(struct hidma_lldev *lldev); 161 156 struct hidma_lldev *hidma_ll_init(struct device *dev, u32 max_channels,
+4 -7
drivers/dma/qcom/hidma_ll.c
··· 105 105 HIDMA_CH_STOPPED = 4, 106 106 }; 107 107 108 - enum tre_type { 109 - HIDMA_TRE_MEMCPY = 3, 110 - }; 111 - 112 108 enum err_code { 113 109 HIDMA_EVRE_STATUS_COMPLETE = 1, 114 110 HIDMA_EVRE_STATUS_ERROR = 4, ··· 170 174 tre->err_info = 0; 171 175 tre->lldev = lldev; 172 176 tre_local = &tre->tre_local[0]; 173 - tre_local[HIDMA_TRE_CFG_IDX] = HIDMA_TRE_MEMCPY; 174 - tre_local[HIDMA_TRE_CFG_IDX] |= (lldev->chidx & 0xFF) << 8; 177 + tre_local[HIDMA_TRE_CFG_IDX] = (lldev->chidx & 0xFF) << 8; 175 178 tre_local[HIDMA_TRE_CFG_IDX] |= BIT(16); /* set IEOB */ 176 179 *tre_ch = i; 177 180 if (callback) ··· 602 607 603 608 void hidma_ll_set_transfer_params(struct hidma_lldev *lldev, u32 tre_ch, 604 609 dma_addr_t src, dma_addr_t dest, u32 len, 605 - u32 flags) 610 + u32 flags, u32 txntype) 606 611 { 607 612 struct hidma_tre *tre; 608 613 u32 *tre_local; ··· 621 626 } 622 627 623 628 tre_local = &tre->tre_local[0]; 629 + tre_local[HIDMA_TRE_CFG_IDX] &= ~GENMASK(7, 0); 630 + tre_local[HIDMA_TRE_CFG_IDX] |= txntype; 624 631 tre_local[HIDMA_TRE_LEN_IDX] = len; 625 632 tre_local[HIDMA_TRE_SRC_LOW_IDX] = lower_32_bits(src); 626 633 tre_local[HIDMA_TRE_SRC_HI_IDX] = upper_32_bits(src);