From: Ravi Kumar V <hidden> Date: 2012-01-06 12:47:50
Following are the changes we have done from the previous
v1 posted here: https://lkml.org/lkml/2011/12/22/148
As our ADM Scatter-gather hardware needs
-32-bit command configuration parameter
apart from
-32-bit source address
-32-bit destination address
-16-bit length
So,we have added new parameter in struct scatterlist to support xfer descriptor
specific private data, and for supporting ADM Box mode DMA we added new
API and data structure.
Ravi Kumar V (2):
dmaengine: Add support for per xfer specific privatedata & box dma
msm: DMAEngine: Add DMAEngine driver based on old MSM DMA APIs
arch/arm/mach-msm/include/mach/dma.h | 33 ++
drivers/dma/Kconfig | 12 +
drivers/dma/Makefile | 1 +
drivers/dma/msm-dma.c | 764 ++++++++++++++++++++++++++++++++++
include/asm-generic/scatterlist.h | 1 +
include/linux/dmaengine.h | 17 +-
6 files changed, 827 insertions(+), 1 deletions(-)
create mode 100644 drivers/dma/msm-dma.c
--
Sent by a consultant of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
From: Ravi Kumar V <hidden> Date: 2012-01-06 12:48:12
Qualcomm MSM have a feature to pass command configuration and
control data along with source,destination and length of transfer
for every transaction, as of now struct scatterlist has no support
to send private data related to each transaction we added private_data
variable for supporting this type of archictures.
Qualcomm MSM also supports BOX mode of dma, currently as there is no
API in dmaengine to support this type of dma we added new API.
Change-Id: Ia9ee19f2c253e68b8e5ff254a57478dcc51014ca
Signed-off-by: Ravi Kumar V <redacted>
---
include/asm-generic/scatterlist.h | 1 +
include/linux/dmaengine.h | 17 ++++++++++++++++-
2 files changed, 17 insertions(+), 1 deletions(-)
@@ -72,10 +72,11 @@ enum dma_transaction_type {DMA_ASYNC_TX,DMA_SLAVE,DMA_CYCLIC,+DMA_BOX,};/* last transaction type for creation of the capabilities mask */-#define DMA_TX_TYPE_END (DMA_CYCLIC + 1)+#define DMA_TX_TYPE_END (DMA_BOX + 1)/**
From: Ravi Kumar V <hidden> Date: 2012-01-06 12:48:24
Add DMAEngine based driver using the old MSM DMA APIs internally.
The benefit of this approach is that not all the drivers
have to get converted to DMAEngine APIs simultaneosly while
both the drivers can stay enabled in the kernel. The client
drivers using the old MSM APIs directly can now convert to
DMAEngine one by one.
Change-Id: I3647ed7b8c73b3078dfa8877a3560db3cb0a2373
Signed-off-by: Ravi Kumar V <redacted>
---
arch/arm/mach-msm/include/mach/dma.h | 33 ++
drivers/dma/Kconfig | 12 +
drivers/dma/Makefile | 1 +
drivers/dma/msm-dma.c | 764 ++++++++++++++++++++++++++++++++++
4 files changed, 810 insertions(+), 0 deletions(-)
create mode 100644 drivers/dma/msm-dma.c
@@ -0,0 +1,764 @@+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.+*+*Thisprogramisfreesoftware;youcanredistributeitand/ormodify+*itunderthetermsoftheGNUGeneralPublicLicenseversion2and+*onlyversion2aspublishedbytheFreeSoftwareFoundation.+*+*Thisprogramisdistributedinthehopethatitwillbeuseful,+*butWITHOUTANYWARRANTY;withouteventheimpliedwarrantyof+*MERCHANTABILITYorFITNESSFORAPARTICULARPURPOSE.Seethe+*GNUGeneralPublicLicenseformoredetails.+*/+#include<linux/init.h>+#include<linux/slab.h>+#include<linux/clk.h>+#include<linux/err.h>+#include<linux/io.h>+#include<linux/interrupt.h>+#include<linux/module.h>+#include<linux/platform_device.h>+#include<linux/spinlock.h>+#include<linux/dmapool.h>+#include<linux/dmaengine.h>+#include<linux/dma-mapping.h>++#include<mach/dma.h>++#define SD3_CHAN_START 0+#define MSM_DMOV_CRCI_COUNT 16+#define MSM_DMA_MAX_CHANS_PER_DEVICE 16+#define MAX_TRANSFER_LENGTH 65535+#define NO_ERR_CHAN_STATUS 0x80000002+#define to_msm_chan(chan) container_of(chan, struct msm_dma_chan, channel)++structmsm_dma_chan{+intchan_id;+dma_cookie_tcompleted_cookie;+dma_cookie_terror_cookie;+spinlock_tlock;+structlist_headactive_list;+structlist_headpending_list;+structdma_chanchannel;+structdma_pool*desc_pool;+structdevice*dev;+intmax_len;+interr;+structtasklet_structtasklet;+};++structmsm_dma_device{+void__iomem*base;+structdevice*dev;+structdma_devicecommon;+structmsm_dma_chan*chan[MSM_DMA_MAX_CHANS_PER_DEVICE];+};++structmsm_dma_desc_hw{+unsignedintcmd_list_ptr;+}__aligned(8);++/* Single Item Mode */+structadm_cmd_t{+unsignedintcmd_cntrl;+unsignedintsrc;+unsignedintdst;+unsignedintlen;+};++structadm_box_cmd_t{+uint32_tcmd_cntrl;+uint32_tsrc_row_addr;+uint32_tdst_row_addr;+uint32_tsrc_dst_len;+uint32_tnum_rows;+uint32_trow_offset;+};++structmsm_dma_desc_sw{+structmsm_dma_desc_hwhw;+structadm_cmd_t*vaddr_cmd;+structadm_box_cmd_t*vaddr_box_cmd;+size_tcoherent_size;+dma_addr_tpaddr_cmd_list;+structlist_headnode;+structmsm_dmov_cmddmov_cmd;+structdma_async_tx_descriptorasync_tx;+}__aligned(8);++staticintmsm_dma_alloc_chan_resources(structdma_chan*dchan)+{+structmsm_dma_chan*chan=to_msm_chan(dchan);++/* Has this channel already been allocated? */+if(chan->desc_pool)+return1;++/*+*Weneedthedescriptortobealignedto8bytes+*formeetingADMspecificationrequirement.+*/+chan->desc_pool=dma_pool_create("msm_dma_desc_pool",+chan->dev,+sizeof(structmsm_dma_desc_sw),+__alignof__(structmsm_dma_desc_sw),0);+if(!chan->desc_pool){+dev_err(chan->dev,"unable to allocate channel %d "+"descriptor pool\n",chan->chan_id);+return-ENOMEM;+}++chan->completed_cookie=1;+dchan->cookie=1;++/* there is at least one descriptor free to be allocated */+return1;+}++staticvoidmsm_dma_free_desc_list(structmsm_dma_chan*chan,+structlist_head*list)+{+structmsm_dma_desc_sw*desc,*_desc;++list_for_each_entry_safe(desc,_desc,list,node){+list_del(&desc->node);+dma_pool_free(chan->desc_pool,desc,desc->async_tx.phys);+}+}++staticvoidmsm_dma_free_chan_resources(structdma_chan*dchan)+{+structmsm_dma_chan*chan=to_msm_chan(dchan);+unsignedlongflags;++dev_dbg(chan->dev,"Free all channel resources.\n");+spin_lock_irqsave(&chan->lock,flags);+msm_dma_free_desc_list(chan,&chan->active_list);+msm_dma_free_desc_list(chan,&chan->pending_list);+spin_unlock_irqrestore(&chan->lock,flags);++dma_pool_destroy(chan->desc_pool);+chan->desc_pool=NULL;+}++staticenumdma_statusmsm_dma_desc_status(structmsm_dma_chan*chan,+structmsm_dma_desc_sw*desc)+{+returndma_async_is_complete(desc->async_tx.cookie,+chan->completed_cookie,+chan->channel.cookie);+}++staticvoidmsm_chan_desc_cleanup(structmsm_dma_chan*chan)+{+structmsm_dma_desc_sw*desc,*_desc;+unsignedlongflags;++dev_dbg(chan->dev,"Cleaning completed descriptor of channel %d\n",+chan->chan_id);+spin_lock_irqsave(&chan->lock,flags);++list_for_each_entry_safe(desc,_desc,&chan->active_list,node){+dma_async_tx_callbackcallback;+void*callback_param;++if(msm_dma_desc_status(chan,desc)==DMA_IN_PROGRESS)+break;++/* Remove from the list of running transactions */+list_del(&desc->node);++/* Run the link descriptor callback function */+callback=desc->async_tx.callback;+callback_param=desc->async_tx.callback_param;+if(callback){+spin_unlock_irqrestore(&chan->lock,flags);+callback(callback_param);+spin_lock_irqsave(&chan->lock,flags);+}++/* Run any dependencies, then free the descriptor */+dma_run_dependencies(&desc->async_tx);+spin_unlock_irqrestore(&chan->lock,flags);++if(desc->vaddr_cmd){+dma_free_coherent(chan->dev,desc->coherent_size,+(void*)desc->vaddr_cmd,+desc->paddr_cmd_list);+}else{+dma_free_coherent(chan->dev,desc->coherent_size,+(void*)desc->vaddr_box_cmd,+desc->paddr_cmd_list);+}+spin_lock_irqsave(&chan->lock,flags);+dma_pool_free(chan->desc_pool,desc,desc->async_tx.phys);+}++spin_unlock_irqrestore(&chan->lock,flags);+}++staticvoiddma_do_tasklet(unsignedlongdata)+{+structmsm_dma_chan*chan=(structmsm_dma_chan*)data;+msm_chan_desc_cleanup(chan);+}++staticvoid+msm_dma_complete_func(structmsm_dmov_cmd*cmd,+unsignedintresult,+structmsm_dmov_errdata*err)+{+unsignedlongflags;+structmsm_dma_desc_sw*desch=container_of(cmd,+structmsm_dma_desc_sw,dmov_cmd);+structmsm_dma_chan*chan=to_msm_chan(desch->async_tx.chan);++spin_lock_irqsave(&chan->lock,flags);++if((result!=NO_ERR_CHAN_STATUS)&&err)+chan->error_cookie=desch->async_tx.cookie;+chan->completed_cookie=desch->async_tx.cookie;++tasklet_schedule(&chan->tasklet);++spin_unlock_irqrestore(&chan->lock,flags);+}++/*+*PassestransferdescriptorstoDMAhardware.+*/+staticvoidmsm_dma_issue_pending(structdma_chan*dchan)+{+structmsm_dma_chan*chan=to_msm_chan(dchan);+structmsm_dma_desc_sw*desch;+unsignedlongflags;++if(chan->err)+return;++spin_lock_irqsave(&chan->lock,flags);++if(list_empty(&chan->pending_list))+gotoout_unlock;++desch=list_first_entry(&chan->pending_list,structmsm_dma_desc_sw,+node);+list_del(&desch->node);+desch->dmov_cmd.complete_func=msm_dma_complete_func;+desch->dmov_cmd.execute_func=NULL;+desch->dmov_cmd.cmdptr=DMOV_CMD_ADDR(desch->async_tx.phys);+list_add_tail(&desch->node,&chan->active_list);+mb();+msm_dmov_enqueue_cmd(chan->chan_id,&desch->dmov_cmd);+out_unlock:+spin_unlock_irqrestore(&chan->lock,flags);+}++/*+*Assignescookieforeachtransferdescriptorpassed.+*Returns+*Assigendcookieforsuccess.+*Errorvalueforfailure.+*/+staticdma_cookie_tmsm_dma_tx_submit(structdma_async_tx_descriptor*tx)+{+structmsm_dma_chan*chan=to_msm_chan(tx->chan);+structmsm_dma_desc_sw*desc=container_of(tx,+structmsm_dma_desc_sw,async_tx);+unsignedlongflags;+dma_cookie_tcookie=-EBUSY;++if(chan->err)+returncookie;++spin_lock_irqsave(&chan->lock,flags);++/*+*assigncookiestoallofthesoftwaredescriptors+*thatmakeupthistransaction+*/+cookie=chan->channel.cookie;+cookie++;+if(cookie<0)+cookie=DMA_MIN_COOKIE;++desc->async_tx.cookie=cookie;+chan->channel.cookie=cookie;++/* put this transaction onto the tail of the pending queue */+list_add_tail(&desc->node,&chan->pending_list);++spin_unlock_irqrestore(&chan->lock,flags);++returncookie;+}++/*+*ReturnstheDMAtransferstatusofaparticularcookie+*/+staticenumdma_statusmsm_tx_status(structdma_chan*dchan,+dma_cookie_tcookie,+structdma_tx_state*txstate)+{+structmsm_dma_chan*chan=to_msm_chan(dchan);+dma_cookie_tlast_used;+dma_cookie_tlast_complete;+enumdma_statusstatus;++last_used=dchan->cookie;+last_complete=chan->completed_cookie;++dma_set_tx_state(txstate,last_complete,last_used,0);++status=dma_async_is_complete(cookie,last_complete,last_used);++if(status!=DMA_IN_PROGRESS)+if(chan->error_cookie==cookie)+status=DMA_ERROR;++returnstatus;+}++staticstructmsm_dma_desc_sw*msm_dma_alloc_descriptor(+structmsm_dma_chan*chan,+intcmd_cnt,+intmask)+{+structmsm_dma_desc_sw*desc;+dma_addr_tpdesc_addr;+dma_addr_tpaddr_cmd_list;+void*err=NULL;++desc=dma_pool_alloc(chan->desc_pool,GFP_ATOMIC,&pdesc_addr);+if(!desc){+dev_dbg(chan->dev,"out of memory for desc\n");+returnERR_CAST(desc);+}++memset(desc,0,sizeof(*desc));+desc->async_tx.phys=pdesc_addr;++if(mask==DMA_BOX){+desc->coherent_size=sizeof(structadm_box_cmd_t);+desc->vaddr_box_cmd=dma_alloc_coherent(chan->dev,+sizeof(structadm_box_cmd_t),+&paddr_cmd_list,GFP_ATOMIC);+if(!desc->vaddr_box_cmd){+dev_dbg(chan->dev,"out of memory for desc\n");+err=desc->vaddr_box_cmd;+gotofail;+}+}else{+desc->coherent_size=sizeof(structadm_cmd_t)*cmd_cnt;++desc->vaddr_cmd=dma_alloc_coherent(chan->dev,+sizeof(structadm_cmd_t)*cmd_cnt,+&paddr_cmd_list,GFP_ATOMIC);++if(!desc->vaddr_cmd){+dev_dbg(chan->dev,"out of memory for desc\n");+err=desc->vaddr_cmd;+gotofail;+}+}++dma_async_tx_descriptor_init(&desc->async_tx,&chan->channel);+desc->async_tx.tx_submit=msm_dma_tx_submit;+desc->paddr_cmd_list=paddr_cmd_list;+desc->hw.cmd_list_ptr=(paddr_cmd_list>>3)|CMD_PTR_LP;+returndesc;+fail:+dma_pool_free(chan->desc_pool,desc,desc->async_tx.phys);+returnERR_CAST(err);+}++/*+*PreparesthetransferdescriptorsforSGtransaction.+*Returns+*addressofdma_async_tx_descriptorforsuccess.+*Pointeroferrorvalueforfailure.+*/+staticstructdma_async_tx_descriptor*msm_dma_prep_sg(+structdma_chan*dchan,+structscatterlist*dst_sg,unsignedintdst_nents,+structscatterlist*src_sg,unsignedintsrc_nents,+unsignedlongflags)+{++structmsm_dma_chan*chan;+structmsm_dma_desc_sw*new;+size_tcopy,len;+intcmd_cnt=0;+intfirst=0;+inti;+dma_addr_tsrc;+dma_addr_tdst;+structadm_cmd_t*cmdlist_vaddr;+structscatterlist*sg;++if(!dchan)+returnERR_PTR(-EINVAL);++if(dst_nents==0||src_nents==0)+returnERR_PTR(-EINVAL);+if(!dst_sg||!src_sg)+returnERR_PTR(-EINVAL);++if(dst_nents!=src_nents)+returnERR_PTR(-EINVAL);++chan=to_msm_chan(dchan);++cmd_cnt=src_nents;++for(i=0;i<src_nents;i++){+len=sg_dma_len(src_sg+i);+if(len!=MAX_TRANSFER_LENGTH)+cmd_cnt+=len/MAX_TRANSFER_LENGTH;+}++new=msm_dma_alloc_descriptor(chan,cmd_cnt,DMA_SG);++if(!new){+dev_err(chan->dev,+"No free memory for link descriptor\n");+returnERR_PTR(-ENOMEM);+}++cmdlist_vaddr=new->vaddr_cmd;++for_each_sg(src_sg,sg,src_nents,i){+len=sg_dma_len(sg);+src=sg_dma_address(sg);+do{+copy=(len>=MAX_TRANSFER_LENGTH)?+MAX_TRANSFER_LENGTH:len;+cmdlist_vaddr->src=src;+cmdlist_vaddr->len=copy;+cmdlist_vaddr->cmd_cntrl=+(sg_dma_private_data(sg)&MSM_DMA_CMD_MASK);+if(first==0){+if(cmd_cnt==1)+cmdlist_vaddr->cmd_cntrl=CMD_LC|+CMD_OCB|CMD_OCU;+else+cmdlist_vaddr->cmd_cntrl=CMD_OCB;+first=1;+}+cmdlist_vaddr++;+len-=copy;+src+=copy;+}while(len);+}+if(cmd_cnt>1){+cmdlist_vaddr--;+cmdlist_vaddr->cmd_cntrl|=CMD_LC|CMD_OCU;+}++cmdlist_vaddr=new->vaddr_cmd;++for_each_sg(dst_sg,sg,src_nents,i){+len=sg_dma_len(sg);+dst=sg_dma_address(sg);+do{+copy=(len>=MAX_TRANSFER_LENGTH)?+MAX_TRANSFER_LENGTH:len;+cmdlist_vaddr->dst=dst;+cmdlist_vaddr++;+len-=copy;+dst+=copy;+}while(len);++}++#ifdef DEBUG+cmdlist_vaddr=new->vaddr_cmd;+i=0;+do{+dev_dbg(chan->dev,"cmd %d src 0x%x dst 0x%x len 0x%x "+"cntrl 0x%x\n",+i,cmdlist_vaddr->src,cmdlist_vaddr->dst,+cmdlist_vaddr->len,cmdlist_vaddr->cmd_cntrl);+cmdlist_vaddr++;+}while(!((cmdlist_vaddr-1)->cmd_cntrl&CMD_LC));+#endif+new->async_tx.flags=flags;+new->async_tx.cookie=-EBUSY;++return&new->async_tx;+}++/*+*PreparesthetransferdescriptorsforBOXtransaction.+*Returns+*addressofdma_async_tx_descriptorforsuccess.+*Pointeroferrorvalueforfailure.+*/+staticstructdma_async_tx_descriptor*msm_dma_prep_box(+structdma_chan*dchan,+structdma_box_list*dst_box,structdma_box_list*src_box,+unsignedintnum_list,unsignedlongflags)+{+structmsm_dma_chan*chan;+structmsm_dma_desc_sw*new;+intcmd_cnt=0;+intfirst=0;+inti;+structadm_box_cmd_t*box_cmd_vaddr;++if(!dchan)+returnERR_PTR(-EINVAL);++if(num_list==0)+returnERR_PTR(-EINVAL);+if(!dst_box||!src_box)+returnERR_PTR(-EINVAL);++chan=to_msm_chan(dchan);++cmd_cnt=num_list;++new=msm_dma_alloc_descriptor(chan,cmd_cnt,DMA_BOX);++if(!new){+dev_err(chan->dev,+"No free memory for link descriptor\n");+returnERR_PTR(-ENOMEM);+}+box_cmd_vaddr=new->vaddr_box_cmd;++for(i=0;i<num_list;i++){++box_cmd_vaddr->src_row_addr=+box_dma_row_address(src_box+i);+box_cmd_vaddr->src_dst_len=+(box_dma_row_len(src_box+i)&+MSM_BOX_SRC_RLEN_MASK)<<+MSM_BOX_SRC_RLEN_SHIFT;+box_cmd_vaddr->cmd_cntrl=+(box_dma_private_data(src_box+i)&+MSM_DMA_CMD_MASK)|MSM_BOX_MODE_CMD;++box_cmd_vaddr->num_rows=(box_dma_row_num(src_box+i)&+MSM_BOX_SRC_RNUM_MASK)<<+MSM_BOX_SRC_RNUM_SHIFT;++box_cmd_vaddr->row_offset=(box_dma_row_offset(src_box+i)&+MSM_BOX_SRC_ROFFSET_MASK)<<+MSM_BOX_SRC_ROFFSET_SHIFT;++if(first==0){+if(cmd_cnt==1)+box_cmd_vaddr->cmd_cntrl|=+CMD_LC|CMD_OCB|CMD_OCU;+else+box_cmd_vaddr->cmd_cntrl|=+CMD_OCB;+first=1;+}+box_cmd_vaddr++;+}++if(cmd_cnt>1){+box_cmd_vaddr--;+box_cmd_vaddr->cmd_cntrl|=CMD_LC|CMD_OCU;+}++box_cmd_vaddr=new->vaddr_box_cmd;++for(i=0;i<num_list;i++){++box_cmd_vaddr->dst_row_addr=box_dma_row_address(dst_box+i);+box_cmd_vaddr->src_dst_len|=+(box_dma_row_len(dst_box+i)&MSM_BOX_DST_RLEN_MASK);+box_cmd_vaddr->num_rows|=+(box_dma_row_num(dst_box+i)&+MSM_BOX_DST_RNUM_MASK);++box_cmd_vaddr->row_offset|=+(box_dma_row_offset(dst_box+i)&+MSM_BOX_DST_ROFFSET_MASK);+box_cmd_vaddr++;+}+#ifdef DEBUG+i=0;+box_cmd_vaddr=new->vaddr_box_cmd;+do{+dev_dbg(chan->dev,"cmd %d src 0x%x dst 0x%x len 0x%x "+"cntrl 0x%x row_offset 0x%x num_rows 0x%x\n",+i,box_cmd_vaddr->src_row_addr,+box_cmd_vaddr->dst_row_addr,+box_cmd_vaddr->src_dst_len,+box_cmd_vaddr->cmd_cntrl,+box_cmd_vaddr->row_offset,+box_cmd_vaddr->num_rows);+box_cmd_vaddr++;+i++;+}while(!((box_cmd_vaddr-1)->cmd_cntrl&CMD_LC));+#endif+new->async_tx.flags=flags;+new->async_tx.cookie=-EBUSY;++return&new->async_tx;+}++/*+*Controllingthehardwarechannellikestopping,flushing.+*/+staticintmsm_dma_chan_control(structdma_chan*chan,enumdma_ctrl_cmdcmd,+unsignedlongarg)+{+intcmd_type=(int)arg;++if(cmd==DMA_TERMINATE_ALL){+switch(cmd_type){+caseGRACEFUL_FLUSH:+msm_dmov_stop_cmd(chan->chan_id,NULL,1);+break;+caseFORCED_FLUSH:+/*+*Wetreatedefaultasforcedflush+*sowefallthrough+*/+default:+msm_dmov_stop_cmd(chan->chan_id,NULL,0);+break;+}+}+return0;+}++staticvoidmsm_dma_chan_remove(structmsm_dma_chan*chan)+{+tasklet_kill(&chan->tasklet);+list_del(&chan->channel.device_node);+kfree(chan);+}++static__devinitintmsm_dma_chan_probe(structmsm_dma_device*qdev,+intchannel)+{+structmsm_dma_chan*chan;++chan=kzalloc(sizeof(*chan),GFP_KERNEL);+if(!chan){+dev_err(qdev->dev,"no free memory for DMA channels!\n");+return-ENOMEM;+}++spin_lock_init(&chan->lock);+INIT_LIST_HEAD(&chan->pending_list);+INIT_LIST_HEAD(&chan->active_list);++chan->chan_id=channel;+chan->completed_cookie=0;+chan->channel.cookie=0;+chan->max_len=MAX_TRANSFER_LENGTH;+chan->err=0;+qdev->chan[channel]=chan;+chan->channel.device=&qdev->common;+chan->dev=qdev->dev;++tasklet_init(&chan->tasklet,dma_do_tasklet,(unsignedlong)chan);++list_add_tail(&chan->channel.device_node,&qdev->common.channels);+qdev->common.chancnt++;++return0;+}++staticint__devinitmsm_dma_probe(structplatform_device*pdev)+{+structmsm_dma_device*qdev;+inti;+intret=0;++qdev=kzalloc(sizeof(*qdev),GFP_KERNEL);+if(!qdev){+dev_err(&pdev->dev,"Not enough memory for device\n");+return-ENOMEM;+}++qdev->dev=&pdev->dev;+INIT_LIST_HEAD(&qdev->common.channels);+qdev->common.device_alloc_chan_resources=+msm_dma_alloc_chan_resources;+qdev->common.device_free_chan_resources=+msm_dma_free_chan_resources;+dma_cap_set(DMA_SG,qdev->common.cap_mask);+dma_cap_set(DMA_BOX,qdev->common.cap_mask);++qdev->common.device_prep_dma_sg=msm_dma_prep_sg;+qdev->common.device_prep_dma_box=msm_dma_prep_box;+qdev->common.device_issue_pending=msm_dma_issue_pending;+qdev->common.dev=&pdev->dev;+qdev->common.device_tx_status=msm_tx_status;+qdev->common.device_control=msm_dma_chan_control;++for(i=SD3_CHAN_START;i<MSM_DMA_MAX_CHANS_PER_DEVICE;i++){+ret=msm_dma_chan_probe(qdev,i);+if(ret){+dev_err(&pdev->dev,"channel %d probe failed\n",i);+gotochan_free;+}+}++dev_info(&pdev->dev,"registering dma device\n");++ret=dma_async_device_register(&qdev->common);++if(ret){+dev_err(&pdev->dev,"Registering Dma device failed\n");+gotochan_free;+}++dev_set_drvdata(&pdev->dev,qdev);+return0;+chan_free:+for(i=SD3_CHAN_START;i<MSM_DMA_MAX_CHANS_PER_DEVICE;i++){+if(qdev->chan[i])+msm_dma_chan_remove(qdev->chan[i]);+}+kfree(qdev);+returnret;+}++staticint__devexitmsm_dma_remove(structplatform_device*pdev)+{+structmsm_dma_device*qdev=platform_get_drvdata(pdev);+inti;++dma_async_device_unregister(&qdev->common);++for(i=SD3_CHAN_START;i<MSM_DMA_MAX_CHANS_PER_DEVICE;i++){+if(qdev->chan[i])+msm_dma_chan_remove(qdev->chan[i]);+}++dev_set_drvdata(&pdev->dev,NULL);+kfree(qdev);++return0;+}++staticstructplatform_drivermsm_dma_driver={+.remove=__devexit_p(msm_dma_remove),+.driver={+.name="msm_dma",+.owner=THIS_MODULE,+},+};++static__initintmsm_dma_init(void)+{+returnplatform_driver_probe(&msm_dma_driver,msm_dma_probe);+}+subsys_initcall(msm_dma_init);++staticvoid__exitmsm_dma_exit(void)+{+platform_driver_unregister(&msm_dma_driver);+}+module_exit(msm_dma_exit);++MODULE_DESCRIPTION("Qualcomm DMA driver");+MODULE_LICENSE("GPL v2");
--
Sent by a consultant of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
Make sure these Change-Id lines aren't in patch emails.
David
--
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
From: Daniel Walker <hidden> Date: 2012-01-07 02:08:59
On Fri, 2012-01-06 at 18:17 +0530, Ravi Kumar V wrote:
quoted hunk
Add DMAEngine based driver using the old MSM DMA APIs internally.
The benefit of this approach is that not all the drivers
have to get converted to DMAEngine APIs simultaneosly while
both the drivers can stay enabled in the kernel. The client
drivers using the old MSM APIs directly can now convert to
DMAEngine one by one.
Change-Id: I3647ed7b8c73b3078dfa8877a3560db3cb0a2373
Signed-off-by: Ravi Kumar V <redacted>
---
arch/arm/mach-msm/include/mach/dma.h | 33 ++
drivers/dma/Kconfig | 12 +
drivers/dma/Makefile | 1 +
drivers/dma/msm-dma.c | 764 ++++++++++++++++++++++++++++++++++
4 files changed, 810 insertions(+), 0 deletions(-)
create mode 100644 drivers/dma/msm-dma.c
@@ -0,0 +1,764 @@+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.+*+*Thisprogramisfreesoftware;youcanredistributeitand/ormodify+*itunderthetermsoftheGNUGeneralPublicLicenseversion2and+*onlyversion2aspublishedbytheFreeSoftwareFoundation.+*+*Thisprogramisdistributedinthehopethatitwillbeuseful,+*butWITHOUTANYWARRANTY;withouteventheimpliedwarrantyof+*MERCHANTABILITYorFITNESSFORAPARTICULARPURPOSE.Seethe+*GNUGeneralPublicLicenseformoredetails.+*/+#include<linux/init.h>+#include<linux/slab.h>+#include<linux/clk.h>+#include<linux/err.h>+#include<linux/io.h>+#include<linux/interrupt.h>+#include<linux/module.h>+#include<linux/platform_device.h>+#include<linux/spinlock.h>+#include<linux/dmapool.h>+#include<linux/dmaengine.h>+#include<linux/dma-mapping.h>++#include<mach/dma.h>++#define SD3_CHAN_START 0+#define MSM_DMOV_CRCI_COUNT 16+#define MSM_DMA_MAX_CHANS_PER_DEVICE 16+#define MAX_TRANSFER_LENGTH 65535+#define NO_ERR_CHAN_STATUS 0x80000002+#define to_msm_chan(chan) container_of(chan, struct msm_dma_chan, channel)++structmsm_dma_chan{+intchan_id;+dma_cookie_tcompleted_cookie;+dma_cookie_terror_cookie;+spinlock_tlock;+structlist_headactive_list;+structlist_headpending_list;+structdma_chanchannel;+structdma_pool*desc_pool;+structdevice*dev;+intmax_len;+interr;+structtasklet_structtasklet;+};++structmsm_dma_device{+void__iomem*base;+structdevice*dev;+structdma_devicecommon;+structmsm_dma_chan*chan[MSM_DMA_MAX_CHANS_PER_DEVICE];+};++structmsm_dma_desc_hw{+unsignedintcmd_list_ptr;+}__aligned(8);++/* Single Item Mode */+structadm_cmd_t{+unsignedintcmd_cntrl;+unsignedintsrc;+unsignedintdst;+unsignedintlen;+};++structadm_box_cmd_t{+uint32_tcmd_cntrl;+uint32_tsrc_row_addr;+uint32_tdst_row_addr;+uint32_tsrc_dst_len;+uint32_tnum_rows;+uint32_trow_offset;+};++structmsm_dma_desc_sw{+structmsm_dma_desc_hwhw;+structadm_cmd_t*vaddr_cmd;+structadm_box_cmd_t*vaddr_box_cmd;+size_tcoherent_size;+dma_addr_tpaddr_cmd_list;+structlist_headnode;+structmsm_dmov_cmddmov_cmd;+structdma_async_tx_descriptorasync_tx;+}__aligned(8);++staticintmsm_dma_alloc_chan_resources(structdma_chan*dchan)+{+structmsm_dma_chan*chan=to_msm_chan(dchan);++/* Has this channel already been allocated? */+if(chan->desc_pool)+return1;++/*+*Weneedthedescriptortobealignedto8bytes+*formeetingADMspecificationrequirement.+*/+chan->desc_pool=dma_pool_create("msm_dma_desc_pool",+chan->dev,+sizeof(structmsm_dma_desc_sw),+__alignof__(structmsm_dma_desc_sw),0);+if(!chan->desc_pool){+dev_err(chan->dev,"unable to allocate channel %d "+"descriptor pool\n",chan->chan_id);+return-ENOMEM;+}++chan->completed_cookie=1;+dchan->cookie=1;++/* there is at least one descriptor free to be allocated */+return1;+}++staticvoidmsm_dma_free_desc_list(structmsm_dma_chan*chan,+structlist_head*list)+{+structmsm_dma_desc_sw*desc,*_desc;++list_for_each_entry_safe(desc,_desc,list,node){+list_del(&desc->node);+dma_pool_free(chan->desc_pool,desc,desc->async_tx.phys);+}+}++staticvoidmsm_dma_free_chan_resources(structdma_chan*dchan)+{+structmsm_dma_chan*chan=to_msm_chan(dchan);+unsignedlongflags;++dev_dbg(chan->dev,"Free all channel resources.\n");+spin_lock_irqsave(&chan->lock,flags);+msm_dma_free_desc_list(chan,&chan->active_list);+msm_dma_free_desc_list(chan,&chan->pending_list);+spin_unlock_irqrestore(&chan->lock,flags);++dma_pool_destroy(chan->desc_pool);+chan->desc_pool=NULL;+}++staticenumdma_statusmsm_dma_desc_status(structmsm_dma_chan*chan,+structmsm_dma_desc_sw*desc)+{+returndma_async_is_complete(desc->async_tx.cookie,+chan->completed_cookie,+chan->channel.cookie);+}++staticvoidmsm_chan_desc_cleanup(structmsm_dma_chan*chan)+{+structmsm_dma_desc_sw*desc,*_desc;+unsignedlongflags;++dev_dbg(chan->dev,"Cleaning completed descriptor of channel %d\n",+chan->chan_id);+spin_lock_irqsave(&chan->lock,flags);++list_for_each_entry_safe(desc,_desc,&chan->active_list,node){+dma_async_tx_callbackcallback;+void*callback_param;++if(msm_dma_desc_status(chan,desc)==DMA_IN_PROGRESS)+break;++/* Remove from the list of running transactions */+list_del(&desc->node);++/* Run the link descriptor callback function */+callback=desc->async_tx.callback;+callback_param=desc->async_tx.callback_param;+if(callback){+spin_unlock_irqrestore(&chan->lock,flags);+callback(callback_param);
Are you sure unlocking here is safe? at_hdmac.c holds the lock the
entire time, and fsldma.c deletes the entire list, then runs the
operations.
Doesn't look like "i" has a log of meaning here.
If it were me I'd make the two #ifdef DEBUG blocks into helper
functions, then you could combine them into a single block. Would look
cleaner too I think.
...
+static void msm_chan_desc_cleanup(struct msm_dma_chan *chan)
+{
+ struct msm_dma_desc_sw *desc, *_desc;
+ unsigned long flags;
+
+ dev_dbg(chan->dev, "Cleaning completed descriptor of channel %d\n",
+ chan->chan_id);
+ spin_lock_irqsave(&chan->lock, flags);
+
+ list_for_each_entry_safe(desc, _desc, &chan->active_list, node) {
+ dma_async_tx_callback callback;
+ void *callback_param;
+
+ if (msm_dma_desc_status(chan, desc) == DMA_IN_PROGRESS)
+ break;
+
+ /* Remove from the list of running transactions */
+ list_del(&desc->node);
+
+ /* Run the link descriptor callback function */
+ callback = desc->async_tx.callback;
+ callback_param = desc->async_tx.callback_param;
+ if (callback) {
+ spin_unlock_irqrestore(&chan->lock, flags);
+ callback(callback_param);
Are you sure unlocking here is safe? at_hdmac.c holds the lock the
entire time, and fsldma.c deletes the entire list, then runs the
operations.
Good catch.
According to a comment in at_hdmac.c, it is safe to hold the lock
while calling the callbacks, so that's probably the easiest solution.
I suspect that you've got something in another driver expecting the
lock to be released, and that might have to be changed.
I do think the way fsldma.c does it is cleaner, though, since it
allows the lock to be released for longer periods of times.
In either case, it can't be releasing a lock in the middle of a loop
like this.
David
--
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
...
+static void msm_chan_desc_cleanup(struct msm_dma_chan *chan)
+{
+ struct msm_dma_desc_sw *desc, *_desc;
+ unsigned long flags;
+
+ dev_dbg(chan->dev, "Cleaning completed descriptor of channel %d\n",
+ chan->chan_id);
+ spin_lock_irqsave(&chan->lock, flags);
+
+ list_for_each_entry_safe(desc, _desc, &chan->active_list, node) {
+ dma_async_tx_callback callback;
+ void *callback_param;
+
+ if (msm_dma_desc_status(chan, desc) == DMA_IN_PROGRESS)
+ break;
+
+ /* Remove from the list of running transactions */
+ list_del(&desc->node);
+
+ /* Run the link descriptor callback function */
+ callback = desc->async_tx.callback;
+ callback_param = desc->async_tx.callback_param;
+ if (callback) {
+ spin_unlock_irqrestore(&chan->lock, flags);
+ callback(callback_param);
Are you sure unlocking here is safe? at_hdmac.c holds the lock the
entire time, and fsldma.c deletes the entire list, then runs the
operations.
Good catch.
According to a comment in at_hdmac.c, it is safe to hold the lock
while calling the callbacks, so that's probably the easiest solution.
I suspect that you've got something in another driver expecting the
lock to be released, and that might have to be changed.
It is _not_ safe to hold the lock while calling callbacks.
Please refer to the DMA engine documentation, found here:
Documentation/dmaengine.txt
section 3:
Note:
Although the async_tx API specifies that completion callback
routines cannot submit any new operations, this is not the
case for slave/cyclic DMA.
For slave DMA, the subsequent transaction may not be available
for submission prior to callback function being invoked, so
slave DMA callbacks are permitted to prepare and submit a new
transaction.
For cyclic DMA, a callback function may wish to terminate the
DMA via dmaengine_terminate_all().
* Therefore, it is important that DMA engine drivers drop any
* locks before calling the callback function which may cause a
* deadlock.
Note that callbacks will always be invoked from the DMA
engines tasklet, never from interrupt context.
...
+static void msm_chan_desc_cleanup(struct msm_dma_chan *chan)
+{
+ struct msm_dma_desc_sw *desc, *_desc;
+ unsigned long flags;
+
+ dev_dbg(chan->dev, "Cleaning completed descriptor of channel %d\n",
+ chan->chan_id);
+ spin_lock_irqsave(&chan->lock, flags);
+
+ list_for_each_entry_safe(desc, _desc, &chan->active_list, node) {
+ dma_async_tx_callback callback;
+ void *callback_param;
+
+ if (msm_dma_desc_status(chan, desc) == DMA_IN_PROGRESS)
+ break;
+
+ /* Remove from the list of running transactions */
+ list_del(&desc->node);
+
+ /* Run the link descriptor callback function */
+ callback = desc->async_tx.callback;
+ callback_param = desc->async_tx.callback_param;
+ if (callback) {
+ spin_unlock_irqrestore(&chan->lock, flags);
+ callback(callback_param);
Are you sure unlocking here is safe? at_hdmac.c holds the lock the
entire time, and fsldma.c deletes the entire list, then runs the
operations.
Good catch.
According to a comment in at_hdmac.c, it is safe to hold the lock
while calling the callbacks, so that's probably the easiest solution.
I suspect that you've got something in another driver expecting the
lock to be released, and that might have to be changed.
It is _not_ safe to hold the lock while calling callbacks.
Please refer to the DMA engine documentation, found here:
Documentation/dmaengine.txt
section 3:
Note:
Although the async_tx API specifies that completion callback
routines cannot submit any new operations, this is not the
case for slave/cyclic DMA.
For slave DMA, the subsequent transaction may not be available
for submission prior to callback function being invoked, so
slave DMA callbacks are permitted to prepare and submit a new
transaction.
For cyclic DMA, a callback function may wish to terminate the
DMA via dmaengine_terminate_all().
* Therefore, it is important that DMA engine drivers drop any
* locks before calling the callback function which may cause a
* deadlock.
Here's the comment from at_hdmac.c .
/*
* The API requires that no submissions are done from a
* callback, so we don't need to drop the lock here
*/
if (callback)
callback(param);
I don't know much about the DMA engine, but maybe there is some special
case here that makes this ok.. (CC'ed Nicolas Ferre)
Daniel
From: Russell King - ARM Linux <hidden> Date: 2012-01-08 00:22:17
On Sat, Jan 07, 2012 at 04:13:56PM -0800, Daniel Walker wrote:
On Sat, 2012-01-07 at 19:21 +0000, Russell King - ARM Linux wrote:
quoted
Please refer to the DMA engine documentation, found here:
Documentation/dmaengine.txt
section 3:
Note:
Although the async_tx API specifies that completion callback
routines cannot submit any new operations, this is not the
case for slave/cyclic DMA.
For slave DMA, the subsequent transaction may not be available
for submission prior to callback function being invoked, so
slave DMA callbacks are permitted to prepare and submit a new
transaction.
For cyclic DMA, a callback function may wish to terminate the
DMA via dmaengine_terminate_all().
* Therefore, it is important that DMA engine drivers drop any
* locks before calling the callback function which may cause a
* deadlock.
Here's the comment from at_hdmac.c .
/*
* The API requires that no submissions are done from a
* callback, so we don't need to drop the lock here
*/
if (callback)
callback(param);
I don't know much about the DMA engine, but maybe there is some special
case here that makes this ok.. (CC'ed Nicolas Ferre)
If you read the note fully, you'll notice that there's a difference
between the async_tx API and the slave/cyclic DMA API (it's covered
in the first paragraph.)
Plus that documentation was written by me, reviewed by Dan and Vinod
and accepted. You can treat it as authoritive, and take from it that
at_hdmac.c is buggy.
From: Ravi Kumar V <hidden> Date: 2012-01-09 11:11:57
On 1/7/2012 7:29 AM, Daniel Walker wrote:
On Fri, 2012-01-06 at 18:17 +0530, Ravi Kumar V wrote:
quoted
Add DMAEngine based driver using the old MSM DMA APIs internally.
The benefit of this approach is that not all the drivers
have to get converted to DMAEngine APIs simultaneosly while
both the drivers can stay enabled in the kernel. The client
drivers using the old MSM APIs directly can now convert to
DMAEngine one by one.
Change-Id: I3647ed7b8c73b3078dfa8877a3560db3cb0a2373
Signed-off-by: Ravi Kumar V<redacted>
---
arch/arm/mach-msm/include/mach/dma.h | 33 ++
drivers/dma/Kconfig | 12 +
drivers/dma/Makefile | 1 +
drivers/dma/msm-dma.c | 764 ++++++++++++++++++++++++++++++++++
4 files changed, 810 insertions(+), 0 deletions(-)
create mode 100644 drivers/dma/msm-dma.c
@@ -0,0 +1,764 @@+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.+*+*Thisprogramisfreesoftware;youcanredistributeitand/ormodify+*itunderthetermsoftheGNUGeneralPublicLicenseversion2and+*onlyversion2aspublishedbytheFreeSoftwareFoundation.+*+*Thisprogramisdistributedinthehopethatitwillbeuseful,+*butWITHOUTANYWARRANTY;withouteventheimpliedwarrantyof+*MERCHANTABILITYorFITNESSFORAPARTICULARPURPOSE.Seethe+*GNUGeneralPublicLicenseformoredetails.+*/+#include<linux/init.h>+#include<linux/slab.h>+#include<linux/clk.h>+#include<linux/err.h>+#include<linux/io.h>+#include<linux/interrupt.h>+#include<linux/module.h>+#include<linux/platform_device.h>+#include<linux/spinlock.h>+#include<linux/dmapool.h>+#include<linux/dmaengine.h>+#include<linux/dma-mapping.h>++#include<mach/dma.h>++#define SD3_CHAN_START 0+#define MSM_DMOV_CRCI_COUNT 16+#define MSM_DMA_MAX_CHANS_PER_DEVICE 16+#define MAX_TRANSFER_LENGTH 65535+#define NO_ERR_CHAN_STATUS 0x80000002+#define to_msm_chan(chan) container_of(chan, struct msm_dma_chan, channel)++structmsm_dma_chan{+intchan_id;+dma_cookie_tcompleted_cookie;+dma_cookie_terror_cookie;+spinlock_tlock;+structlist_headactive_list;+structlist_headpending_list;+structdma_chanchannel;+structdma_pool*desc_pool;+structdevice*dev;+intmax_len;+interr;+structtasklet_structtasklet;+};++structmsm_dma_device{+void__iomem*base;+structdevice*dev;+structdma_devicecommon;+structmsm_dma_chan*chan[MSM_DMA_MAX_CHANS_PER_DEVICE];+};++structmsm_dma_desc_hw{+unsignedintcmd_list_ptr;+}__aligned(8);++/* Single Item Mode */+structadm_cmd_t{+unsignedintcmd_cntrl;+unsignedintsrc;+unsignedintdst;+unsignedintlen;+};++structadm_box_cmd_t{+uint32_tcmd_cntrl;+uint32_tsrc_row_addr;+uint32_tdst_row_addr;+uint32_tsrc_dst_len;+uint32_tnum_rows;+uint32_trow_offset;+};++structmsm_dma_desc_sw{+structmsm_dma_desc_hwhw;+structadm_cmd_t*vaddr_cmd;+structadm_box_cmd_t*vaddr_box_cmd;+size_tcoherent_size;+dma_addr_tpaddr_cmd_list;+structlist_headnode;+structmsm_dmov_cmddmov_cmd;+structdma_async_tx_descriptorasync_tx;+}__aligned(8);++staticintmsm_dma_alloc_chan_resources(structdma_chan*dchan)+{+structmsm_dma_chan*chan=to_msm_chan(dchan);++/* Has this channel already been allocated? */+if(chan->desc_pool)+return1;++/*+*Weneedthedescriptortobealignedto8bytes+*formeetingADMspecificationrequirement.+*/+chan->desc_pool=dma_pool_create("msm_dma_desc_pool",+chan->dev,+sizeof(structmsm_dma_desc_sw),+__alignof__(structmsm_dma_desc_sw),0);+if(!chan->desc_pool){+dev_err(chan->dev,"unable to allocate channel %d "+"descriptor pool\n",chan->chan_id);+return-ENOMEM;+}++chan->completed_cookie=1;+dchan->cookie=1;++/* there is at least one descriptor free to be allocated */+return1;+}++staticvoidmsm_dma_free_desc_list(structmsm_dma_chan*chan,+structlist_head*list)+{+structmsm_dma_desc_sw*desc,*_desc;++list_for_each_entry_safe(desc,_desc,list,node){+list_del(&desc->node);+dma_pool_free(chan->desc_pool,desc,desc->async_tx.phys);+}+}++staticvoidmsm_dma_free_chan_resources(structdma_chan*dchan)+{+structmsm_dma_chan*chan=to_msm_chan(dchan);+unsignedlongflags;++dev_dbg(chan->dev,"Free all channel resources.\n");+spin_lock_irqsave(&chan->lock,flags);+msm_dma_free_desc_list(chan,&chan->active_list);+msm_dma_free_desc_list(chan,&chan->pending_list);+spin_unlock_irqrestore(&chan->lock,flags);++dma_pool_destroy(chan->desc_pool);+chan->desc_pool=NULL;+}++staticenumdma_statusmsm_dma_desc_status(structmsm_dma_chan*chan,+structmsm_dma_desc_sw*desc)+{+returndma_async_is_complete(desc->async_tx.cookie,+chan->completed_cookie,+chan->channel.cookie);+}++staticvoidmsm_chan_desc_cleanup(structmsm_dma_chan*chan)+{+structmsm_dma_desc_sw*desc,*_desc;+unsignedlongflags;++dev_dbg(chan->dev,"Cleaning completed descriptor of channel %d\n",+chan->chan_id);+spin_lock_irqsave(&chan->lock,flags);++list_for_each_entry_safe(desc,_desc,&chan->active_list,node){+dma_async_tx_callbackcallback;+void*callback_param;++if(msm_dma_desc_status(chan,desc)==DMA_IN_PROGRESS)+break;++/* Remove from the list of running transactions */+list_del(&desc->node);++/* Run the link descriptor callback function */+callback=desc->async_tx.callback;+callback_param=desc->async_tx.callback_param;+if(callback){+spin_unlock_irqrestore(&chan->lock,flags);+callback(callback_param);
Are you sure unlocking here is safe? at_hdmac.c holds the lock the
entire time, and fsldma.c deletes the entire list, then runs the
operations.
Doesn't look like "i" has a log of meaning here.
If it were me I'd make the two #ifdef DEBUG blocks into helper
functions, then you could combine them into a single block. Would look
cleaner too I think.
Why do you need to cast here? Both the flush macro's are positive.
quoted
+
+ if (cmd == DMA_TERMINATE_ALL) {
+ switch (cmd_type) {
+ case GRACEFUL_FLUSH:
+ msm_dmov_stop_cmd(chan->chan_id, NULL, 1);
+ break;
+ case FORCED_FLUSH:
+ /*
+ * We treate default as forced flush
+ * so we fall through
+ */
+ default:
+ msm_dmov_stop_cmd(chan->chan_id, NULL, 0);
+ break;
+ }
+ }
+ return 0;
+}
+
I will address the comments in next patch release, i will wait for
sometime for vinod comments and release new patch v3.
Ravi
--
Sent by a consultant of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
From: Ravi Kumar V <hidden> Date: 2012-01-17 06:26:25
On 1/9/2012 4:41 PM, Ravi Kumar V wrote:
On 1/7/2012 7:29 AM, Daniel Walker wrote:
quoted
On Fri, 2012-01-06 at 18:17 +0530, Ravi Kumar V wrote:
quoted
Add DMAEngine based driver using the old MSM DMA APIs internally.
The benefit of this approach is that not all the drivers
have to get converted to DMAEngine APIs simultaneosly while
both the drivers can stay enabled in the kernel. The client
drivers using the old MSM APIs directly can now convert to
DMAEngine one by one.
Change-Id: I3647ed7b8c73b3078dfa8877a3560db3cb0a2373
Signed-off-by: Ravi Kumar V<redacted>
---
arch/arm/mach-msm/include/mach/dma.h | 33 ++
drivers/dma/Kconfig | 12 +
drivers/dma/Makefile | 1 +
drivers/dma/msm-dma.c | 764 ++++++++++++++++++++++++++++++++++
4 files changed, 810 insertions(+), 0 deletions(-)
create mode 100644 drivers/dma/msm-dma.c
diff --git a/arch/arm/mach-msm/include/mach/dma.h
b/arch/arm/mach-msm/include/mach/dma.h
index 05583f5..34f4dac 100644
help
Enable support for the Cirrus Logic EP93xx M2P/M2M DMA controller.
+config MSM_DMA
+ tristate "Qualcomm MSM DMA support"
+ depends on ARCH_MSM
+ select DMA_ENGINE
+ help
+ Support the Qualcomm DMA engine. This engine is integrated into
+ Qualcomm chips.
+
+ Say Y here if you have such a chipset.
+
+ If unsure, say N.
+
config DMA_ENGINE
bool
Doesn't look like "i" has a log of meaning here.
If it were me I'd make the two #ifdef DEBUG blocks into helper
functions, then you could combine them into a single block. Would look
cleaner too I think.
Why do you need to cast here? Both the flush macro's are positive.
quoted
+
+ if (cmd == DMA_TERMINATE_ALL) {
+ switch (cmd_type) {
+ case GRACEFUL_FLUSH:
+ msm_dmov_stop_cmd(chan->chan_id, NULL, 1);
+ break;
+ case FORCED_FLUSH:
+ /*
+ * We treate default as forced flush
+ * so we fall through
+ */
+ default:
+ msm_dmov_stop_cmd(chan->chan_id, NULL, 0);
+ break;
+ }
+ }
+ return 0;
+}
+
I will address the comments in next patch release, i will wait for
sometime for vinod comments and release new patch v3.
Ravi
Dan williams please can you review my patch and let me know your comments.
--
Sent by a consultant of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
From: Ravi Kumar V <hidden> Date: 2012-01-17 06:32:45
On 1/9/2012 4:41 PM, Ravi Kumar V wrote:
On 1/7/2012 7:29 AM, Daniel Walker wrote:
quoted
On Fri, 2012-01-06 at 18:17 +0530, Ravi Kumar V wrote:
quoted
Add DMAEngine based driver using the old MSM DMA APIs internally.
The benefit of this approach is that not all the drivers
have to get converted to DMAEngine APIs simultaneosly while
both the drivers can stay enabled in the kernel. The client
drivers using the old MSM APIs directly can now convert to
DMAEngine one by one.
Change-Id: I3647ed7b8c73b3078dfa8877a3560db3cb0a2373
Signed-off-by: Ravi Kumar V<redacted>
---
I will address the comments in next patch release, i will wait for
sometime for vinod comments and release new patch v3.
Ravi
Dan please can you review my patches and let me know your comments.
--
Sent by a consultant of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
On Fri, 2012-01-06 at 18:17 +0530, Ravi Kumar V wrote:
<sorry for delayed review, was on vacation and now traveling >
As our ADM Scatter-gather hardware needs
-32-bit command configuration parameter
apart from
-32-bit source address
-32-bit destination address
-16-bit length
So,we have added new parameter in struct scatterlist to support xfer
descriptor
specific private data, and for supporting ADM Box mode DMA we added
new
API and data structure.
On Fri, 2012-01-06 at 18:17 +0530, Ravi Kumar V wrote:
Qualcomm MSM have a feature to pass command configuration and
control data along with source,destination and length of transfer
for every transaction, as of now struct scatterlist has no support
to send private data related to each transaction we added private_data
variable for supporting this type of archictures.
this looks quite similar to what RIO [1] folks were asking, ie ability
to pass specific parameters for each transaction which are device
specific.
quoted hunk
Qualcomm MSM also supports BOX mode of dma, currently as there is no
API in dmaengine to support this type of dma we added new API.
Change-Id: Ia9ee19f2c253e68b8e5ff254a57478dcc51014ca
Signed-off-by: Ravi Kumar V <redacted>
---
include/asm-generic/scatterlist.h | 1 +
include/linux/dmaengine.h | 17 ++++++++++++++++-
2 files changed, 17 insertions(+), 1 deletions(-)
what do you plan to pass here. Please keep in mind this is a generic
scatterlist structure, and modifying it for your purposes doesn't seem
to be a great one!
Also why can't you pass this as addition argument in your new "BOX API"?
@@ -72,10 +72,11 @@ enum dma_transaction_type {DMA_ASYNC_TX,DMA_SLAVE,DMA_CYCLIC,+DMA_BOX,};/* last transaction type for creation of the capabilities mask */-#define DMA_TX_TYPE_END (DMA_CYCLIC + 1)+#define DMA_TX_TYPE_END (DMA_BOX + 1)/**
On Fri, 2012-01-06 at 18:17 +0530, Ravi Kumar V wrote:
+static int msm_dma_alloc_chan_resources(struct dma_chan *dchan)
+{
+ struct msm_dma_chan *chan = to_msm_chan(dchan);
+
+ /* Has this channel already been allocated? */
+ if (chan->desc_pool)
+ return 1;
that is _wrong_. This would mean you have allocated 1 descriptor.
Please read the documentation again.
+
+/*
+ * Assignes cookie for each transfer descriptor passed.
+ * Returns
+ * Assigend cookie for success.
typo ^^^^^^^^^
+
+
+/*
+ * Prepares the transfer descriptors for BOX transaction.
+ * Returns
+ * address of dma_async_tx_descriptor for success.
+ * Pointer of error value for failure.
+ */
More comments, once I understand what "BOX mode" is?
Also, if you can add basic driver without box mode, we can merge fairly
quickly, box mode can come once we understand what we want and how...
--
~Vinod
From: Ravi Kumar V <hidden> Date: 2012-01-20 12:30:15
On 1/17/2012 7:15 PM, Vinod Koul wrote:
On Fri, 2012-01-06 at 18:17 +0530, Ravi Kumar V wrote:
<sorry for delayed review, was on vacation and now traveling>
quoted
As our ADM Scatter-gather hardware needs
-32-bit command configuration parameter
apart from
-32-bit source address
-32-bit destination address
-16-bit length
So,we have added new parameter in struct scatterlist to support xfer
descriptor
specific private data, and for supporting ADM Box mode DMA we added
new
API and data structure.
what do you mean by "ADM Box mode"?
ADM Box mode is a interleaved type of DMA where data from rows of equal
length and equal distance(bytes) between each other are transferred to
similar pattern of rows.
Each row length and distance between each row in destination pattern may
not be equal to source pattern.
Distance between beginning of any two rows are always greater than row
length.
Example:
If 4 rows of 16 bytes each are arranged such that distance between
beginning of any two rows are 32 bytes.
Now they can be transferred using BOX mode to destination pattern
arranged in 2 rows of 32 bytes each and distance between them can be any
lets say 128 bytes.
Source pattern:
4 data rows starts address 0th byte.
0-----16-bytes-data-----15
16 16 bytes void 31
32---------data---------47
48 void 63
64---------data---------79
80 void 95
96---------data--------111
Transferred to destination
Destination pattern:
2 rows
0----------32-bytes-data----------31
32 96 bytes void 127
128-------------data-------------159
--
Sent by a consultant of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
what do you plan to pass here. Please keep in mind this is a generic
scatterlist structure, and modifying it for your purposes doesn't seem
to be a great one!
Also why can't you pass this as addition argument in your new "BOX API"?
We are using DMA-Engine framework for both SG mode and BOX mode of our HW.
For SG mode we are using device_prep_dma_sg API but the problem we are
facing is we need to pass command configuration parameter along with
each descriptor to our HW, we did not find any suitable API/structure in
framework to support this.
So thought of adding new element in struct scatterlist.
please can you suggest a way to pass private parameter with
every descriptor.
quoted
};
/*
+
+struct dma_box_list {
+ dma_addr_t dma_row_address;
+ unsigned int dma_row_len;
+ unsigned int dma_row_num;
+ unsigned int dma_row_offset;
+ unsigned long private_data;
+};
again a private data here?
is this some kind of interleaved pattern?
Yes this interleaved pattern.
quoted
+
/**
* struct dma_device - info on the entity supplying DMA services
* @chancnt: how many DMA channels are supported
still not clean what kind of transfer do you want to do here
We are doing interleaved pattern of data transfer between source and
destination boxs, num_list is number of box mode commands
Please can you refer patch 0/2 I have replied explaining about box mode
transfer clearly.
quoted
+
int (*device_control)(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
unsigned long arg);
--
Sent by a consultant of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
From: Ravi Kumar V <hidden> Date: 2012-01-20 12:46:25
On 1/17/2012 8:01 PM, Vinod Koul wrote:
On Fri, 2012-01-06 at 18:17 +0530, Ravi Kumar V wrote:
quoted
+static int msm_dma_alloc_chan_resources(struct dma_chan *dchan)
+{
+ struct msm_dma_chan *chan = to_msm_chan(dchan);
+
+ /* Has this channel already been allocated? */
+ if (chan->desc_pool)
+ return 1;
that is _wrong_. This would mean you have allocated 1 descriptor.
Please read the documentation again.
Yes you are right, i will update in next patch release.
quoted
+
+/*
+ * Assignes cookie for each transfer descriptor passed.
+ * Returns
+ * Assigend cookie for success.
typo ^^^^^^^^^
I will change
quoted
+
+
+/*
+ * Prepares the transfer descriptors for BOX transaction.
+ * Returns
+ * address of dma_async_tx_descriptor for success.
+ * Pointer of error value for failure.
+ */
pls use kernel-doc style for these...
I will update
quoted
+static struct dma_async_tx_descriptor *msm_dma_prep_box(
+ struct dma_chan *dchan,
+ struct dma_box_list *dst_box, struct dma_box_list *src_box,
+ unsigned int num_list, unsigned long flags)
+{
+
+/*
+ * Controlling the hardware channel like stopping, flushing.
+ */
+static int msm_dma_chan_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
+ unsigned long arg)
+{
+ int cmd_type = (int) arg;
+
+ if (cmd == DMA_TERMINATE_ALL) {
+ switch (cmd_type) {
+ case GRACEFUL_FLUSH:
+ msm_dmov_stop_cmd(chan->chan_id, NULL, 1);
+ break;
+ case FORCED_FLUSH:
+ /*
+ * We treate default as forced flush
+ * so we fall through
+ */
+ default:
+ msm_dmov_stop_cmd(chan->chan_id, NULL, 0);
+ break;
+ }
+ }
More comments, once I understand what "BOX mode" is?
Also, if you can add basic driver without box mode, we can merge fairly
quickly, box mode can come once we understand what we want and how...
We also implemented SG mode using device_prep_dma_sg() but we need to
pass extra parameter "command configuration" to our HW with every
descriptor.
Please can you suggest a way to transfer private param to
device_prep_dma_sg()
--
Sent by a consultant of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
On Fri, 2012-01-20 at 18:00 +0530, Ravi Kumar V wrote:
On 1/17/2012 7:15 PM, Vinod Koul wrote:
quoted
On Fri, 2012-01-06 at 18:17 +0530, Ravi Kumar V wrote:
<sorry for delayed review, was on vacation and now traveling>
quoted
As our ADM Scatter-gather hardware needs
-32-bit command configuration parameter
apart from
-32-bit source address
-32-bit destination address
-16-bit length
So,we have added new parameter in struct scatterlist to support xfer
descriptor
specific private data, and for supporting ADM Box mode DMA we added
new
API and data structure.
what do you mean by "ADM Box mode"?
ADM Box mode is a interleaved type of DMA where data from rows of equal
length and equal distance(bytes) between each other are transferred to
similar pattern of rows.
Each row length and distance between each row in destination pattern may
not be equal to source pattern.
Distance between beginning of any two rows are always greater than row
length.
Example:
If 4 rows of 16 bytes each are arranged such that distance between
beginning of any two rows are 32 bytes.
Now they can be transferred using BOX mode to destination pattern
arranged in 2 rows of 32 bytes each and distance between them can be any
lets say 128 bytes.
Source pattern:
4 data rows starts address 0th byte.
0-----16-bytes-data-----15
16 16 bytes void 31
32---------data---------47
48 void 63
64---------data---------79
80 void 95
96---------data--------111
Transferred to destination
Destination pattern:
2 rows
0----------32-bytes-data----------31
32 96 bytes void 127
128-------------data-------------159
Sounds like you should be using interleaved API
Please see this and read the patch history, which has nice details about
this
/**
* struct dma_interleaved_template - Template to convey DMAC the
transfer pattern
* and attributes.
* @src_start: Bus address of source for the first chunk.
* @dst_start: Bus address of destination for the first chunk.
* @dir: Specifies the type of Source and Destination.
* @src_inc: If the source address increments after reading from it.
* @dst_inc: If the destination address increments after writing to it.
* @src_sgl: If the 'icg' of sgl[] applies to Source (scattered read).
* Otherwise, source is read contiguously (icg ignored).
* Ignored if src_inc is false.
* @dst_sgl: If the 'icg' of sgl[] applies to Destination (scattered write).
* Otherwise, destination is filled contiguously (icg ignored).
* Ignored if dst_inc is false.
* @numf: Number of frames in this template.
* @frame_size: Number of chunks in a frame i.e, size of sgl[].
* @sgl: Array of {chunk,icg} pairs that make up a frame.
*/
struct dma_interleaved_template {
dma_addr_t src_start;
dma_addr_t dst_start;
enum dma_transfer_direction dir;
bool src_inc;
bool dst_inc;
bool src_sgl;
bool dst_sgl;
size_t numf;
size_t frame_size;
struct data_chunk sgl[0];
};
using the interleaved API:
struct dma_async_tx_descriptor *(*device_prep_interleaved_dma)(
struct dma_chan *chan, struct dma_interleaved_template *xt,
unsigned long flags);
--
~Vinod
From: Ravi Kumar V <hidden> Date: 2012-01-23 11:11:24
On 1/20/2012 7:01 PM, Vinod Koul wrote:
On Fri, 2012-01-20 at 18:00 +0530, Ravi Kumar V wrote:
quoted
On 1/17/2012 7:15 PM, Vinod Koul wrote:
quoted
On Fri, 2012-01-06 at 18:17 +0530, Ravi Kumar V wrote:
<sorry for delayed review, was on vacation and now traveling>
quoted
As our ADM Scatter-gather hardware needs
-32-bit command configuration parameter
apart from
-32-bit source address
-32-bit destination address
-16-bit length
So,we have added new parameter in struct scatterlist to support xfer
descriptor
specific private data, and for supporting ADM Box mode DMA we added
new
API and data structure.
what do you mean by "ADM Box mode"?
ADM Box mode is a interleaved type of DMA where data from rows of equal
length and equal distance(bytes) between each other are transferred to
similar pattern of rows.
Each row length and distance between each row in destination pattern may
not be equal to source pattern.
Distance between beginning of any two rows are always greater than row
length.
Example:
If 4 rows of 16 bytes each are arranged such that distance between
beginning of any two rows are 32 bytes.
Now they can be transferred using BOX mode to destination pattern
arranged in 2 rows of 32 bytes each and distance between them can be any
lets say 128 bytes.
Source pattern:
4 data rows starts address 0th byte.
0-----16-bytes-data-----15
16 16 bytes void 31
32---------data---------47
48 void 63
64---------data---------79
80 void 95
96---------data--------111
Transferred to destination
Destination pattern:
2 rows
0----------32-bytes-data----------31
32 96 bytes void 127
128-------------data-------------159
Sounds like you should be using interleaved API
Please see this and read the patch history, which has nice details about
this
/**
* struct dma_interleaved_template - Template to convey DMAC the
transfer pattern
* and attributes.
* @src_start: Bus address of source for the first chunk.
* @dst_start: Bus address of destination for the first chunk.
* @dir: Specifies the type of Source and Destination.
* @src_inc: If the source address increments after reading from it.
* @dst_inc: If the destination address increments after writing to it.
* @src_sgl: If the 'icg' of sgl[] applies to Source (scattered read).
* Otherwise, source is read contiguously (icg ignored).
* Ignored if src_inc is false.
* @dst_sgl: If the 'icg' of sgl[] applies to Destination (scattered write).
* Otherwise, destination is filled contiguously (icg ignored).
* Ignored if dst_inc is false.
* @numf: Number of frames in this template.
* @frame_size: Number of chunks in a frame i.e, size of sgl[].
* @sgl: Array of {chunk,icg} pairs that make up a frame.
*/
struct dma_interleaved_template {
dma_addr_t src_start;
dma_addr_t dst_start;
enum dma_transfer_direction dir;
bool src_inc;
bool dst_inc;
bool src_sgl;
bool dst_sgl;
size_t numf;
size_t frame_size;
struct data_chunk sgl[0];
};
using the interleaved API:
struct dma_async_tx_descriptor *(*device_prep_interleaved_dma)(
struct dma_chan *chan, struct dma_interleaved_template *xt,
unsigned long flags);
If some changes are made in interleave API then it can support our BOX
mode. Here in interleaved template he is assuming destination pattern as
can be contiguous or same as source pattern, but in our case destination
pattern is different from source pattern.
So if a new parameter destination data chunk is added in "struct
dma_interleaved_template" structure then it can support different
destination pattern.
Also it will good if you can provide another parameter for passing
private data to dma driver.
Please can you review my other patches also where we replied to some of
your questions about passing private data for SG mode.
Thanks
Ravi Kumar
--
Sent by a consultant of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
On Mon, 2012-01-23 at 16:41 +0530, Ravi Kumar V wrote:
If some changes are made in interleave API then it can support our BOX
mode. Here in interleaved template he is assuming destination pattern as
can be contiguous or same as source pattern, but in our case destination
pattern is different from source pattern.
So if a new parameter destination data chunk is added in "struct
dma_interleaved_template" structure then it can support different
destination pattern.
do you mean you have cases where you are doing a "memcpy" from one
interleaved memory to another?
Can you provide me with a scenario where this maybe helpful?
The reason why the API was designed like this was to give ability to
take these kind of interleaved memory and copy them to peripheral
(constant addr) or memory (typically contagious).
In case it is just a pattern I wonder why it cannot be described in
standard scatter gather definitions as you can split the block further
down to copy from one respective block to somewhere else in memory.
Also it will good if you can provide another parameter for passing
private data to dma driver.
1. what does this parameter do?
2. is this parameter static for a channel or it changes per transfer?
--
~Vinod
From: Ravi Kumar V <hidden> Date: 2012-01-25 13:11:37
On 1/23/2012 7:21 PM, Vinod Koul wrote:
On Mon, 2012-01-23 at 16:41 +0530, Ravi Kumar V wrote:
quoted
If some changes are made in interleave API then it can support our BOX
mode. Here in interleaved template he is assuming destination pattern as
can be contiguous or same as source pattern, but in our case destination
pattern is different from source pattern.
So if a new parameter destination data chunk is added in "struct
dma_interleaved_template" structure then it can support different
destination pattern.
do you mean you have cases where you are doing a "memcpy" from one
interleaved memory to another?
Can you provide me with a scenario where this maybe helpful?
Presently we are transferring data from interleaved memory tho
contagious memory and vice-verse.
We can use the interleaved API for present scenario, but it will
restrict the HW capability of transferring data from one interleaved
pattern to other interleaved pattern.
The reason why the API was designed like this was to give ability to
take these kind of interleaved memory and copy them to peripheral
(constant addr) or memory (typically contagious).
In case it is just a pattern I wonder why it cannot be described in
standard scatter gather definitions as you can split the block further
down to copy from one respective block to somewhere else in memory.
We can use scatter gather but it will be extra burden on software to
create those many SG list unlike in box mode just a single command
serves the purpose.
quoted
Also it will good if you can provide another parameter for passing
private data to dma driver.
1. what does this parameter do?
Private parameter in our case will be command configuration parameter
where we are passing information to HW like endianness, synchronization
& acknowledge mechanism between DMA HW and peripherals running with
different clock than DMA.
2. is this parameter static for a channel or it changes per transfer?
This parameter changes per each transfer.
We can see these possibilities to implement our DMA driver but still
have to add new parameter in "scatterlist" & "interleaved template" for
supporting per transfer private data like our command configuration
parameter.
1.We have to add new parameter "struct data_chunk" in
"interleaved_template" for supporting different destination pattern.
It helps a lot for implementing our total HW capability.
2.We have to use present API's for box mode.
--scatter gather API for different interleaved source & destination
patterns.
--interleaved API for interleaved source pattern to destination
contiguous pattern/vice-verse.
It causes some extra burden on our software to create sglist.
3.Implement New API for BOX mode.
I feel if we can go with first option then it helps a lot.
Please can you suggest a better way to solve our problem.
Thanks,
Ravi Kumar
--
Sent by a consultant of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
From: Ravi Kumar V <hidden> Date: 2012-01-30 07:54:00
On 1/25/2012 6:41 PM, Ravi Kumar V wrote:
On 1/23/2012 7:21 PM, Vinod Koul wrote:
quoted
On Mon, 2012-01-23 at 16:41 +0530, Ravi Kumar V wrote:
quoted
If some changes are made in interleave API then it can support our BOX
mode. Here in interleaved template he is assuming destination pattern as
can be contiguous or same as source pattern, but in our case destination
pattern is different from source pattern.
So if a new parameter destination data chunk is added in "struct
dma_interleaved_template" structure then it can support different
destination pattern.
do you mean you have cases where you are doing a "memcpy" from one
interleaved memory to another?
Can you provide me with a scenario where this maybe helpful?
Presently we are transferring data from interleaved memory tho
contagious memory and vice-verse.
We can use the interleaved API for present scenario, but it will
restrict the HW capability of transferring data from one interleaved
pattern to other interleaved pattern.
quoted
The reason why the API was designed like this was to give ability to
take these kind of interleaved memory and copy them to peripheral
(constant addr) or memory (typically contagious).
In case it is just a pattern I wonder why it cannot be described in
standard scatter gather definitions as you can split the block further
down to copy from one respective block to somewhere else in memory.
We can use scatter gather but it will be extra burden on software to
create those many SG list unlike in box mode just a single command
serves the purpose.
quoted
quoted
Also it will good if you can provide another parameter for passing
private data to dma driver.
1. what does this parameter do?
Private parameter in our case will be command configuration parameter
where we are passing information to HW like endianness, synchronization
& acknowledge mechanism between DMA HW and peripherals running with
different clock than DMA.
quoted
2. is this parameter static for a channel or it changes per transfer?
This parameter changes per each transfer.
We can see these possibilities to implement our DMA driver but still
have to add new parameter in "scatterlist" & "interleaved template" for
supporting per transfer private data like our command configuration
parameter.
1.We have to add new parameter "struct data_chunk" in
"interleaved_template" for supporting different destination pattern.
It helps a lot for implementing our total HW capability.
2.We have to use present API's for box mode.
--scatter gather API for different interleaved source & destination
patterns.
--interleaved API for interleaved source pattern to destination
contiguous pattern/vice-verse.
It causes some extra burden on our software to create sglist.
3.Implement New API for BOX mode.
I feel if we can go with first option then it helps a lot.
Please can you suggest a better way to solve our problem.
Thanks,
Ravi Kumar
Please can you suggest best way.
--
Sent by a consultant of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
On Wed, 2012-01-25 at 18:41 +0530, Ravi Kumar V wrote:
On 1/23/2012 7:21 PM, Vinod Koul wrote:
quoted
On Mon, 2012-01-23 at 16:41 +0530, Ravi Kumar V wrote:
quoted
If some changes are made in interleave API then it can support our BOX
mode. Here in interleaved template he is assuming destination pattern as
can be contiguous or same as source pattern, but in our case destination
pattern is different from source pattern.
So if a new parameter destination data chunk is added in "struct
dma_interleaved_template" structure then it can support different
destination pattern.
do you mean you have cases where you are doing a "memcpy" from one
interleaved memory to another?
Can you provide me with a scenario where this maybe helpful?
Presently we are transferring data from interleaved memory tho
contagious memory and vice-verse.
We can use the interleaved API for present scenario, but it will
restrict the HW capability of transferring data from one interleaved
pattern to other interleaved pattern.
That's interesting capability.
My question still unanswered is whats the real work usage of this
capability. Helps to understand what this would be used for and
providing optimal solution
quoted
The reason why the API was designed like this was to give ability to
take these kind of interleaved memory and copy them to peripheral
(constant addr) or memory (typically contagious).
In case it is just a pattern I wonder why it cannot be described in
standard scatter gather definitions as you can split the block further
down to copy from one respective block to somewhere else in memory.
We can use scatter gather but it will be extra burden on software to
create those many SG list unlike in box mode just a single command
serves the purpose.
quoted
quoted
Also it will good if you can provide another parameter for passing
private data to dma driver.
1. what does this parameter do?
Private parameter in our case will be command configuration parameter
where we are passing information to HW like endianness, synchronization
& acknowledge mechanism between DMA HW and peripherals running with
different clock than DMA.
This is a separate discussion. We had similar talk on need to pass
controller/subsystem specific parameters [1] sometime back during RIO
patches. Alexandre has posted a new RFC [2] which should be extended to
whatever API you finally end up using
[1]: https://lkml.org/lkml/2011/10/24/275
[2]: https://lkml.org/lkml/2012/1/26/405
--
~Vinod
From: Ravi Kumar V <hidden> Date: 2012-01-31 05:59:41
On 1/30/2012 1:45 PM, Vinod Koul wrote:
On Wed, 2012-01-25 at 18:41 +0530, Ravi Kumar V wrote:
quoted
On 1/23/2012 7:21 PM, Vinod Koul wrote:
quoted
On Mon, 2012-01-23 at 16:41 +0530, Ravi Kumar V wrote:
quoted
If some changes are made in interleave API then it can support our BOX
mode. Here in interleaved template he is assuming destination pattern as
can be contiguous or same as source pattern, but in our case destination
pattern is different from source pattern.
So if a new parameter destination data chunk is added in "struct
dma_interleaved_template" structure then it can support different
destination pattern.
do you mean you have cases where you are doing a "memcpy" from one
interleaved memory to another?
Can you provide me with a scenario where this maybe helpful?
Presently we are transferring data from interleaved memory tho
contagious memory and vice-verse.
We can use the interleaved API for present scenario, but it will
restrict the HW capability of transferring data from one interleaved
pattern to other interleaved pattern.
That's interesting capability.
My question still unanswered is whats the real work usage of this
capability. Helps to understand what this would be used for and
providing optimal solution
quoted
quoted
The reason why the API was designed like this was to give ability to
take these kind of interleaved memory and copy them to peripheral
(constant addr) or memory (typically contagious).
In case it is just a pattern I wonder why it cannot be described in
standard scatter gather definitions as you can split the block further
down to copy from one respective block to somewhere else in memory.
We can use scatter gather but it will be extra burden on software to
create those many SG list unlike in box mode just a single command
serves the purpose.
quoted
quoted
Also it will good if you can provide another parameter for passing
private data to dma driver.
1. what does this parameter do?
Private parameter in our case will be command configuration parameter
where we are passing information to HW like endianness, synchronization
& acknowledge mechanism between DMA HW and peripherals running with
different clock than DMA.
This is a separate discussion. We had similar talk on need to pass
controller/subsystem specific parameters [1] sometime back during RIO
patches. Alexandre has posted a new RFC [2] which should be extended to
whatever API you finally end up using
[1]: https://lkml.org/lkml/2011/10/24/275
[2]: https://lkml.org/lkml/2012/1/26/405
Yes if we follow the above RFC and add extra context parameter also in
device_prep_dma_sg() & device_prep_interleaved_dma() then it supports
our hardware and our work will be completed.
can we follow above RFC and implement our driver.
Is above RFC finalized and included in mainline?
Thanks,
Ravi Kumar
--
Sent by a consultant of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
Yes if we follow the above RFC and add extra context parameter also
in
device_prep_dma_sg() & device_prep_interleaved_dma() then it supports
our hardware and our work will be completed.
can we follow above RFC and implement our driver.
Is above RFC finalized and included in mainline?
Alexandre will post an updated one soon, but the idea is same
--
~Vinod
Yes if we follow the above RFC and add extra context parameter also
in
device_prep_dma_sg()& device_prep_interleaved_dma() then it supports
our hardware and our work will be completed.
can we follow above RFC and implement our driver.
Is above RFC finalized and included in mainline?
Alexandre will post an updated one soon, but the idea is same
Can we add extra parameter context to device_prep_dma_sg() &
device_prep_interleaved_dma() API's and implement our driver.
--
Sent by a consultant of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
Yes if we follow the above RFC and add extra context parameter also
in
device_prep_dma_sg()& device_prep_interleaved_dma() then it supports
our hardware and our work will be completed.
can we follow above RFC and implement our driver.
Is above RFC finalized and included in mainline?
Alexandre will post an updated one soon, but the idea is same
Can we add extra parameter context to device_prep_dma_sg() &
device_prep_interleaved_dma() API's and implement our driver.
So what one are you going to use...
From the description sounds like you need interleaved API but with
changes to make it interleaved in both src and dtsn, right?
Then why prep_dma_sg?
--
~Vinod
Yes if we follow the above RFC and add extra context parameter also
in
device_prep_dma_sg()& device_prep_interleaved_dma() then it supports
our hardware and our work will be completed.
can we follow above RFC and implement our driver.
Is above RFC finalized and included in mainline?
Alexandre will post an updated one soon, but the idea is same
Can we add extra parameter context to device_prep_dma_sg()&
device_prep_interleaved_dma() API's and implement our driver.
So what one are you going to use...
quoted
From the description sounds like you need interleaved API but with
changes to make it interleaved in both src and dtsn, right?her
Then why prep_dma_sg?
Our hardware supports single transfer mode,scatter gather mode & box mode.
we are using these dmaengine API's for our HW
device_prep_memcpy() for single mode.
device_prep_dma_sg() for sg mode.
device_prep_interleaved_dma() for box mode.
We need to pass command configuration parameter to all of the above
three modes and it can be possible if extra context parameter is added
into these API's
--
Sent by a consultant of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
Yes if we follow the above RFC and add extra context parameter also
in
device_prep_dma_sg()& device_prep_interleaved_dma() then it supports
our hardware and our work will be completed.
can we follow above RFC and implement our driver.
Is above RFC finalized and included in mainline?
Alexandre will post an updated one soon, but the idea is same
Can we add extra parameter context to device_prep_dma_sg()&
device_prep_interleaved_dma() API's and implement our driver.
So what one are you going to use...
quoted
From the description sounds like you need interleaved API but with
changes to make it interleaved in both src and dtsn, right?
Then why prep_dma_sg?
Our hardware supports single transfer mode,scatter gather mode & box mode.
we are using these dmaengine API's for our HW
device_prep_memcpy() for single mode.
device_prep_dma_sg() for sg mode.
device_prep_interleaved_dma() for box mode.
We need to pass command configuration parameter to all of the above
three modes and it can be possible if extra context parameter is added
into these API's
Thanks
Ravi Kumar
--
Sent by a consultant of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
On Wed, 2012-02-01 at 14:07 +0530, Ravi Kumar V wrote:
Our hardware supports single transfer mode,scatter gather mode & box
mode.
we are using these dmaengine API's for our HW
device_prep_memcpy() for single mode.
device_prep_dma_sg() for sg mode.
device_prep_interleaved_dma() for box mode.
We need to pass command configuration parameter to all of the above
three modes and it can be possible if extra context parameter is added
into these API's
but again, is this static fr channel for each transfer. Would you be
able to derive these for non box modes?
--
~Vinod
From: Ravi Kumar V <hidden> Date: 2012-02-01 09:09:11
On 2/1/2012 2:16 PM, Vinod Koul wrote:
On Wed, 2012-02-01 at 14:07 +0530, Ravi Kumar V wrote:
quoted
Our hardware supports single transfer mode,scatter gather mode& box
mode.
we are using these dmaengine API's for our HW
device_prep_memcpy() for single mode.
device_prep_dma_sg() for sg mode.
device_prep_interleaved_dma() for box mode.
We need to pass command configuration parameter to all of the above
three modes and it can be possible if extra context parameter is added
into these API's
but again, is this static fr channel for each transfer. Would you be
able to derive these for non box modes?
Command configuration parameter has this information which is used be our HW
1.Device Id for Synchronization & acknowledgment with slow clock devices.
2.Endian type.
3.Blocking/unblocking channel after/before transfer.
Command configuration parameter should be passed in all the three modes
and per transfer so this parameter is dynamic keep changing for each
transfer.
--
Sent by a consultant of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.