mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-21 06:50:25 +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)
|
if (!adev)
|
||||||
return ERR_PTR(-ENOMEM);
|
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->isp = isp;
|
||||||
adev->ctrl = ctrl;
|
adev->ctrl = ctrl;
|
||||||
adev->pdata = pdata;
|
adev->pdata = pdata;
|
||||||
|
@ -106,10 +104,6 @@ ipu6_bus_initialize_device(struct pci_dev *pdev, struct device *parent,
|
||||||
|
|
||||||
auxdev->dev.parent = parent;
|
auxdev->dev.parent = parent;
|
||||||
auxdev->dev.release = ipu6_bus_release;
|
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);
|
ret = auxiliary_device_init(auxdev);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
|
|
||||||
#include "ipu6.h"
|
#include "ipu6.h"
|
||||||
#include "ipu6-bus.h"
|
#include "ipu6-bus.h"
|
||||||
|
#include "ipu6-dma.h"
|
||||||
#include "ipu6-buttress.h"
|
#include "ipu6-buttress.h"
|
||||||
#include "ipu6-platform-buttress-regs.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)
|
const struct firmware *fw, struct sg_table *sgt)
|
||||||
{
|
{
|
||||||
bool is_vmalloc = is_vmalloc_addr(fw->data);
|
bool is_vmalloc = is_vmalloc_addr(fw->data);
|
||||||
|
struct pci_dev *pdev = sys->isp->pdev;
|
||||||
struct page **pages;
|
struct page **pages;
|
||||||
const void *addr;
|
const void *addr;
|
||||||
unsigned long n_pages;
|
unsigned long n_pages;
|
||||||
|
@ -588,14 +590,20 @@ int ipu6_buttress_map_fw_image(struct ipu6_bus_device *sys,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = dma_map_sgtable(&sys->auxdev.dev, sgt, DMA_TO_DEVICE, 0);
|
ret = dma_map_sgtable(&pdev->dev, sgt, DMA_TO_DEVICE, 0);
|
||||||
if (ret < 0) {
|
if (ret) {
|
||||||
ret = -ENOMEM;
|
|
||||||
sg_free_table(sgt);
|
sg_free_table(sgt);
|
||||||
goto out;
|
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:
|
out:
|
||||||
kfree(pages);
|
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,
|
void ipu6_buttress_unmap_fw_image(struct ipu6_bus_device *sys,
|
||||||
struct sg_table *sgt)
|
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);
|
sg_free_table(sgt);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_NS_GPL(ipu6_buttress_unmap_fw_image, INTEL_IPU6);
|
EXPORT_SYMBOL_NS_GPL(ipu6_buttress_unmap_fw_image, INTEL_IPU6);
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include "ipu6.h"
|
#include "ipu6.h"
|
||||||
#include "ipu6-bus.h"
|
#include "ipu6-bus.h"
|
||||||
#include "ipu6-cpd.h"
|
#include "ipu6-cpd.h"
|
||||||
|
#include "ipu6-dma.h"
|
||||||
|
|
||||||
/* 15 entries + header*/
|
/* 15 entries + header*/
|
||||||
#define MAX_PKG_DIR_ENT_CNT 16
|
#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);
|
dma_addr_t dma_addr_src = sg_dma_address(adev->fw_sgt.sgl);
|
||||||
const struct ipu6_cpd_ent *ent, *man_ent, *met_ent;
|
const struct ipu6_cpd_ent *ent, *man_ent, *met_ent;
|
||||||
struct device *dev = &adev->auxdev.dev;
|
|
||||||
struct ipu6_device *isp = adev->isp;
|
struct ipu6_device *isp = adev->isp;
|
||||||
unsigned int man_sz, met_sz;
|
unsigned int man_sz, met_sz;
|
||||||
void *pkg_dir_pos;
|
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;
|
met_sz = met_ent->len;
|
||||||
|
|
||||||
adev->pkg_dir_size = PKG_DIR_SIZE + man_sz + met_sz;
|
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 = ipu6_dma_alloc(adev, adev->pkg_dir_size,
|
||||||
&adev->pkg_dir_dma_addr, GFP_KERNEL, 0);
|
&adev->pkg_dir_dma_addr, GFP_KERNEL, 0);
|
||||||
if (!adev->pkg_dir)
|
if (!adev->pkg_dir)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
@ -198,8 +198,8 @@ int ipu6_cpd_create_pkg_dir(struct ipu6_bus_device *adev, const void *src)
|
||||||
met_ent->len);
|
met_ent->len);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(&isp->pdev->dev, "Failed to parse module data\n");
|
dev_err(&isp->pdev->dev, "Failed to parse module data\n");
|
||||||
dma_free_attrs(dev, adev->pkg_dir_size,
|
ipu6_dma_free(adev, adev->pkg_dir_size,
|
||||||
adev->pkg_dir, adev->pkg_dir_dma_addr, 0);
|
adev->pkg_dir, adev->pkg_dir_dma_addr, 0);
|
||||||
return ret;
|
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;
|
pkg_dir_pos += man_sz;
|
||||||
memcpy(pkg_dir_pos, src + met_ent->offset, met_sz);
|
memcpy(pkg_dir_pos, src + met_ent->offset, met_sz);
|
||||||
|
|
||||||
dma_sync_single_range_for_device(dev, adev->pkg_dir_dma_addr,
|
ipu6_dma_sync_single(adev, adev->pkg_dir_dma_addr,
|
||||||
0, adev->pkg_dir_size, DMA_TO_DEVICE);
|
adev->pkg_dir_size);
|
||||||
|
|
||||||
return 0;
|
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)
|
void ipu6_cpd_free_pkg_dir(struct ipu6_bus_device *adev)
|
||||||
{
|
{
|
||||||
dma_free_attrs(&adev->auxdev.dev, adev->pkg_dir_size, adev->pkg_dir,
|
ipu6_dma_free(adev, adev->pkg_dir_size, adev->pkg_dir,
|
||||||
adev->pkg_dir_dma_addr, 0);
|
adev->pkg_dir_dma_addr, 0);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_NS_GPL(ipu6_cpd_free_pkg_dir, INTEL_IPU6);
|
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;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __dma_clear_buffer(struct page *page, size_t size,
|
static void __clear_buffer(struct page *page, size_t size, unsigned long attrs)
|
||||||
unsigned long attrs)
|
|
||||||
{
|
{
|
||||||
void *ptr;
|
void *ptr;
|
||||||
|
|
||||||
|
@ -56,8 +55,7 @@ static void __dma_clear_buffer(struct page *page, size_t size,
|
||||||
clflush_cache_range(ptr, size);
|
clflush_cache_range(ptr, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct page **__dma_alloc_buffer(struct device *dev, size_t size,
|
static struct page **__alloc_buffer(size_t size, gfp_t gfp, unsigned long attrs)
|
||||||
gfp_t gfp, unsigned long attrs)
|
|
||||||
{
|
{
|
||||||
int count = PHYS_PFN(size);
|
int count = PHYS_PFN(size);
|
||||||
int array_size = count * sizeof(struct page *);
|
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;
|
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;
|
i += 1 << order;
|
||||||
count -= 1 << order;
|
count -= 1 << order;
|
||||||
}
|
}
|
||||||
|
@ -100,29 +98,26 @@ error:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __dma_free_buffer(struct device *dev, struct page **pages,
|
static void __free_buffer(struct page **pages, size_t size, unsigned long attrs)
|
||||||
size_t size, unsigned long attrs)
|
|
||||||
{
|
{
|
||||||
int count = PHYS_PFN(size);
|
int count = PHYS_PFN(size);
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
for (i = 0; i < count && pages[i]; 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);
|
__free_pages(pages[i], 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
kvfree(pages);
|
kvfree(pages);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ipu6_dma_sync_single_for_cpu(struct device *dev,
|
void ipu6_dma_sync_single(struct ipu6_bus_device *sys, dma_addr_t dma_handle,
|
||||||
dma_addr_t dma_handle,
|
size_t size)
|
||||||
size_t size,
|
|
||||||
enum dma_data_direction dir)
|
|
||||||
{
|
{
|
||||||
void *vaddr;
|
void *vaddr;
|
||||||
u32 offset;
|
u32 offset;
|
||||||
struct vm_info *info;
|
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);
|
info = get_vm_info(mmu, dma_handle);
|
||||||
if (WARN_ON(!info))
|
if (WARN_ON(!info))
|
||||||
|
@ -135,10 +130,10 @@ static void ipu6_dma_sync_single_for_cpu(struct device *dev,
|
||||||
vaddr = info->vaddr + offset;
|
vaddr = info->vaddr + offset;
|
||||||
clflush_cache_range(vaddr, size);
|
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,
|
void ipu6_dma_sync_sg(struct ipu6_bus_device *sys, struct scatterlist *sglist,
|
||||||
struct scatterlist *sglist,
|
int nents)
|
||||||
int nents, enum dma_data_direction dir)
|
|
||||||
{
|
{
|
||||||
struct scatterlist *sg;
|
struct scatterlist *sg;
|
||||||
int i;
|
int i;
|
||||||
|
@ -146,14 +141,22 @@ static void ipu6_dma_sync_sg_for_cpu(struct device *dev,
|
||||||
for_each_sg(sglist, sg, nents, i)
|
for_each_sg(sglist, sg, nents, i)
|
||||||
clflush_cache_range(page_to_virt(sg_page(sg)), sg->length);
|
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,
|
void ipu6_dma_sync_sgtable(struct ipu6_bus_device *sys, struct sg_table *sgt)
|
||||||
dma_addr_t *dma_handle, gfp_t gfp,
|
|
||||||
unsigned long attrs)
|
|
||||||
{
|
{
|
||||||
struct ipu6_mmu *mmu = to_ipu6_bus_device(dev)->mmu;
|
ipu6_dma_sync_sg(sys, sgt->sgl, sgt->orig_nents);
|
||||||
struct pci_dev *pdev = to_ipu6_bus_device(dev)->isp->pdev;
|
}
|
||||||
|
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;
|
dma_addr_t pci_dma_addr, ipu6_iova;
|
||||||
|
struct ipu6_mmu *mmu = sys->mmu;
|
||||||
struct vm_info *info;
|
struct vm_info *info;
|
||||||
unsigned long count;
|
unsigned long count;
|
||||||
struct page **pages;
|
struct page **pages;
|
||||||
|
@ -173,7 +176,7 @@ static void *ipu6_dma_alloc(struct device *dev, size_t size,
|
||||||
if (!iova)
|
if (!iova)
|
||||||
goto out_kfree;
|
goto out_kfree;
|
||||||
|
|
||||||
pages = __dma_alloc_buffer(dev, size, gfp, attrs);
|
pages = __alloc_buffer(size, gfp, attrs);
|
||||||
if (!pages)
|
if (!pages)
|
||||||
goto out_free_iova;
|
goto out_free_iova;
|
||||||
|
|
||||||
|
@ -227,7 +230,7 @@ out_unmap:
|
||||||
ipu6_mmu_unmap(mmu->dmap->mmu_info, ipu6_iova, PAGE_SIZE);
|
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:
|
out_free_iova:
|
||||||
__free_iova(&mmu->dmap->iovad, iova);
|
__free_iova(&mmu->dmap->iovad, iova);
|
||||||
|
@ -236,13 +239,13 @@ out_kfree:
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL_NS_GPL(ipu6_dma_alloc, INTEL_IPU6);
|
||||||
|
|
||||||
static void ipu6_dma_free(struct device *dev, size_t size, void *vaddr,
|
void ipu6_dma_free(struct ipu6_bus_device *sys, size_t size, void *vaddr,
|
||||||
dma_addr_t dma_handle,
|
dma_addr_t dma_handle, unsigned long attrs)
|
||||||
unsigned long attrs)
|
|
||||||
{
|
{
|
||||||
struct ipu6_mmu *mmu = to_ipu6_bus_device(dev)->mmu;
|
struct ipu6_mmu *mmu = sys->mmu;
|
||||||
struct pci_dev *pdev = to_ipu6_bus_device(dev)->isp->pdev;
|
struct pci_dev *pdev = sys->isp->pdev;
|
||||||
struct iova *iova = find_iova(&mmu->dmap->iovad, PHYS_PFN(dma_handle));
|
struct iova *iova = find_iova(&mmu->dmap->iovad, PHYS_PFN(dma_handle));
|
||||||
dma_addr_t pci_dma_addr, ipu6_iova;
|
dma_addr_t pci_dma_addr, ipu6_iova;
|
||||||
struct vm_info *info;
|
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),
|
ipu6_mmu_unmap(mmu->dmap->mmu_info, PFN_PHYS(iova->pfn_lo),
|
||||||
PFN_PHYS(iova_size(iova)));
|
PFN_PHYS(iova_size(iova)));
|
||||||
|
|
||||||
__dma_free_buffer(dev, pages, size, attrs);
|
__free_buffer(pages, size, attrs);
|
||||||
|
|
||||||
mmu->tlb_invalidate(mmu);
|
mmu->tlb_invalidate(mmu);
|
||||||
|
|
||||||
|
@ -289,13 +292,14 @@ static void ipu6_dma_free(struct device *dev, size_t size, void *vaddr,
|
||||||
|
|
||||||
kfree(info);
|
kfree(info);
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL_NS_GPL(ipu6_dma_free, INTEL_IPU6);
|
||||||
|
|
||||||
static int ipu6_dma_mmap(struct device *dev, struct vm_area_struct *vma,
|
int ipu6_dma_mmap(struct ipu6_bus_device *sys, struct vm_area_struct *vma,
|
||||||
void *addr, dma_addr_t iova, size_t size,
|
void *addr, dma_addr_t iova, size_t size,
|
||||||
unsigned long attrs)
|
unsigned long attrs)
|
||||||
{
|
{
|
||||||
struct ipu6_mmu *mmu = to_ipu6_bus_device(dev)->mmu;
|
struct ipu6_mmu *mmu = sys->mmu;
|
||||||
size_t count = PHYS_PFN(PAGE_ALIGN(size));
|
size_t count = PFN_UP(size);
|
||||||
struct vm_info *info;
|
struct vm_info *info;
|
||||||
size_t i;
|
size_t i;
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -323,18 +327,17 @@ static int ipu6_dma_mmap(struct device *dev, struct vm_area_struct *vma,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ipu6_dma_unmap_sg(struct device *dev,
|
void ipu6_dma_unmap_sg(struct ipu6_bus_device *sys, struct scatterlist *sglist,
|
||||||
struct scatterlist *sglist,
|
int nents, enum dma_data_direction dir,
|
||||||
int nents, enum dma_data_direction dir,
|
unsigned long attrs)
|
||||||
unsigned long attrs)
|
|
||||||
{
|
{
|
||||||
struct pci_dev *pdev = to_ipu6_bus_device(dev)->isp->pdev;
|
struct device *dev = &sys->auxdev.dev;
|
||||||
struct ipu6_mmu *mmu = to_ipu6_bus_device(dev)->mmu;
|
struct ipu6_mmu *mmu = sys->mmu;
|
||||||
struct iova *iova = find_iova(&mmu->dmap->iovad,
|
struct iova *iova = find_iova(&mmu->dmap->iovad,
|
||||||
PHYS_PFN(sg_dma_address(sglist)));
|
PHYS_PFN(sg_dma_address(sglist)));
|
||||||
int i, npages, count;
|
|
||||||
struct scatterlist *sg;
|
struct scatterlist *sg;
|
||||||
dma_addr_t pci_dma_addr;
|
dma_addr_t pci_dma_addr;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
if (!nents)
|
if (!nents)
|
||||||
return;
|
return;
|
||||||
|
@ -342,31 +345,15 @@ static void ipu6_dma_unmap_sg(struct device *dev,
|
||||||
if (WARN_ON(!iova))
|
if (WARN_ON(!iova))
|
||||||
return;
|
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
|
* Before IPU6 mmu unmap, return the pci dma address back to sg
|
||||||
* assume the nents is less than orig_nents as the least granule
|
* assume the nents is less than orig_nents as the least granule
|
||||||
* is 1 SZ_4K page
|
* is 1 SZ_4K page
|
||||||
*/
|
*/
|
||||||
dev_dbg(dev, "trying to unmap concatenated %u ents\n", count);
|
dev_dbg(dev, "trying to unmap concatenated %u ents\n", nents);
|
||||||
for_each_sg(sglist, sg, count, i) {
|
for_each_sg(sglist, sg, nents, i) {
|
||||||
dev_dbg(dev, "ipu unmap sg[%d] %pad\n", i, &sg_dma_address(sg));
|
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,
|
pci_dma_addr = ipu6_mmu_iova_to_phys(mmu->dmap->mmu_info,
|
||||||
sg_dma_address(sg));
|
sg_dma_address(sg));
|
||||||
dev_dbg(dev, "return pci_dma_addr %pad back to sg[%d]\n",
|
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)));
|
PFN_PHYS(iova_size(iova)));
|
||||||
|
|
||||||
mmu->tlb_invalidate(mmu);
|
mmu->tlb_invalidate(mmu);
|
||||||
|
|
||||||
dma_unmap_sg_attrs(&pdev->dev, sglist, nents, dir, attrs);
|
|
||||||
|
|
||||||
__free_iova(&mmu->dmap->iovad, iova);
|
__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 ipu6_dma_map_sg(struct ipu6_bus_device *sys, struct scatterlist *sglist,
|
||||||
int nents, enum dma_data_direction dir,
|
int nents, enum dma_data_direction dir,
|
||||||
unsigned long attrs)
|
unsigned long attrs)
|
||||||
{
|
{
|
||||||
struct ipu6_mmu *mmu = to_ipu6_bus_device(dev)->mmu;
|
struct device *dev = &sys->auxdev.dev;
|
||||||
struct pci_dev *pdev = to_ipu6_bus_device(dev)->isp->pdev;
|
struct ipu6_mmu *mmu = sys->mmu;
|
||||||
struct scatterlist *sg;
|
struct scatterlist *sg;
|
||||||
struct iova *iova;
|
struct iova *iova;
|
||||||
size_t npages = 0;
|
size_t npages = 0;
|
||||||
unsigned long iova_addr;
|
unsigned long iova_addr;
|
||||||
int i, count;
|
int i;
|
||||||
|
|
||||||
for_each_sg(sglist, sg, nents, i) {
|
for_each_sg(sglist, sg, nents, i) {
|
||||||
if (sg->offset) {
|
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);
|
for_each_sg(sglist, sg, nents, i)
|
||||||
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)
|
|
||||||
npages += PHYS_PFN(PAGE_ALIGN(sg_dma_len(sg)));
|
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,
|
iova = alloc_iova(&mmu->dmap->iovad, npages,
|
||||||
PHYS_PFN(dma_get_mask(dev)), 0);
|
PHYS_PFN(dma_get_mask(dev)), 0);
|
||||||
if (!iova)
|
if (!iova)
|
||||||
|
@ -427,7 +406,7 @@ static int ipu6_dma_map_sg(struct device *dev, struct scatterlist *sglist,
|
||||||
iova->pfn_hi);
|
iova->pfn_hi);
|
||||||
|
|
||||||
iova_addr = iova->pfn_lo;
|
iova_addr = iova->pfn_lo;
|
||||||
for_each_sg(sglist, sg, count, i) {
|
for_each_sg(sglist, sg, nents, i) {
|
||||||
phys_addr_t iova_pa;
|
phys_addr_t iova_pa;
|
||||||
int ret;
|
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)));
|
iova_addr += PHYS_PFN(PAGE_ALIGN(sg_dma_len(sg)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((attrs & DMA_ATTR_SKIP_CPU_SYNC) == 0)
|
dev_dbg(dev, "dmamap %d ents %zu pages mapped\n", nents, npages);
|
||||||
ipu6_dma_sync_sg_for_cpu(dev, sglist, nents, DMA_BIDIRECTIONAL);
|
|
||||||
|
|
||||||
return count;
|
return nents;
|
||||||
|
|
||||||
out_fail:
|
out_fail:
|
||||||
ipu6_dma_unmap_sg(dev, sglist, i, dir, attrs);
|
ipu6_dma_unmap_sg(sys, sglist, i, dir, attrs);
|
||||||
|
|
||||||
return 0;
|
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
|
* Create scatter-list for the already allocated DMA buffer
|
||||||
*/
|
*/
|
||||||
static int ipu6_dma_get_sgtable(struct device *dev, struct sg_table *sgt,
|
int ipu6_dma_get_sgtable(struct ipu6_bus_device *sys, struct sg_table *sgt,
|
||||||
void *cpu_addr, dma_addr_t handle, size_t size,
|
void *cpu_addr, dma_addr_t handle, size_t size,
|
||||||
unsigned long attrs)
|
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;
|
struct vm_info *info;
|
||||||
int n_pages;
|
int n_pages;
|
||||||
int ret = 0;
|
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,
|
ret = sg_alloc_table_from_pages(sgt, info->pages, n_pages, 0, size,
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
if (ret)
|
if (ret)
|
||||||
dev_warn(dev, "IPU6 get sgt table failed\n");
|
dev_warn(dev, "get sgt table failed\n");
|
||||||
|
|
||||||
return ret;
|
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
|
#define IPU6_DMA_H
|
||||||
|
|
||||||
#include <linux/dma-map-ops.h>
|
#include <linux/dma-map-ops.h>
|
||||||
|
#include <linux/dma-mapping.h>
|
||||||
#include <linux/iova.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;
|
struct ipu6_mmu_info;
|
||||||
|
|
||||||
|
@ -14,6 +20,30 @@ struct ipu6_dma_mapping {
|
||||||
struct iova_domain iovad;
|
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 */
|
#endif /* IPU6_DMA_H */
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
|
|
||||||
#include "ipu6-bus.h"
|
#include "ipu6-bus.h"
|
||||||
|
#include "ipu6-dma.h"
|
||||||
#include "ipu6-fw-com.h"
|
#include "ipu6-fw-com.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -88,7 +89,6 @@ struct ipu6_fw_com_context {
|
||||||
void *dma_buffer;
|
void *dma_buffer;
|
||||||
dma_addr_t dma_addr;
|
dma_addr_t dma_addr;
|
||||||
unsigned int dma_size;
|
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 *input_queue; /* array of host to SP queues */
|
||||||
struct ipu6_fw_sys_queue *output_queue; /* array of SP to host */
|
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 ipu6_fw_com_context *ctx;
|
||||||
struct device *dev = &adev->auxdev.dev;
|
struct device *dev = &adev->auxdev.dev;
|
||||||
size_t sizeall, offset;
|
size_t sizeall, offset;
|
||||||
unsigned long attrs = 0;
|
|
||||||
void *specific_host_addr;
|
void *specific_host_addr;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
|
@ -206,9 +205,8 @@ void *ipu6_fw_com_prepare(struct ipu6_fw_com_cfg *cfg,
|
||||||
|
|
||||||
sizeall += sizeinput + sizeoutput;
|
sizeall += sizeinput + sizeoutput;
|
||||||
|
|
||||||
ctx->dma_buffer = dma_alloc_attrs(dev, sizeall, &ctx->dma_addr,
|
ctx->dma_buffer = ipu6_dma_alloc(adev, sizeall, &ctx->dma_addr,
|
||||||
GFP_KERNEL, attrs);
|
GFP_KERNEL, 0);
|
||||||
ctx->attrs = attrs;
|
|
||||||
if (!ctx->dma_buffer) {
|
if (!ctx->dma_buffer) {
|
||||||
dev_err(dev, "failed to allocate dma memory\n");
|
dev_err(dev, "failed to allocate dma memory\n");
|
||||||
kfree(ctx);
|
kfree(ctx);
|
||||||
|
@ -239,6 +237,8 @@ void *ipu6_fw_com_prepare(struct ipu6_fw_com_cfg *cfg,
|
||||||
memcpy(specific_host_addr, cfg->specific_addr,
|
memcpy(specific_host_addr, cfg->specific_addr,
|
||||||
cfg->specific_size);
|
cfg->specific_size);
|
||||||
|
|
||||||
|
ipu6_dma_sync_single(adev, ctx->config_vied_addr, sizeall);
|
||||||
|
|
||||||
/* initialize input queues */
|
/* initialize input queues */
|
||||||
offset += specific_size;
|
offset += specific_size;
|
||||||
res.reg = SYSCOM_QPR_BASE_REG;
|
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))
|
if (!force && !ctx->cell_ready(ctx->adev))
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
|
||||||
dma_free_attrs(&ctx->adev->auxdev.dev, ctx->dma_size,
|
ipu6_dma_free(ctx->adev, ctx->dma_size,
|
||||||
ctx->dma_buffer, ctx->dma_addr, ctx->attrs);
|
ctx->dma_buffer, ctx->dma_addr, 0);
|
||||||
kfree(ctx);
|
kfree(ctx);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue