bool mv_cesa_req_dma_iter_next_transfer(struct mv_cesa_dma_iter *iter, struct mv_cesa_sg_dma_iter *sgiter, unsigned int len) { if (!sgiter->sg) return false; sgiter->op_offset += len; sgiter->offset += len; if (sgiter->offset == sg_dma_len(sgiter->sg)) { if (sg_is_last(sgiter->sg)) return false; sgiter->offset = 0; sgiter->sg = sg_next(sgiter->sg); } if (sgiter->op_offset == iter->op_len) return false; return true; }
/* * Do a scatter/gather DMA copy from FB memory. You must have done * a successful call to viafb_request_dma() first. */ int viafb_dma_copy_out_sg(unsigned int offset, struct scatterlist *sg, int nsg) { struct viafb_vx855_dma_descr *descr; void *descrpages; dma_addr_t descr_handle; unsigned long flags; int i; struct scatterlist *sgentry; dma_addr_t nextdesc; /* * Get a place to put the descriptors. */ descrpages = dma_alloc_coherent(&global_dev.pdev->dev, nsg*sizeof(struct viafb_vx855_dma_descr), &descr_handle, GFP_KERNEL); if (descrpages == NULL) { dev_err(&global_dev.pdev->dev, "Unable to get descr page.\n"); return -ENOMEM; } mutex_lock(&viafb_dma_lock); /* * Fill them in. */ descr = descrpages; nextdesc = descr_handle + sizeof(struct viafb_vx855_dma_descr); for_each_sg(sg, sgentry, nsg, i) { dma_addr_t paddr = sg_dma_address(sgentry); descr->addr_low = paddr & 0xfffffff0; descr->addr_high = ((u64) paddr >> 32) & 0x0fff; descr->fb_offset = offset; descr->seg_size = sg_dma_len(sgentry) >> 4; descr->tile_mode = 0; descr->next_desc_low = (nextdesc&0xfffffff0) | VIAFB_DMA_MAGIC; descr->next_desc_high = ((u64) nextdesc >> 32) & 0x0fff; descr->pad = 0xffffffff; /* VIA driver does this */ offset += sg_dma_len(sgentry); nextdesc += sizeof(struct viafb_vx855_dma_descr); descr++; }
int videobuf_dma_map(struct videobuf_queue* q, struct videobuf_dmabuf *dma) { MAGIC_CHECK(dma->magic,MAGIC_DMABUF); BUG_ON(0 == dma->nr_pages); if (dma->pages) { dma->sglist = videobuf_pages_to_sg(dma->pages, dma->nr_pages, dma->offset); } if (dma->vmalloc) { dma->sglist = videobuf_vmalloc_to_sg (dma->vmalloc,dma->nr_pages); } if (dma->bus_addr) { dma->sglist = kmalloc(sizeof(struct scatterlist), GFP_KERNEL); if (NULL != dma->sglist) { dma->sglen = 1; sg_dma_address(&dma->sglist[0]) = dma->bus_addr & PAGE_MASK; dma->sglist[0].offset = dma->bus_addr & ~PAGE_MASK; sg_dma_len(&dma->sglist[0]) = dma->nr_pages * PAGE_SIZE; } } if (NULL == dma->sglist) { dprintk(1,"scatterlist is NULL\n"); return -ENOMEM; } if (!dma->bus_addr) { dma->sglen = dma_map_sg(q->dev, dma->sglist, dma->nr_pages, dma->direction); if (0 == dma->sglen) { printk(KERN_WARNING "%s: videobuf_map_sg failed\n",__func__); kfree(dma->sglist); dma->sglist = NULL; dma->sglen = 0; return -EIO; } } return 0; }
static int dma_start(struct rk_mmc *host) { int i, res, direction, sg_len; enum rk29_dmasrc src; struct mmc_data *data = host->data; BUG_ON(!data); host->dma_xfer_size = 0; if (data->flags & MMC_DATA_READ){ direction = DMA_FROM_DEVICE; src = RK29_DMASRC_HW; }else{ direction = DMA_TO_DEVICE; src = RK29_DMASRC_MEM; } sg_len = rk_mmc_pre_dma_transfer(host, host->data, 0); if(sg_len < 0){ host->ops->stop(host); return sg_len; } res = rk29_dma_devconfig(MMC_DMA_CHN, src, host->dma_addr); if(unlikely(res < 0)) return res; for(i = 0; i < sg_len; i++){ res = rk29_dma_enqueue(MMC_DMA_CHN, host, sg_dma_address(&data->sg[i]), sg_dma_len(&data->sg[i])); if(unlikely(res < 0)) return res; } res = rk29_dma_ctrl(MMC_DMA_CHN, RK29_DMAOP_START); if(unlikely(res < 0)) return res; return res; }
/* Supports scatter/gather */ static void mmc_dma_rx_start(struct mmci_host *host) { unsigned int len; int i, dma_len; struct scatterlist *sg; struct mmc_request *mrq = host->mrq; struct mmc_data *reqdata = mrq->data; void *dmaaddr; u32 dmalen, dmaxferlen; sg = reqdata->sg; len = reqdata->sg_len; dma_len = dma_map_sg( mmc_dev(host->mmc), reqdata->sg, reqdata->sg_len, DMA_FROM_DEVICE); if (dma_len == 0) return; /* Setup transfer */ for (i = 0; i < len; i++) { dmalen = (u32) sg_dma_len(&sg[i]); dmaaddr = (void *) sg_dma_address(&sg[i]); /* Build a list with a max size if 15872 bytes per seg */ while (dmalen > 0) { dmaxferlen = dmalen; if (dmaxferlen > 15872) dmaxferlen = 15872; lpc178x_dma_queue_llist_entry(dmac_drvdat.lastch, (void *) SD_FIFO((u32)host->base), dmaaddr, dmaxferlen); dmaaddr += dmaxferlen; dmalen -= dmaxferlen; } } }
static struct sg_table * tegra_gem_prime_map_dma_buf(struct dma_buf_attachment *attach, enum dma_data_direction dir) { struct drm_gem_object *gem = attach->dmabuf->priv; struct tegra_bo *bo = to_tegra_bo(gem); struct sg_table *sgt; sgt = kmalloc(sizeof(*sgt), GFP_KERNEL); if (!sgt) return NULL; if (bo->pages) { struct scatterlist *sg; unsigned int i; if (sg_alloc_table(sgt, bo->num_pages, GFP_KERNEL)) goto free; for_each_sg(sgt->sgl, sg, bo->num_pages, i) sg_set_page(sg, bo->pages[i], PAGE_SIZE, 0); if (dma_map_sg(attach->dev, sgt->sgl, sgt->nents, dir) == 0) goto free; } else { if (sg_alloc_table(sgt, 1, GFP_KERNEL)) goto free; sg_dma_address(sgt->sgl) = bo->paddr; sg_dma_len(sgt->sgl) = gem->size; } return sgt; free: sg_free_table(sgt); kfree(sgt); return NULL; }
static struct sg_table * tegra_gem_prime_map_dma_buf(struct dma_buf_attachment *attach, enum dma_data_direction dir) { struct drm_gem_object *gem = attach->dmabuf->priv; struct tegra_bo *bo = to_tegra_bo(gem); struct sg_table *sgt; sgt = kmalloc(sizeof(*sgt), GFP_KERNEL); if (!sgt) return NULL; if (sg_alloc_table(sgt, 1, GFP_KERNEL)) { kfree(sgt); return NULL; } sg_dma_address(sgt->sgl) = bo->paddr; sg_dma_len(sgt->sgl) = gem->size; return sgt; }
static unsigned int fill_xfer_opecodes( struct opecode* op_ptr , struct scatterlist* sg_list , unsigned int sg_nums , bool xfer_first, bool xfer_last , unsigned int xfer_mode ) { struct scatterlist* curr_sg; int sg_index; unsigned int op_count; dma_addr_t dma_address; unsigned int dma_length; bool dma_last; if (IS_ERR_OR_NULL(op_ptr) || IS_ERR_OR_NULL(sg_list) || (sg_nums < 1)) { return 0; } op_count = 0; for_each_sg(sg_list, curr_sg, sg_nums, sg_index) { dma_address = sg_dma_address(curr_sg); dma_length = sg_dma_len(curr_sg); dma_last = (sg_index >= sg_nums-1) ? xfer_last : 0; set_xfer_opecode( op_ptr , /* struct opecode* op_ptr */ 0 , /* bool fetch */ 0 , /* bool done */ xfer_first , /* bool xfer_first */ dma_last , /* bool xfer_last */ dma_address, /* dma_addr_t addr */ dma_length , /* unsigned int size */ xfer_mode /* unsigned int mode */ ); op_count++; op_ptr++; xfer_first = 0; }
static int samsung_dmadev_prepare(unsigned ch, struct samsung_dma_prep_info *info) { struct scatterlist sg; struct dma_chan *chan = (struct dma_chan *)ch; struct dma_async_tx_descriptor *desc; switch (info->cap) { case DMA_SLAVE: sg_init_table(&sg, 1); sg_dma_len(&sg) = info->len; sg_set_page(&sg, pfn_to_page(PFN_DOWN(info->buf)), info->len, offset_in_page(info->buf)); sg_dma_address(&sg) = info->buf; desc = chan->device->device_prep_slave_sg(chan, &sg, 1, info->direction, DMA_PREP_INTERRUPT); break; case DMA_CYCLIC: desc = chan->device->device_prep_dma_cyclic(chan, info->buf, info->len, info->period, info->direction); break; default: dev_err(&chan->dev->device, "unsupported format\n"); return -EFAULT; } if (!desc) { dev_err(&chan->dev->device, "cannot prepare cyclic dma\n"); return -EFAULT; } desc->callback = info->fp; desc->callback_param = info->fp_param; dmaengine_submit((struct dma_async_tx_descriptor *)desc); return 0; }
/* Unmap the current page: common for multiple and single block IO */ static void usdhi6_sg_unmap(struct usdhi6_host *host, bool force) { struct mmc_data *data = host->mrq->data; struct page *page = host->head_pg.page; if (page) { /* Previous block was cross-page boundary */ struct scatterlist *sg = data->sg_len > 1 ? host->sg : data->sg; size_t blk_head = host->head_len; if (!data->error && data->flags & MMC_DATA_READ) { memcpy(host->head_pg.mapped + PAGE_SIZE - blk_head, host->bounce_buf, blk_head); memcpy(host->pg.mapped, host->bounce_buf + blk_head, data->blksz - blk_head); } flush_dcache_page(page); kunmap(page); host->head_pg.page = NULL; if (!force && sg_dma_len(sg) + sg->offset > (host->page_idx << PAGE_SHIFT) + data->blksz - blk_head) /* More blocks in this SG, don't unmap the next page */ return; } page = host->pg.page; if (!page) return; flush_dcache_page(page); kunmap(page); host->pg.page = NULL; }
static void jz_mmc_receive_pio(struct jz_mmc_host *host) { struct mmc_data *data = 0; int sg_len = 0, max = 0, count = 0; u32 *buf = 0; struct scatterlist *sg; unsigned int nob; data = host->mrq->data; nob = data->blocks; REG_MSC_NOB = nob; REG_MSC_BLKLEN = data->blksz; max = host->pio.len; if (host->pio.index < host->dma.len) { sg = &data->sg[host->pio.index]; buf = sg_virt(sg) + host->pio.offset; /* This is the space left inside the buffer */ sg_len = sg_dma_len(&data->sg[host->pio.index]) - host->pio.offset; /* Check to if we need less then the size of the sg_buffer */ if (sg_len < max) max = sg_len; } max = max / 4; for(count = 0; count < max; count++) { while (REG_MSC_STAT & MSC_STAT_DATA_FIFO_EMPTY) ; *buf++ = REG_MSC_RXFIFO; } host->pio.len -= count; host->pio.offset += count; if (sg_len && count == sg_len) { host->pio.index++; host->pio.offset = 0; } }
static void camera_core_start_overlay(struct camera_device *cam) { int err; unsigned long irqflags; if (!cam->previewing) return; spin_lock_irqsave(&cam->overlay_lock, irqflags); sg_dma_address(&cam->overlay_sglist) = cam->overlay_base_phys; sg_dma_len(&cam->overlay_sglist)= cam->pix.sizeimage; while (cam->overlay_cnt < 2) { err = camera_core_sgdma_queue(cam, &cam->overlay_sglist, 1, camera_core_overlay_callback, NULL); if (err) break; ++cam->overlay_cnt; } spin_unlock_irqrestore(&cam->overlay_lock, irqflags); }
static int hptiop_buildsgl(struct scsi_cmnd *scp, struct hpt_iopsg *psg) { struct Scsi_Host *host = scp->device->host; struct hptiop_hba *hba = (struct hptiop_hba *)host->hostdata; struct scatterlist *sg; int idx, nseg; nseg = scsi_dma_map(scp); BUG_ON(nseg < 0); if (!nseg) return 0; HPT_SCP(scp)->sgcnt = nseg; HPT_SCP(scp)->mapped = 1; BUG_ON(HPT_SCP(scp)->sgcnt > hba->max_sg_descriptors); scsi_for_each_sg(scp, sg, HPT_SCP(scp)->sgcnt, idx) { psg[idx].pci_address = cpu_to_le64(sg_dma_address(sg)); psg[idx].size = cpu_to_le32(sg_dma_len(sg)); psg[idx].eot = (idx == HPT_SCP(scp)->sgcnt - 1) ? cpu_to_le32(1) : 0; }
static void vb2_dma_contig_map_dmabuf(void *mem_priv) { struct vb2_dc_buf *buf = mem_priv; struct dma_buf *dmabuf; struct sg_table *sg; enum dma_data_direction dir; if (!buf || !buf->db_attach) return; WARN_ON(buf->dma_addr); dmabuf = buf->db_attach->dmabuf; /* TODO need a way to know if we are camera or display, etc.. */ dir = DMA_BIDIRECTIONAL; /* get the associated sg for this buffer */ sg = dma_buf_map_attachment(buf->db_attach, dir); if (!sg) return; /* * convert sglist to paddr: * Assumption: for dma-contig, dmabuf would map to single entry * Will print a warning if it has more than one. */ if (sg->nents > 1) printk(KERN_WARNING "dmabuf scatterlist has more than 1 entry\n"); buf->dma_addr = sg_dma_address(sg->sgl); buf->size = sg_dma_len(sg->sgl); /* save this sg in dmabuf for put_scatterlist */ dmabuf->priv = sg; }
static struct sg_table *omap_gem_map_dma_buf( struct dma_buf_attachment *attachment, enum dma_data_direction dir) { struct drm_gem_object *obj = attachment->dmabuf->priv; struct sg_table *sg; dma_addr_t dma_addr; int ret; sg = kzalloc(sizeof(*sg), GFP_KERNEL); if (!sg) return ERR_PTR(-ENOMEM); /* camera, etc, need physically contiguous.. but we need a * better way to know this.. */ ret = omap_gem_pin(obj, &dma_addr); if (ret) goto out; ret = sg_alloc_table(sg, 1, GFP_KERNEL); if (ret) goto out; sg_init_table(sg->sgl, 1); sg_dma_len(sg->sgl) = obj->size; sg_set_page(sg->sgl, pfn_to_page(PFN_DOWN(dma_addr)), obj->size, 0); sg_dma_address(sg->sgl) = dma_addr; /* this must be after omap_gem_pin() to ensure we have pages attached */ omap_gem_dma_sync_buffer(obj, dir); return sg; out: kfree(sg); return ERR_PTR(ret); }
static void map_dma(unsigned int i, unsigned int j) { unsigned int data_len = 0; unsigned int k, pci_dir; int count; struct scatterlist *sg; struct mscp *cpp; struct scsi_cmnd *SCpnt; cpp = &HD(j)->cp[i]; SCpnt = cpp->SCpnt; pci_dir = SCpnt->sc_data_direction; if (SCpnt->sense_buffer) cpp->sense_addr = H2DEV(pci_map_single(HD(j)->pdev, SCpnt->sense_buffer, SCSI_SENSE_BUFFERSIZE, PCI_DMA_FROMDEVICE)); cpp->sense_len = SCSI_SENSE_BUFFERSIZE; if (scsi_bufflen(SCpnt)) { count = scsi_dma_map(SCpnt); BUG_ON(count < 0); scsi_for_each_sg(SCpnt, sg, count, k) { cpp->sglist[k].address = H2DEV(sg_dma_address(sg)); cpp->sglist[k].num_bytes = H2DEV(sg_dma_len(sg)); data_len += sg->length; } cpp->sg = TRUE; cpp->use_sg = scsi_sg_count(SCpnt); cpp->data_address = H2DEV(pci_map_single(HD(j)->pdev, cpp->sglist, cpp->use_sg * sizeof(struct sg_list), pci_dir)); cpp->data_len = H2DEV(data_len); } else {
static void omap2_mcspi_tx_dma(struct spi_device *spi, struct spi_transfer *xfer, struct dma_slave_config cfg) { struct omap2_mcspi *mcspi; struct omap2_mcspi_dma *mcspi_dma; unsigned int count; mcspi = spi_master_get_devdata(spi->master); mcspi_dma = &mcspi->dma_channels[spi->chip_select]; count = xfer->len; if (mcspi_dma->dma_tx) { struct dma_async_tx_descriptor *tx; struct scatterlist sg; dmaengine_slave_config(mcspi_dma->dma_tx, &cfg); sg_init_table(&sg, 1); sg_dma_address(&sg) = xfer->tx_dma; sg_dma_len(&sg) = xfer->len; tx = dmaengine_prep_slave_sg(mcspi_dma->dma_tx, &sg, 1, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (tx) { tx->callback = omap2_mcspi_tx_callback; tx->callback_param = spi; dmaengine_submit(tx); } else { /* FIXME: fall back to PIO? */ } } dma_async_issue_pending(mcspi_dma->dma_tx); omap2_mcspi_set_dma_req(spi, 0, 1); }
/* Prepare DMA to start data transfer from the MMC card */ static void jz_mmc_tx_setup_data(struct jz_mmc_host *host, struct mmc_data *data) { unsigned int nob = data->blocks; int channeltx = txdmachan; int i; u32 size; if (data->flags & MMC_DATA_STREAM) nob = 0xffff; REG_MSC_NOB = nob; REG_MSC_BLKLEN = data->blksz; size = nob * data->blksz; if (data->flags & MMC_DATA_READ) { host->dma.dir = DMA_FROM_DEVICE; } else { host->dma.dir = DMA_TO_DEVICE; } host->dma.len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len, host->dma.dir); for (i = 0; i < host->dma.len; i++) { host->sg_cpu[i].dtadr = sg_dma_address(&data->sg[i]); host->sg_cpu[i].dcmd = sg_dma_len(&data->sg[i]); dma_cache_wback_inv((unsigned long) CKSEG0ADDR(sg_dma_address(data->sg)) + data->sg->offset, host->sg_cpu[i].dcmd); jz_mmc_start_dma(channeltx, host->sg_cpu[i].dtadr, host->sg_cpu[i].dcmd, DMA_MODE_WRITE); } }
dma_addr_t ispmmu_vmap(const struct scatterlist *sglist, int sglen) { int err; void *da; struct sg_table *sgt; unsigned int i; struct scatterlist *sg, *src = (struct scatterlist *)sglist; /* * convert isp sglist to iommu sgt * FIXME: should be fixed in the upper layer? */ sgt = kmalloc(sizeof(*sgt), GFP_KERNEL); if (!sgt) return -ENOMEM; err = sg_alloc_table(sgt, sglen, GFP_KERNEL); if (err) goto err_sg_alloc; for_each_sg(sgt->sgl, sg, sgt->nents, i) sg_set_buf(sg, phys_to_virt(sg_dma_address(src + i)), sg_dma_len(src + i)); da = (void *)iommu_vmap(isp_iommu, 0, sgt, IOMMU_FLAG); if (IS_ERR(da)) goto err_vmap; return (dma_addr_t)da; err_vmap: sg_free_table(sgt); err_sg_alloc: kfree(sgt); return -ENOMEM; }
/** * iser_data_buf_aligned_len - Tries to determine the maximal correctly aligned * for RDMA sub-list of a scatter-gather list of memory buffers, and returns * the number of entries which are aligned correctly. Supports the case where * consecutive SG elements are actually fragments of the same physcial page. */ static unsigned int iser_data_buf_aligned_len(struct iser_data_buf *data) { struct scatterlist *sg; dma_addr_t end_addr, next_addr; int i, cnt; unsigned int ret_len = 0; sg = (struct scatterlist *)data->buf; for (cnt = 0, i = 0; i < data->dma_nents; i++, cnt++) { /* iser_dbg("Checking sg iobuf [%d]: phys=0x%08lX " "offset: %ld sz: %ld\n", i, (unsigned long)page_to_phys(sg[i].page), (unsigned long)sg[i].offset, (unsigned long)sg[i].length); */ end_addr = sg_dma_address(&sg[i]) + sg_dma_len(&sg[i]); /* iser_dbg("Checking sg iobuf end address " "0x%08lX\n", end_addr); */ if (i + 1 < data->dma_nents) { next_addr = sg_dma_address(&sg[i+1]); /* are i, i+1 fragments of the same page? */ if (end_addr == next_addr) continue; else if (!IS_4K_ALIGNED(end_addr)) { ret_len = cnt + 1; break; } } } if (i == data->dma_nents) ret_len = cnt; /* loop ended */ iser_dbg("Found %d aligned entries out of %d in sg:0x%p\n", ret_len, data->dma_nents, data); return ret_len; }
static int srp_indirect_data(struct scsi_cmnd *sc, struct srp_cmd *cmd, struct srp_indirect_buf *id, enum dma_data_direction dir, srp_rdma_t rdma_io, int dma_map, int ext_desc) { struct iu_entry *iue = NULL; struct srp_direct_buf *md = NULL; struct scatterlist dummy, *sg = NULL; dma_addr_t token = 0; int err = 0; int nmd, nsg = 0, len; if (dma_map || ext_desc) { iue = (struct iu_entry *) sc->SCp.ptr; sg = scsi_sglist(sc); dprintk("%p %u %u %d %d\n", iue, scsi_bufflen(sc), id->len, cmd->data_in_desc_cnt, cmd->data_out_desc_cnt); } nmd = id->table_desc.len / sizeof(struct srp_direct_buf); if ((dir == DMA_FROM_DEVICE && nmd == cmd->data_in_desc_cnt) || (dir == DMA_TO_DEVICE && nmd == cmd->data_out_desc_cnt)) { md = &id->desc_list[0]; goto rdma; } if (ext_desc && dma_map) { md = dma_alloc_coherent(iue->target->dev, id->table_desc.len, &token, GFP_KERNEL); if (!md) { eprintk("Can't get dma memory %u\n", id->table_desc.len); return -ENOMEM; } sg_init_one(&dummy, md, id->table_desc.len); sg_dma_address(&dummy) = token; sg_dma_len(&dummy) = id->table_desc.len; err = rdma_io(sc, &dummy, 1, &id->table_desc, 1, DMA_TO_DEVICE, id->table_desc.len); if (err) { eprintk("Error copying indirect table %d\n", err); goto free_mem; } } else { eprintk("This command uses external indirect buffer\n"); return -EINVAL; } rdma: if (dma_map) { nsg = dma_map_sg(iue->target->dev, sg, scsi_sg_count(sc), DMA_BIDIRECTIONAL); if (!nsg) { eprintk("fail to map %p %d\n", iue, scsi_sg_count(sc)); err = -EIO; goto free_mem; } len = min(scsi_bufflen(sc), id->len); } else len = id->len; err = rdma_io(sc, sg, nsg, md, nmd, dir, len); if (dma_map) dma_unmap_sg(iue->target->dev, sg, nsg, DMA_BIDIRECTIONAL); free_mem: if (token && dma_map) dma_free_coherent(iue->target->dev, id->table_desc.len, md, token); return err; }
/* * IOCTL operation; Import fd to UMP memory */ int ump_ion_import_wrapper(u32 __user * argument, struct ump_session_data * session_data) { _ump_uk_ion_import_s user_interaction; ump_dd_handle *ump_handle; ump_dd_physical_block * blocks; unsigned long num_blocks; struct ion_handle *ion_hnd; struct scatterlist *sg; struct scatterlist *sg_ion; unsigned long i = 0; ump_session_memory_list_element * session_memory_element = NULL; if (ion_client_ump==NULL) ion_client_ump = ion_client_create(ion_exynos, -1, "ump"); /* Sanity check input parameters */ if (NULL == argument || NULL == session_data) { MSG_ERR(("NULL parameter in ump_ioctl_allocate()\n")); return -ENOTTY; } /* Copy the user space memory to kernel space (so we safely can read it) */ if (0 != copy_from_user(&user_interaction, argument, sizeof(user_interaction))) { MSG_ERR(("copy_from_user() in ump_ioctl_allocate()\n")); return -EFAULT; } user_interaction.ctx = (void *) session_data; /* translate fd to secure ID*/ ion_hnd = ion_import_fd(ion_client_ump, user_interaction.ion_fd); sg_ion = ion_map_dma(ion_client_ump,ion_hnd); blocks = (ump_dd_physical_block*)_mali_osk_malloc(sizeof(ump_dd_physical_block)*1024); if (NULL == blocks) { MSG_ERR(("Failed to allocate blocks in ump_ioctl_allocate()\n")); return -ENOMEM; } sg = sg_ion; do { blocks[i].addr = sg_phys(sg); blocks[i].size = sg_dma_len(sg); i++; if (i>=1024) { _mali_osk_free(blocks); MSG_ERR(("ion_import fail() in ump_ioctl_allocate()\n")); return -EFAULT; } sg = sg_next(sg); } while(sg); num_blocks = i; /* Initialize the session_memory_element, and add it to the session object */ session_memory_element = _mali_osk_calloc( 1, sizeof(ump_session_memory_list_element)); if (NULL == session_memory_element) { _mali_osk_free(blocks); DBG_MSG(1, ("Failed to allocate ump_session_memory_list_element in ump_ioctl_allocate()\n")); return -EFAULT; } ump_handle = ump_dd_handle_create_from_phys_blocks(blocks, num_blocks); if (UMP_DD_HANDLE_INVALID == ump_handle) { _mali_osk_free(session_memory_element); _mali_osk_free(blocks); DBG_MSG(1, ("Failed to allocate ump_session_memory_list_element in ump_ioctl_allocate()\n")); return -EFAULT; } session_memory_element->mem = (ump_dd_mem*)ump_handle; _mali_osk_mutex_wait(session_data->lock); _mali_osk_list_add(&(session_memory_element->list), &(session_data->list_head_session_memory_list)); _mali_osk_mutex_signal(session_data->lock); ion_unmap_dma(ion_client_ump,ion_hnd); ion_free(ion_client_ump, ion_hnd); _mali_osk_free(blocks); user_interaction.secure_id = ump_dd_secure_id_get(ump_handle); user_interaction.size = ump_dd_size_get(ump_handle); user_interaction.ctx = NULL; if (0 != copy_to_user(argument, &user_interaction, sizeof(user_interaction))) { /* If the copy fails then we should release the memory. We can use the IOCTL release to accomplish this */ MSG_ERR(("copy_to_user() failed in ump_ioctl_allocate()\n")); return -EFAULT; } return 0; /* success */ }
static unsigned int siw_dma_len(struct ib_device *dev, struct scatterlist *sg) { return sg_dma_len(sg); }
/* Prepare to transfer the next segment of a scatterlist */ static void mmc_omap_prepare_dma(struct mmc_omap_host *host, struct mmc_data *data) { int dma_ch = host->dma_ch; unsigned long data_addr; u16 buf, frame; u32 count; struct scatterlist *sg = &data->sg[host->sg_idx]; int src_port = 0; int dst_port = 0; int sync_dev = 0; data_addr = host->phys_base + OMAP_MMC_REG_DATA; frame = data->blksz; count = sg_dma_len(sg); if ((data->blocks == 1) && (count > data->blksz)) count = frame; host->dma_len = count; /* FIFO is 16x2 bytes on 15xx, and 32x2 bytes on 16xx and 24xx. * Use 16 or 32 word frames when the blocksize is at least that large. * Blocksize is usually 512 bytes; but not for some SD reads. */ if (cpu_is_omap15xx() && frame > 32) frame = 32; else if (frame > 64) frame = 64; count /= frame; frame >>= 1; if (!(data->flags & MMC_DATA_WRITE)) { buf = 0x800f | ((frame - 1) << 8); if (cpu_class_is_omap1()) { src_port = OMAP_DMA_PORT_TIPB; dst_port = OMAP_DMA_PORT_EMIFF; } if (cpu_is_omap24xx()) sync_dev = OMAP24XX_DMA_MMC1_RX; omap_set_dma_src_params(dma_ch, src_port, OMAP_DMA_AMODE_CONSTANT, data_addr, 0, 0); omap_set_dma_dest_params(dma_ch, dst_port, OMAP_DMA_AMODE_POST_INC, sg_dma_address(sg), 0, 0); omap_set_dma_dest_data_pack(dma_ch, 1); omap_set_dma_dest_burst_mode(dma_ch, OMAP_DMA_DATA_BURST_4); } else { buf = 0x0f80 | ((frame - 1) << 0); if (cpu_class_is_omap1()) { src_port = OMAP_DMA_PORT_EMIFF; dst_port = OMAP_DMA_PORT_TIPB; } if (cpu_is_omap24xx()) sync_dev = OMAP24XX_DMA_MMC1_TX; omap_set_dma_dest_params(dma_ch, dst_port, OMAP_DMA_AMODE_CONSTANT, data_addr, 0, 0); omap_set_dma_src_params(dma_ch, src_port, OMAP_DMA_AMODE_POST_INC, sg_dma_address(sg), 0, 0); omap_set_dma_src_data_pack(dma_ch, 1); omap_set_dma_src_burst_mode(dma_ch, OMAP_DMA_DATA_BURST_4); } /* Max limit for DMA frame count is 0xffff */ BUG_ON(count > 0xffff); OMAP_MMC_WRITE(host, BUF, buf); omap_set_dma_transfer_params(dma_ch, OMAP_DMA_DATA_TYPE_S16, frame, count, OMAP_DMA_SYNC_FRAME, sync_dev, 0); }
static void au1xmmc_receive_pio(struct au1xmmc_host *host) { struct mmc_data *data; int max, count, sg_len = 0; unsigned char *sg_ptr = NULL; u32 status, val; struct scatterlist *sg; data = host->mrq->data; if (!(host->flags & HOST_F_RECV)) return; max = host->pio.len; if (host->pio.index < host->dma.len) { sg = &data->sg[host->pio.index]; sg_ptr = sg_virt(sg) + host->pio.offset; /* This is the space left inside the buffer */ sg_len = sg_dma_len(&data->sg[host->pio.index]) - host->pio.offset; /* Check if we need less than the size of the sg_buffer */ if (sg_len < max) max = sg_len; } if (max > AU1XMMC_MAX_TRANSFER) max = AU1XMMC_MAX_TRANSFER; for (count = 0; count < max; count++) { status = au_readl(HOST_STATUS(host)); if (!(status & SD_STATUS_NE)) break; if (status & SD_STATUS_RC) { DBG("RX CRC Error [%d + %d].\n", host->pdev->id, host->pio.len, count); break; } if (status & SD_STATUS_RO) { DBG("RX Overrun [%d + %d]\n", host->pdev->id, host->pio.len, count); break; } else if (status & SD_STATUS_RU) { DBG("RX Underrun [%d + %d]\n", host->pdev->id, host->pio.len, count); break; } val = au_readl(HOST_RXPORT(host)); if (sg_ptr) *sg_ptr++ = (unsigned char)(val & 0xFF); } host->pio.len -= count; host->pio.offset += count; if (sg_len && count == sg_len) { host->pio.index++; host->pio.offset = 0; } if (host->pio.len == 0) { /* IRQ_OFF(host, SD_CONFIG_RA | SD_CONFIG_RF); */ IRQ_OFF(host, SD_CONFIG_NE); if (host->flags & HOST_F_STOP) SEND_STOP(host); tasklet_schedule(&host->data_task); } }
/** * usb_sg_init - initializes scatterlist-based bulk/interrupt I/O request * @io: request block being initialized. until usb_sg_wait() returns, * treat this as a pointer to an opaque block of memory, * @dev: the usb device that will send or receive the data * @pipe: endpoint "pipe" used to transfer the data * @period: polling rate for interrupt endpoints, in frames or * (for high speed endpoints) microframes; ignored for bulk * @sg: scatterlist entries * @nents: how many entries in the scatterlist * @length: how many bytes to send from the scatterlist, or zero to * send every byte identified in the list. * @mem_flags: SLAB_* flags affecting memory allocations in this call * * Returns zero for success, else a negative errno value. This initializes a * scatter/gather request, allocating resources such as I/O mappings and urb * memory (except maybe memory used by USB controller drivers). * * The request must be issued using usb_sg_wait(), which waits for the I/O to * complete (or to be canceled) and then cleans up all resources allocated by * usb_sg_init(). * * The request may be canceled with usb_sg_cancel(), either before or after * usb_sg_wait() is called. */ int usb_sg_init ( struct usb_sg_request *io, struct usb_device *dev, unsigned pipe, unsigned period, struct scatterlist *sg, int nents, size_t length, int mem_flags ) { int i; int urb_flags; int dma; if (!io || !dev || !sg || usb_pipecontrol (pipe) || usb_pipeisoc (pipe) || nents <= 0) return -EINVAL; spin_lock_init (&io->lock); io->dev = dev; io->pipe = pipe; io->sg = sg; io->nents = nents; /* not all host controllers use DMA (like the mainstream pci ones); * they can use PIO (sl811) or be software over another transport. */ dma = (dev->dev.dma_mask != 0); if (dma) io->entries = usb_buffer_map_sg (dev, pipe, sg, nents); else io->entries = nents; /* initialize all the urbs we'll use */ if (io->entries <= 0) return io->entries; io->count = 0; io->urbs = kmalloc (io->entries * sizeof *io->urbs, mem_flags); if (!io->urbs) goto nomem; urb_flags = URB_ASYNC_UNLINK | URB_NO_TRANSFER_DMA_MAP | URB_NO_INTERRUPT; if (usb_pipein (pipe)) urb_flags |= URB_SHORT_NOT_OK; for (i = 0; i < io->entries; i++, io->count = i) { unsigned len; io->urbs [i] = usb_alloc_urb (0, mem_flags); if (!io->urbs [i]) { io->entries = i; goto nomem; } io->urbs [i]->dev = NULL; io->urbs [i]->pipe = pipe; io->urbs [i]->interval = period; io->urbs [i]->transfer_flags = urb_flags; io->urbs [i]->complete = sg_complete; io->urbs [i]->context = io; io->urbs [i]->status = -EINPROGRESS; io->urbs [i]->actual_length = 0; if (dma) { /* hc may use _only_ transfer_dma */ io->urbs [i]->transfer_dma = sg_dma_address (sg + i); len = sg_dma_len (sg + i); } else { /* hc may use _only_ transfer_buffer */ io->urbs [i]->transfer_buffer = page_address (sg [i].page) + sg [i].offset; len = sg [i].length; } if (length) { len = min_t (unsigned, len, length); length -= len; if (length == 0) io->entries = i + 1; } io->urbs [i]->transfer_buffer_length = len; } io->urbs [--i]->transfer_flags &= ~URB_NO_INTERRUPT; /* transaction state */ io->status = 0; io->bytes = 0; init_completion (&io->complete); return 0; nomem: sg_clean (io); return -ENOMEM; }
static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data) { struct msmsdcc_nc_dmadata *nc; dmov_box *box; uint32_t rows; uint32_t crci; unsigned int n; int i, rc; struct scatterlist *sg = data->sg; rc = validate_dma(host, data); if (rc) return rc; host->dma.sg = data->sg; host->dma.num_ents = data->sg_len; nc = host->dma.nc; if (host->pdev_id == 1) crci = MSMSDCC_CRCI_SDC1; else if (host->pdev_id == 2) crci = MSMSDCC_CRCI_SDC2; else if (host->pdev_id == 3) crci = MSMSDCC_CRCI_SDC3; else if (host->pdev_id == 4) crci = MSMSDCC_CRCI_SDC4; else { host->dma.sg = NULL; host->dma.num_ents = 0; return -ENOENT; } if (data->flags & MMC_DATA_READ) host->dma.dir = DMA_FROM_DEVICE; else host->dma.dir = DMA_TO_DEVICE; /* host->curr.user_pages = (data->flags & MMC_DATA_USERPAGE); */ host->curr.user_pages = 0; n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg, host->dma.num_ents, host->dma.dir); if (n != host->dma.num_ents) { printk(KERN_ERR "%s: Unable to map in all sg elements\n", mmc_hostname(host->mmc)); host->dma.sg = NULL; host->dma.num_ents = 0; return -ENOMEM; } box = &nc->cmd[0]; for (i = 0; i < host->dma.num_ents; i++) { box->cmd = CMD_MODE_BOX; if (i == (host->dma.num_ents - 1)) box->cmd |= CMD_LC; rows = (sg_dma_len(sg) % MCI_FIFOSIZE) ? (sg_dma_len(sg) / MCI_FIFOSIZE) + 1 : (sg_dma_len(sg) / MCI_FIFOSIZE) ; if (data->flags & MMC_DATA_READ) { box->src_row_addr = msmsdcc_fifo_addr(host); box->dst_row_addr = sg_dma_address(sg); box->src_dst_len = (MCI_FIFOSIZE << 16) | (MCI_FIFOSIZE); box->row_offset = MCI_FIFOSIZE; box->num_rows = rows * ((1 << 16) + 1); box->cmd |= CMD_SRC_CRCI(crci); } else { box->src_row_addr = sg_dma_address(sg); box->dst_row_addr = msmsdcc_fifo_addr(host); box->src_dst_len = (MCI_FIFOSIZE << 16) | (MCI_FIFOSIZE); box->row_offset = (MCI_FIFOSIZE << 16); box->num_rows = rows * ((1 << 16) + 1); box->cmd |= CMD_DST_CRCI(crci); } box++; sg++; } /* location of command block must be 64 bit aligned */ BUG_ON(host->dma.cmd_busaddr & 0x07); nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP; host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST | DMOV_CMD_ADDR(host->dma.cmdptr_busaddr); host->dma.hdr.complete_func = msmsdcc_dma_complete_func; return 0; }
/** * ixgbe_fcoe_ddp_setup - called to set up ddp context * @netdev: the corresponding net_device * @xid: the exchange id requesting ddp * @sgl: the scatter-gather list for this request * @sgc: the number of scatter-gather items * * Returns : 1 for success and 0 for no ddp */ static int ixgbe_fcoe_ddp_setup(struct net_device *netdev, u16 xid, struct scatterlist *sgl, unsigned int sgc, int target_mode) { struct ixgbe_adapter *adapter; struct ixgbe_hw *hw; struct ixgbe_fcoe *fcoe; struct ixgbe_fcoe_ddp *ddp; struct ixgbe_fcoe_ddp_pool *ddp_pool; struct scatterlist *sg; unsigned int i, j, dmacount; unsigned int len; static const unsigned int bufflen = IXGBE_FCBUFF_MIN; unsigned int firstoff = 0; unsigned int lastsize; unsigned int thisoff = 0; unsigned int thislen = 0; u32 fcbuff, fcdmarw, fcfltrw, fcrxctl; dma_addr_t addr = 0; if (!netdev || !sgl) return 0; adapter = netdev_priv(netdev); if (xid >= IXGBE_FCOE_DDP_MAX) { e_warn(drv, "xid=0x%x out-of-range\n", xid); return 0; } /* no DDP if we are already down or resetting */ if (test_bit(__IXGBE_DOWN, &adapter->state) || test_bit(__IXGBE_RESETTING, &adapter->state)) return 0; fcoe = &adapter->fcoe; ddp = &fcoe->ddp[xid]; if (ddp->sgl) { e_err(drv, "xid 0x%x w/ non-null sgl=%p nents=%d\n", xid, ddp->sgl, ddp->sgc); return 0; } ixgbe_fcoe_clear_ddp(ddp); if (!fcoe->ddp_pool) { e_warn(drv, "No ddp_pool resources allocated\n"); return 0; } ddp_pool = per_cpu_ptr(fcoe->ddp_pool, get_cpu()); if (!ddp_pool->pool) { e_warn(drv, "xid=0x%x no ddp pool for fcoe\n", xid); goto out_noddp; } /* setup dma from scsi command sgl */ dmacount = dma_map_sg(&adapter->pdev->dev, sgl, sgc, DMA_FROM_DEVICE); if (dmacount == 0) { e_err(drv, "xid 0x%x DMA map error\n", xid); goto out_noddp; } /* alloc the udl from per cpu ddp pool */ ddp->udl = dma_pool_alloc(ddp_pool->pool, GFP_ATOMIC, &ddp->udp); if (!ddp->udl) { e_err(drv, "failed allocated ddp context\n"); goto out_noddp_unmap; } ddp->pool = ddp_pool->pool; ddp->sgl = sgl; ddp->sgc = sgc; j = 0; for_each_sg(sgl, sg, dmacount, i) { addr = sg_dma_address(sg); len = sg_dma_len(sg); while (len) { /* max number of buffers allowed in one DDP context */ if (j >= IXGBE_BUFFCNT_MAX) { ddp_pool->noddp++; goto out_noddp_free; } /* get the offset of length of current buffer */ thisoff = addr & ((dma_addr_t)bufflen - 1); thislen = min((bufflen - thisoff), len); /* * all but the 1st buffer (j == 0) * must be aligned on bufflen */ if ((j != 0) && (thisoff)) goto out_noddp_free; /* * all but the last buffer * ((i == (dmacount - 1)) && (thislen == len)) * must end at bufflen */ if (((i != (dmacount - 1)) || (thislen != len)) && ((thislen + thisoff) != bufflen)) goto out_noddp_free; ddp->udl[j] = (u64)(addr - thisoff); /* only the first buffer may have none-zero offset */ if (j == 0) firstoff = thisoff; len -= thislen; addr += thislen; j++; } }
static struct dma_async_tx_descriptor *mdc_prep_slave_sg( struct dma_chan *chan, struct scatterlist *sgl, unsigned int sg_len, enum dma_transfer_direction dir, unsigned long flags, void *context) { struct mdc_chan *mchan = to_mdc_chan(chan); struct mdc_dma *mdma = mchan->mdma; struct mdc_tx_desc *mdesc; struct scatterlist *sg; struct mdc_hw_list_desc *curr, *prev = NULL; dma_addr_t curr_phys, prev_phys; unsigned int i; if (!sgl) return NULL; if (!is_slave_direction(dir)) return NULL; if (mdc_check_slave_width(mchan, dir) < 0) return NULL; mdesc = kzalloc(sizeof(*mdesc), GFP_NOWAIT); if (!mdesc) return NULL; mdesc->chan = mchan; for_each_sg(sgl, sg, sg_len, i) { dma_addr_t buf = sg_dma_address(sg); size_t buf_len = sg_dma_len(sg); while (buf_len > 0) { size_t xfer_size; curr = dma_pool_alloc(mdma->desc_pool, GFP_NOWAIT, &curr_phys); if (!curr) goto free_desc; if (!prev) { mdesc->list_phys = curr_phys; mdesc->list = curr; } else { prev->node_addr = curr_phys; prev->next_desc = curr; } xfer_size = min_t(size_t, mdma->max_xfer_size, buf_len); if (dir == DMA_MEM_TO_DEV) { mdc_list_desc_config(mchan, curr, dir, buf, mchan->config.dst_addr, xfer_size); } else { mdc_list_desc_config(mchan, curr, dir, mchan->config.src_addr, buf, xfer_size); } prev = curr; prev_phys = curr_phys; mdesc->list_len++; mdesc->list_xfer_size += xfer_size; buf += xfer_size; buf_len -= xfer_size; } }
static void s5p_set_dma_outdata(struct s5p_aes_dev *dev, struct scatterlist *sg) { SSS_WRITE(dev, FCBTDMAS, sg_dma_address(sg)); SSS_WRITE(dev, FCBTDMAL, sg_dma_len(sg)); }