/* * drivers/video/tegra/host/dmabuf.c * * Tegra Graphics Host DMA-BUF support * * Copyright (c) 2012, NVIDIA Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include "chip_support.h" #include "nvhost_memmgr.h" static inline struct dma_buf_attachment *to_dmabuf_att(struct mem_handle *h) { return (struct dma_buf_attachment *)(((u32)h) & ~0x3); } static inline struct dma_buf *to_dmabuf(struct mem_handle *h) { return to_dmabuf_att(h)->dmabuf; } static inline int to_dmabuf_fd(u32 id) { return nvhost_memmgr_id(id) >> 2; } struct mem_handle *nvhost_dmabuf_alloc(size_t size, size_t align, int flags) { /* TODO: Add allocation via DMA Mapping API */ return NULL; } void nvhost_dmabuf_put(struct mem_handle *handle) { struct dma_buf_attachment *attach = to_dmabuf_att(handle); struct dma_buf *dmabuf = attach->dmabuf; dma_buf_detach(dmabuf, attach); dma_buf_put(dmabuf); } struct sg_table *nvhost_dmabuf_pin(struct mem_handle *handle) { return dma_buf_map_attachment(to_dmabuf_att(handle), DMA_BIDIRECTIONAL); } void nvhost_dmabuf_unpin(struct mem_handle *handle, struct sg_table *sgt) { dma_buf_unmap_attachment(to_dmabuf_att(handle), sgt, DMA_BIDIRECTIONAL); } void *nvhost_dmabuf_mmap(struct mem_handle *handle) { return dma_buf_vmap(to_dmabuf(handle)); } void nvhost_dmabuf_munmap(struct mem_handle *handle, void *addr) { dma_buf_vunmap(to_dmabuf(handle), addr); } void *nvhost_dmabuf_kmap(struct mem_handle *handle, unsigned int pagenum) { return dma_buf_kmap(to_dmabuf(handle), pagenum); } void nvhost_dmabuf_kunmap(struct mem_handle *handle, unsigned int pagenum, void *addr) { dma_buf_kunmap(to_dmabuf(handle), pagenum, addr); } struct mem_handle *nvhost_dmabuf_get(u32 id, struct platform_device *dev) { struct mem_handle *h; struct dma_buf *buf; buf = dma_buf_get(to_dmabuf_fd(id)); if (IS_ERR_OR_NULL(buf)) return (struct mem_handle *)buf; else { h = (struct mem_handle *)dma_buf_attach(buf, &dev->dev); if (IS_ERR_OR_NULL(h)) dma_buf_put(buf); } return (struct mem_handle *) ((u32)h | mem_mgr_type_dmabuf); } int nvhost_dmabuf_pin_array_ids(struct platform_device *dev, long unsigned *ids, long unsigned id_type_mask, long unsigned id_type, u32 count, struct nvhost_job_unpin *unpin_data, dma_addr_t *phys_addr) { int i; int pin_count = 0; int err; for (i = 0; i < count; i++) { struct mem_handle *handle; struct sg_table *sgt; if ((ids[i] & id_type_mask) != id_type) continue; handle = nvhost_dmabuf_get(ids[i], dev); if (IS_ERR(handle)) { err = PTR_ERR(handle); goto fail; } sgt = nvhost_dmabuf_pin(handle); if (IS_ERR_OR_NULL(sgt)) { nvhost_dmabuf_put(handle); err = PTR_ERR(sgt); goto fail; } phys_addr[i] = sg_dma_address(sgt->sgl); unpin_data[pin_count].h = handle; unpin_data[pin_count].mem = sgt; pin_count++; } return pin_count; fail: while (pin_count) { pin_count--; nvhost_dmabuf_unpin(unpin_data[pin_count].h, unpin_data[pin_count].mem); nvhost_dmabuf_put(unpin_data[pin_count].h); } return err; }