mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00
media: ipu6: not override the dma_ops of device in driver
DMA ops are a helper for architectures and not for drivers to override the
DMA implementation. Driver should not override the DMA implementation.
This patch removes the dma_ops override from auxiliary device and adds
driver-internal helpers that use the actual DMA mapping APIs.
Fixes: 9163d83573
("media: intel/ipu6: add IPU6 DMA mapping API and MMU table")
Signed-off-by: Bingbu Cao <bingbu.cao@intel.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
[Sakari Ailus: Fix the commit message a little.]
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
This commit is contained in:
parent
199c204bcc
commit
daabc5c647
6 changed files with 156 additions and 132 deletions
|
@ -94,8 +94,6 @@ ipu6_bus_initialize_device(struct pci_dev *pdev, struct device *parent,
|
|||
if (!adev)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
adev->dma_mask = DMA_BIT_MASK(isp->secure_mode ? IPU6_MMU_ADDR_BITS :
|
||||
IPU6_MMU_ADDR_BITS_NON_SECURE);
|
||||
adev->isp = isp;
|
||||
adev->ctrl = ctrl;
|
||||
adev->pdata = pdata;
|
||||
|
@ -106,10 +104,6 @@ ipu6_bus_initialize_device(struct pci_dev *pdev, struct device *parent,
|
|||
|
||||
auxdev->dev.parent = parent;
|
||||
auxdev->dev.release = ipu6_bus_release;
|
||||
auxdev->dev.dma_ops = &ipu6_dma_ops;
|
||||
auxdev->dev.dma_mask = &adev->dma_mask;
|
||||
auxdev->dev.dma_parms = pdev->dev.dma_parms;
|
||||
auxdev->dev.coherent_dma_mask = adev->dma_mask;
|
||||
|
||||
ret = auxiliary_device_init(auxdev);
|
||||
if (ret < 0) {
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
#include "ipu6.h"
|
||||
#include "ipu6-bus.h"
|
||||
#include "ipu6-dma.h"
|
||||
#include "ipu6-buttress.h"
|
||||
#include "ipu6-platform-buttress-regs.h"
|
||||
|
||||
|
@ -553,6 +554,7 @@ int ipu6_buttress_map_fw_image(struct ipu6_bus_device *sys,
|
|||
const struct firmware *fw, struct sg_table *sgt)
|
||||
{
|
||||
bool is_vmalloc = is_vmalloc_addr(fw->data);
|
||||
struct pci_dev *pdev = sys->isp->pdev;
|
||||
struct page **pages;
|
||||
const void *addr;
|
||||
unsigned long n_pages;
|
||||
|
@ -588,14 +590,20 @@ int ipu6_buttress_map_fw_image(struct ipu6_bus_device *sys,
|
|||
goto out;
|
||||
}
|
||||
|
||||
ret = dma_map_sgtable(&sys->auxdev.dev, sgt, DMA_TO_DEVICE, 0);
|
||||
if (ret < 0) {
|
||||
ret = -ENOMEM;
|
||||
ret = dma_map_sgtable(&pdev->dev, sgt, DMA_TO_DEVICE, 0);
|
||||
if (ret) {
|
||||
sg_free_table(sgt);
|
||||
goto out;
|
||||
}
|
||||
|
||||
dma_sync_sgtable_for_device(&sys->auxdev.dev, sgt, DMA_TO_DEVICE);
|
||||
ret = ipu6_dma_map_sgtable(sys, sgt, DMA_TO_DEVICE, 0);
|
||||
if (ret) {
|
||||
dma_unmap_sgtable(&pdev->dev, sgt, DMA_TO_DEVICE, 0);
|
||||
sg_free_table(sgt);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ipu6_dma_sync_sgtable(sys, sgt);
|
||||
|
||||
out:
|
||||
kfree(pages);
|
||||
|
@ -607,7 +615,10 @@ EXPORT_SYMBOL_NS_GPL(ipu6_buttress_map_fw_image, INTEL_IPU6);
|
|||
void ipu6_buttress_unmap_fw_image(struct ipu6_bus_device *sys,
|
||||
struct sg_table *sgt)
|
||||
{
|
||||
dma_unmap_sgtable(&sys->auxdev.dev, sgt, DMA_TO_DEVICE, 0);
|
||||
struct pci_dev *pdev = sys->isp->pdev;
|
||||
|
||||
ipu6_dma_unmap_sgtable(sys, sgt, DMA_TO_DEVICE, 0);
|
||||
dma_unmap_sgtable(&pdev->dev, sgt, DMA_TO_DEVICE, 0);
|
||||
sg_free_table(sgt);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(ipu6_buttress_unmap_fw_image, INTEL_IPU6);
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "ipu6.h"
|
||||
#include "ipu6-bus.h"
|
||||
#include "ipu6-cpd.h"
|
||||
#include "ipu6-dma.h"
|
||||
|
||||
/* 15 entries + header*/
|
||||
#define MAX_PKG_DIR_ENT_CNT 16
|
||||
|
@ -162,7 +163,6 @@ int ipu6_cpd_create_pkg_dir(struct ipu6_bus_device *adev, const void *src)
|
|||
{
|
||||
dma_addr_t dma_addr_src = sg_dma_address(adev->fw_sgt.sgl);
|
||||
const struct ipu6_cpd_ent *ent, *man_ent, *met_ent;
|
||||
struct device *dev = &adev->auxdev.dev;
|
||||
struct ipu6_device *isp = adev->isp;
|
||||
unsigned int man_sz, met_sz;
|
||||
void *pkg_dir_pos;
|
||||
|
@ -175,8 +175,8 @@ int ipu6_cpd_create_pkg_dir(struct ipu6_bus_device *adev, const void *src)
|
|||
met_sz = met_ent->len;
|
||||
|
||||
adev->pkg_dir_size = PKG_DIR_SIZE + man_sz + met_sz;
|
||||
adev->pkg_dir = dma_alloc_attrs(dev, adev->pkg_dir_size,
|
||||
&adev->pkg_dir_dma_addr, GFP_KERNEL, 0);
|
||||
adev->pkg_dir = ipu6_dma_alloc(adev, adev->pkg_dir_size,
|
||||
&adev->pkg_dir_dma_addr, GFP_KERNEL, 0);
|
||||
if (!adev->pkg_dir)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -198,8 +198,8 @@ int ipu6_cpd_create_pkg_dir(struct ipu6_bus_device *adev, const void *src)
|
|||
met_ent->len);
|
||||
if (ret) {
|
||||
dev_err(&isp->pdev->dev, "Failed to parse module data\n");
|
||||
dma_free_attrs(dev, adev->pkg_dir_size,
|
||||
adev->pkg_dir, adev->pkg_dir_dma_addr, 0);
|
||||
ipu6_dma_free(adev, adev->pkg_dir_size,
|
||||
adev->pkg_dir, adev->pkg_dir_dma_addr, 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -211,8 +211,8 @@ int ipu6_cpd_create_pkg_dir(struct ipu6_bus_device *adev, const void *src)
|
|||
pkg_dir_pos += man_sz;
|
||||
memcpy(pkg_dir_pos, src + met_ent->offset, met_sz);
|
||||
|
||||
dma_sync_single_range_for_device(dev, adev->pkg_dir_dma_addr,
|
||||
0, adev->pkg_dir_size, DMA_TO_DEVICE);
|
||||
ipu6_dma_sync_single(adev, adev->pkg_dir_dma_addr,
|
||||
adev->pkg_dir_size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -220,8 +220,8 @@ EXPORT_SYMBOL_NS_GPL(ipu6_cpd_create_pkg_dir, INTEL_IPU6);
|
|||
|
||||
void ipu6_cpd_free_pkg_dir(struct ipu6_bus_device *adev)
|
||||
{
|
||||
dma_free_attrs(&adev->auxdev.dev, adev->pkg_dir_size, adev->pkg_dir,
|
||||
adev->pkg_dir_dma_addr, 0);
|
||||
ipu6_dma_free(adev, adev->pkg_dir_size, adev->pkg_dir,
|
||||
adev->pkg_dir_dma_addr, 0);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(ipu6_cpd_free_pkg_dir, INTEL_IPU6);
|
||||
|
||||
|
|
|
@ -39,8 +39,7 @@ static struct vm_info *get_vm_info(struct ipu6_mmu *mmu, dma_addr_t iova)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static void __dma_clear_buffer(struct page *page, size_t size,
|
||||
unsigned long attrs)
|
||||
static void __clear_buffer(struct page *page, size_t size, unsigned long attrs)
|
||||
{
|
||||
void *ptr;
|
||||
|
||||
|
@ -56,8 +55,7 @@ static void __dma_clear_buffer(struct page *page, size_t size,
|
|||
clflush_cache_range(ptr, size);
|
||||
}
|
||||
|
||||
static struct page **__dma_alloc_buffer(struct device *dev, size_t size,
|
||||
gfp_t gfp, unsigned long attrs)
|
||||
static struct page **__alloc_buffer(size_t size, gfp_t gfp, unsigned long attrs)
|
||||
{
|
||||
int count = PHYS_PFN(size);
|
||||
int array_size = count * sizeof(struct page *);
|
||||
|
@ -86,7 +84,7 @@ static struct page **__dma_alloc_buffer(struct device *dev, size_t size,
|
|||
pages[i + j] = pages[i] + j;
|
||||
}
|
||||
|
||||
__dma_clear_buffer(pages[i], PAGE_SIZE << order, attrs);
|
||||
__clear_buffer(pages[i], PAGE_SIZE << order, attrs);
|
||||
i += 1 << order;
|
||||
count -= 1 << order;
|
||||
}
|
||||
|
@ -100,29 +98,26 @@ error:
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static void __dma_free_buffer(struct device *dev, struct page **pages,
|
||||
size_t size, unsigned long attrs)
|
||||
static void __free_buffer(struct page **pages, size_t size, unsigned long attrs)
|
||||
{
|
||||
int count = PHYS_PFN(size);
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < count && pages[i]; i++) {
|
||||
__dma_clear_buffer(pages[i], PAGE_SIZE, attrs);
|
||||
__clear_buffer(pages[i], PAGE_SIZE, attrs);
|
||||
__free_pages(pages[i], 0);
|
||||
}
|
||||
|
||||
kvfree(pages);
|
||||
}
|
||||
|
||||
static void ipu6_dma_sync_single_for_cpu(struct device *dev,
|
||||
dma_addr_t dma_handle,
|
||||
size_t size,
|
||||
enum dma_data_direction dir)
|
||||
void ipu6_dma_sync_single(struct ipu6_bus_device *sys, dma_addr_t dma_handle,
|
||||
size_t size)
|
||||
{
|
||||
void *vaddr;
|
||||
u32 offset;
|
||||
struct vm_info *info;
|
||||
struct ipu6_mmu *mmu = to_ipu6_bus_device(dev)->mmu;
|
||||
struct ipu6_mmu *mmu = sys->mmu;
|
||||
|
||||
info = get_vm_info(mmu, dma_handle);
|
||||
if (WARN_ON(!info))
|
||||
|
@ -135,10 +130,10 @@ static void ipu6_dma_sync_single_for_cpu(struct device *dev,
|
|||
vaddr = info->vaddr + offset;
|
||||
clflush_cache_range(vaddr, size);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(ipu6_dma_sync_single, INTEL_IPU6);
|
||||
|
||||
static void ipu6_dma_sync_sg_for_cpu(struct device *dev,
|
||||
struct scatterlist *sglist,
|
||||
int nents, enum dma_data_direction dir)
|
||||
void ipu6_dma_sync_sg(struct ipu6_bus_device *sys, struct scatterlist *sglist,
|
||||
int nents)
|
||||
{
|
||||
struct scatterlist *sg;
|
||||
int i;
|
||||
|
@ -146,14 +141,22 @@ static void ipu6_dma_sync_sg_for_cpu(struct device *dev,
|
|||
for_each_sg(sglist, sg, nents, i)
|
||||
clflush_cache_range(page_to_virt(sg_page(sg)), sg->length);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(ipu6_dma_sync_sg, INTEL_IPU6);
|
||||
|
||||
static void *ipu6_dma_alloc(struct device *dev, size_t size,
|
||||
dma_addr_t *dma_handle, gfp_t gfp,
|
||||
unsigned long attrs)
|
||||
void ipu6_dma_sync_sgtable(struct ipu6_bus_device *sys, struct sg_table *sgt)
|
||||
{
|
||||
struct ipu6_mmu *mmu = to_ipu6_bus_device(dev)->mmu;
|
||||
struct pci_dev *pdev = to_ipu6_bus_device(dev)->isp->pdev;
|
||||
ipu6_dma_sync_sg(sys, sgt->sgl, sgt->orig_nents);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(ipu6_dma_sync_sgtable, INTEL_IPU6);
|
||||
|
||||
void *ipu6_dma_alloc(struct ipu6_bus_device *sys, size_t size,
|
||||
dma_addr_t *dma_handle, gfp_t gfp,
|
||||
unsigned long attrs)
|
||||
{
|
||||
struct device *dev = &sys->auxdev.dev;
|
||||
struct pci_dev *pdev = sys->isp->pdev;
|
||||
dma_addr_t pci_dma_addr, ipu6_iova;
|
||||
struct ipu6_mmu *mmu = sys->mmu;
|
||||
struct vm_info *info;
|
||||
unsigned long count;
|
||||
struct page **pages;
|
||||
|
@ -173,7 +176,7 @@ static void *ipu6_dma_alloc(struct device *dev, size_t size,
|
|||
if (!iova)
|
||||
goto out_kfree;
|
||||
|
||||
pages = __dma_alloc_buffer(dev, size, gfp, attrs);
|
||||
pages = __alloc_buffer(size, gfp, attrs);
|
||||
if (!pages)
|
||||
goto out_free_iova;
|
||||
|
||||
|
@ -227,7 +230,7 @@ out_unmap:
|
|||
ipu6_mmu_unmap(mmu->dmap->mmu_info, ipu6_iova, PAGE_SIZE);
|
||||
}
|
||||
|
||||
__dma_free_buffer(dev, pages, size, attrs);
|
||||
__free_buffer(pages, size, attrs);
|
||||
|
||||
out_free_iova:
|
||||
__free_iova(&mmu->dmap->iovad, iova);
|
||||
|
@ -236,13 +239,13 @@ out_kfree:
|
|||
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(ipu6_dma_alloc, INTEL_IPU6);
|
||||
|
||||
static void ipu6_dma_free(struct device *dev, size_t size, void *vaddr,
|
||||
dma_addr_t dma_handle,
|
||||
unsigned long attrs)
|
||||
void ipu6_dma_free(struct ipu6_bus_device *sys, size_t size, void *vaddr,
|
||||
dma_addr_t dma_handle, unsigned long attrs)
|
||||
{
|
||||
struct ipu6_mmu *mmu = to_ipu6_bus_device(dev)->mmu;
|
||||
struct pci_dev *pdev = to_ipu6_bus_device(dev)->isp->pdev;
|
||||
struct ipu6_mmu *mmu = sys->mmu;
|
||||
struct pci_dev *pdev = sys->isp->pdev;
|
||||
struct iova *iova = find_iova(&mmu->dmap->iovad, PHYS_PFN(dma_handle));
|
||||
dma_addr_t pci_dma_addr, ipu6_iova;
|
||||
struct vm_info *info;
|
||||
|
@ -281,7 +284,7 @@ static void ipu6_dma_free(struct device *dev, size_t size, void *vaddr,
|
|||
ipu6_mmu_unmap(mmu->dmap->mmu_info, PFN_PHYS(iova->pfn_lo),
|
||||
PFN_PHYS(iova_size(iova)));
|
||||
|
||||
__dma_free_buffer(dev, pages, size, attrs);
|
||||
__free_buffer(pages, size, attrs);
|
||||
|
||||
mmu->tlb_invalidate(mmu);
|
||||
|
||||
|
@ -289,13 +292,14 @@ static void ipu6_dma_free(struct device *dev, size_t size, void *vaddr,
|
|||
|
||||
kfree(info);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(ipu6_dma_free, INTEL_IPU6);
|
||||
|
||||
static int ipu6_dma_mmap(struct device *dev, struct vm_area_struct *vma,
|
||||
void *addr, dma_addr_t iova, size_t size,
|
||||
unsigned long attrs)
|
||||
int ipu6_dma_mmap(struct ipu6_bus_device *sys, struct vm_area_struct *vma,
|
||||
void *addr, dma_addr_t iova, size_t size,
|
||||
unsigned long attrs)
|
||||
{
|
||||
struct ipu6_mmu *mmu = to_ipu6_bus_device(dev)->mmu;
|
||||
size_t count = PHYS_PFN(PAGE_ALIGN(size));
|
||||
struct ipu6_mmu *mmu = sys->mmu;
|
||||
size_t count = PFN_UP(size);
|
||||
struct vm_info *info;
|
||||
size_t i;
|
||||
int ret;
|
||||
|
@ -323,18 +327,17 @@ static int ipu6_dma_mmap(struct device *dev, struct vm_area_struct *vma,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void ipu6_dma_unmap_sg(struct device *dev,
|
||||
struct scatterlist *sglist,
|
||||
int nents, enum dma_data_direction dir,
|
||||
unsigned long attrs)
|
||||
void ipu6_dma_unmap_sg(struct ipu6_bus_device *sys, struct scatterlist *sglist,
|
||||
int nents, enum dma_data_direction dir,
|
||||
unsigned long attrs)
|
||||
{
|
||||
struct pci_dev *pdev = to_ipu6_bus_device(dev)->isp->pdev;
|
||||
struct ipu6_mmu *mmu = to_ipu6_bus_device(dev)->mmu;
|
||||
struct device *dev = &sys->auxdev.dev;
|
||||
struct ipu6_mmu *mmu = sys->mmu;
|
||||
struct iova *iova = find_iova(&mmu->dmap->iovad,
|
||||
PHYS_PFN(sg_dma_address(sglist)));
|
||||
int i, npages, count;
|
||||
struct scatterlist *sg;
|
||||
dma_addr_t pci_dma_addr;
|
||||
unsigned int i;
|
||||
|
||||
if (!nents)
|
||||
return;
|
||||
|
@ -342,31 +345,15 @@ static void ipu6_dma_unmap_sg(struct device *dev,
|
|||
if (WARN_ON(!iova))
|
||||
return;
|
||||
|
||||
if ((attrs & DMA_ATTR_SKIP_CPU_SYNC) == 0)
|
||||
ipu6_dma_sync_sg_for_cpu(dev, sglist, nents, DMA_BIDIRECTIONAL);
|
||||
|
||||
/* get the nents as orig_nents given by caller */
|
||||
count = 0;
|
||||
npages = iova_size(iova);
|
||||
for_each_sg(sglist, sg, nents, i) {
|
||||
if (sg_dma_len(sg) == 0 ||
|
||||
sg_dma_address(sg) == DMA_MAPPING_ERROR)
|
||||
break;
|
||||
|
||||
npages -= PHYS_PFN(PAGE_ALIGN(sg_dma_len(sg)));
|
||||
count++;
|
||||
if (npages <= 0)
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Before IPU6 mmu unmap, return the pci dma address back to sg
|
||||
* assume the nents is less than orig_nents as the least granule
|
||||
* is 1 SZ_4K page
|
||||
*/
|
||||
dev_dbg(dev, "trying to unmap concatenated %u ents\n", count);
|
||||
for_each_sg(sglist, sg, count, i) {
|
||||
dev_dbg(dev, "ipu unmap sg[%d] %pad\n", i, &sg_dma_address(sg));
|
||||
dev_dbg(dev, "trying to unmap concatenated %u ents\n", nents);
|
||||
for_each_sg(sglist, sg, nents, i) {
|
||||
dev_dbg(dev, "unmap sg[%d] %pad size %u\n", i,
|
||||
&sg_dma_address(sg), sg_dma_len(sg));
|
||||
pci_dma_addr = ipu6_mmu_iova_to_phys(mmu->dmap->mmu_info,
|
||||
sg_dma_address(sg));
|
||||
dev_dbg(dev, "return pci_dma_addr %pad back to sg[%d]\n",
|
||||
|
@ -380,23 +367,21 @@ static void ipu6_dma_unmap_sg(struct device *dev,
|
|||
PFN_PHYS(iova_size(iova)));
|
||||
|
||||
mmu->tlb_invalidate(mmu);
|
||||
|
||||
dma_unmap_sg_attrs(&pdev->dev, sglist, nents, dir, attrs);
|
||||
|
||||
__free_iova(&mmu->dmap->iovad, iova);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(ipu6_dma_unmap_sg, INTEL_IPU6);
|
||||
|
||||
static int ipu6_dma_map_sg(struct device *dev, struct scatterlist *sglist,
|
||||
int nents, enum dma_data_direction dir,
|
||||
unsigned long attrs)
|
||||
int ipu6_dma_map_sg(struct ipu6_bus_device *sys, struct scatterlist *sglist,
|
||||
int nents, enum dma_data_direction dir,
|
||||
unsigned long attrs)
|
||||
{
|
||||
struct ipu6_mmu *mmu = to_ipu6_bus_device(dev)->mmu;
|
||||
struct pci_dev *pdev = to_ipu6_bus_device(dev)->isp->pdev;
|
||||
struct device *dev = &sys->auxdev.dev;
|
||||
struct ipu6_mmu *mmu = sys->mmu;
|
||||
struct scatterlist *sg;
|
||||
struct iova *iova;
|
||||
size_t npages = 0;
|
||||
unsigned long iova_addr;
|
||||
int i, count;
|
||||
int i;
|
||||
|
||||
for_each_sg(sglist, sg, nents, i) {
|
||||
if (sg->offset) {
|
||||
|
@ -406,18 +391,12 @@ static int ipu6_dma_map_sg(struct device *dev, struct scatterlist *sglist,
|
|||
}
|
||||
}
|
||||
|
||||
dev_dbg(dev, "pci_dma_map_sg trying to map %d ents\n", nents);
|
||||
count = dma_map_sg_attrs(&pdev->dev, sglist, nents, dir, attrs);
|
||||
if (count <= 0) {
|
||||
dev_err(dev, "pci_dma_map_sg %d ents failed\n", nents);
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev_dbg(dev, "pci_dma_map_sg %d ents mapped\n", count);
|
||||
|
||||
for_each_sg(sglist, sg, count, i)
|
||||
for_each_sg(sglist, sg, nents, i)
|
||||
npages += PHYS_PFN(PAGE_ALIGN(sg_dma_len(sg)));
|
||||
|
||||
dev_dbg(dev, "dmamap trying to map %d ents %zu pages\n",
|
||||
nents, npages);
|
||||
|
||||
iova = alloc_iova(&mmu->dmap->iovad, npages,
|
||||
PHYS_PFN(dma_get_mask(dev)), 0);
|
||||
if (!iova)
|
||||
|
@ -427,7 +406,7 @@ static int ipu6_dma_map_sg(struct device *dev, struct scatterlist *sglist,
|
|||
iova->pfn_hi);
|
||||
|
||||
iova_addr = iova->pfn_lo;
|
||||
for_each_sg(sglist, sg, count, i) {
|
||||
for_each_sg(sglist, sg, nents, i) {
|
||||
phys_addr_t iova_pa;
|
||||
int ret;
|
||||
|
||||
|
@ -446,25 +425,48 @@ static int ipu6_dma_map_sg(struct device *dev, struct scatterlist *sglist,
|
|||
iova_addr += PHYS_PFN(PAGE_ALIGN(sg_dma_len(sg)));
|
||||
}
|
||||
|
||||
if ((attrs & DMA_ATTR_SKIP_CPU_SYNC) == 0)
|
||||
ipu6_dma_sync_sg_for_cpu(dev, sglist, nents, DMA_BIDIRECTIONAL);
|
||||
dev_dbg(dev, "dmamap %d ents %zu pages mapped\n", nents, npages);
|
||||
|
||||
return count;
|
||||
return nents;
|
||||
|
||||
out_fail:
|
||||
ipu6_dma_unmap_sg(dev, sglist, i, dir, attrs);
|
||||
ipu6_dma_unmap_sg(sys, sglist, i, dir, attrs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(ipu6_dma_map_sg, INTEL_IPU6);
|
||||
|
||||
int ipu6_dma_map_sgtable(struct ipu6_bus_device *sys, struct sg_table *sgt,
|
||||
enum dma_data_direction dir, unsigned long attrs)
|
||||
{
|
||||
int nents;
|
||||
|
||||
nents = ipu6_dma_map_sg(sys, sgt->sgl, sgt->nents, dir, attrs);
|
||||
if (nents < 0)
|
||||
return nents;
|
||||
|
||||
sgt->nents = nents;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(ipu6_dma_map_sgtable, INTEL_IPU6);
|
||||
|
||||
void ipu6_dma_unmap_sgtable(struct ipu6_bus_device *sys, struct sg_table *sgt,
|
||||
enum dma_data_direction dir, unsigned long attrs)
|
||||
{
|
||||
ipu6_dma_unmap_sg(sys, sgt->sgl, sgt->nents, dir, attrs);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(ipu6_dma_unmap_sgtable, INTEL_IPU6);
|
||||
|
||||
/*
|
||||
* Create scatter-list for the already allocated DMA buffer
|
||||
*/
|
||||
static int ipu6_dma_get_sgtable(struct device *dev, struct sg_table *sgt,
|
||||
void *cpu_addr, dma_addr_t handle, size_t size,
|
||||
unsigned long attrs)
|
||||
int ipu6_dma_get_sgtable(struct ipu6_bus_device *sys, struct sg_table *sgt,
|
||||
void *cpu_addr, dma_addr_t handle, size_t size,
|
||||
unsigned long attrs)
|
||||
{
|
||||
struct ipu6_mmu *mmu = to_ipu6_bus_device(dev)->mmu;
|
||||
struct device *dev = &sys->auxdev.dev;
|
||||
struct ipu6_mmu *mmu = sys->mmu;
|
||||
struct vm_info *info;
|
||||
int n_pages;
|
||||
int ret = 0;
|
||||
|
@ -484,20 +486,7 @@ static int ipu6_dma_get_sgtable(struct device *dev, struct sg_table *sgt,
|
|||
ret = sg_alloc_table_from_pages(sgt, info->pages, n_pages, 0, size,
|
||||
GFP_KERNEL);
|
||||
if (ret)
|
||||
dev_warn(dev, "IPU6 get sgt table failed\n");
|
||||
dev_warn(dev, "get sgt table failed\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
const struct dma_map_ops ipu6_dma_ops = {
|
||||
.alloc = ipu6_dma_alloc,
|
||||
.free = ipu6_dma_free,
|
||||
.mmap = ipu6_dma_mmap,
|
||||
.map_sg = ipu6_dma_map_sg,
|
||||
.unmap_sg = ipu6_dma_unmap_sg,
|
||||
.sync_single_for_cpu = ipu6_dma_sync_single_for_cpu,
|
||||
.sync_single_for_device = ipu6_dma_sync_single_for_cpu,
|
||||
.sync_sg_for_cpu = ipu6_dma_sync_sg_for_cpu,
|
||||
.sync_sg_for_device = ipu6_dma_sync_sg_for_cpu,
|
||||
.get_sgtable = ipu6_dma_get_sgtable,
|
||||
};
|
||||
|
|
|
@ -5,7 +5,13 @@
|
|||
#define IPU6_DMA_H
|
||||
|
||||
#include <linux/dma-map-ops.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/iova.h>
|
||||
#include <linux/iova.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "ipu6-bus.h"
|
||||
|
||||
struct ipu6_mmu_info;
|
||||
|
||||
|
@ -14,6 +20,30 @@ struct ipu6_dma_mapping {
|
|||
struct iova_domain iovad;
|
||||
};
|
||||
|
||||
extern const struct dma_map_ops ipu6_dma_ops;
|
||||
|
||||
void ipu6_dma_sync_single(struct ipu6_bus_device *sys, dma_addr_t dma_handle,
|
||||
size_t size);
|
||||
void ipu6_dma_sync_sg(struct ipu6_bus_device *sys, struct scatterlist *sglist,
|
||||
int nents);
|
||||
void ipu6_dma_sync_sgtable(struct ipu6_bus_device *sys, struct sg_table *sgt);
|
||||
void *ipu6_dma_alloc(struct ipu6_bus_device *sys, size_t size,
|
||||
dma_addr_t *dma_handle, gfp_t gfp,
|
||||
unsigned long attrs);
|
||||
void ipu6_dma_free(struct ipu6_bus_device *sys, size_t size, void *vaddr,
|
||||
dma_addr_t dma_handle, unsigned long attrs);
|
||||
int ipu6_dma_mmap(struct ipu6_bus_device *sys, struct vm_area_struct *vma,
|
||||
void *addr, dma_addr_t iova, size_t size,
|
||||
unsigned long attrs);
|
||||
int ipu6_dma_map_sg(struct ipu6_bus_device *sys, struct scatterlist *sglist,
|
||||
int nents, enum dma_data_direction dir,
|
||||
unsigned long attrs);
|
||||
void ipu6_dma_unmap_sg(struct ipu6_bus_device *sys, struct scatterlist *sglist,
|
||||
int nents, enum dma_data_direction dir,
|
||||
unsigned long attrs);
|
||||
int ipu6_dma_map_sgtable(struct ipu6_bus_device *sys, struct sg_table *sgt,
|
||||
enum dma_data_direction dir, unsigned long attrs);
|
||||
void ipu6_dma_unmap_sgtable(struct ipu6_bus_device *sys, struct sg_table *sgt,
|
||||
enum dma_data_direction dir, unsigned long attrs);
|
||||
int ipu6_dma_get_sgtable(struct ipu6_bus_device *sys, struct sg_table *sgt,
|
||||
void *cpu_addr, dma_addr_t handle, size_t size,
|
||||
unsigned long attrs);
|
||||
#endif /* IPU6_DMA_H */
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include <linux/types.h>
|
||||
|
||||
#include "ipu6-bus.h"
|
||||
#include "ipu6-dma.h"
|
||||
#include "ipu6-fw-com.h"
|
||||
|
||||
/*
|
||||
|
@ -88,7 +89,6 @@ struct ipu6_fw_com_context {
|
|||
void *dma_buffer;
|
||||
dma_addr_t dma_addr;
|
||||
unsigned int dma_size;
|
||||
unsigned long attrs;
|
||||
|
||||
struct ipu6_fw_sys_queue *input_queue; /* array of host to SP queues */
|
||||
struct ipu6_fw_sys_queue *output_queue; /* array of SP to host */
|
||||
|
@ -164,7 +164,6 @@ void *ipu6_fw_com_prepare(struct ipu6_fw_com_cfg *cfg,
|
|||
struct ipu6_fw_com_context *ctx;
|
||||
struct device *dev = &adev->auxdev.dev;
|
||||
size_t sizeall, offset;
|
||||
unsigned long attrs = 0;
|
||||
void *specific_host_addr;
|
||||
unsigned int i;
|
||||
|
||||
|
@ -206,9 +205,8 @@ void *ipu6_fw_com_prepare(struct ipu6_fw_com_cfg *cfg,
|
|||
|
||||
sizeall += sizeinput + sizeoutput;
|
||||
|
||||
ctx->dma_buffer = dma_alloc_attrs(dev, sizeall, &ctx->dma_addr,
|
||||
GFP_KERNEL, attrs);
|
||||
ctx->attrs = attrs;
|
||||
ctx->dma_buffer = ipu6_dma_alloc(adev, sizeall, &ctx->dma_addr,
|
||||
GFP_KERNEL, 0);
|
||||
if (!ctx->dma_buffer) {
|
||||
dev_err(dev, "failed to allocate dma memory\n");
|
||||
kfree(ctx);
|
||||
|
@ -239,6 +237,8 @@ void *ipu6_fw_com_prepare(struct ipu6_fw_com_cfg *cfg,
|
|||
memcpy(specific_host_addr, cfg->specific_addr,
|
||||
cfg->specific_size);
|
||||
|
||||
ipu6_dma_sync_single(adev, ctx->config_vied_addr, sizeall);
|
||||
|
||||
/* initialize input queues */
|
||||
offset += specific_size;
|
||||
res.reg = SYSCOM_QPR_BASE_REG;
|
||||
|
@ -315,8 +315,8 @@ int ipu6_fw_com_release(struct ipu6_fw_com_context *ctx, unsigned int force)
|
|||
if (!force && !ctx->cell_ready(ctx->adev))
|
||||
return -EBUSY;
|
||||
|
||||
dma_free_attrs(&ctx->adev->auxdev.dev, ctx->dma_size,
|
||||
ctx->dma_buffer, ctx->dma_addr, ctx->attrs);
|
||||
ipu6_dma_free(ctx->adev, ctx->dma_size,
|
||||
ctx->dma_buffer, ctx->dma_addr, 0);
|
||||
kfree(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue