forked from Minki/linux
dma-mapping updates for 5.12:
- add support to emulate processing delays in the DMA API benchmark selftest (Barry Song) - remove support for non-contiguous noncoherent allocations, which aren't used and will be replaced by a different API -----BEGIN PGP SIGNATURE----- iQI/BAABCgApFiEEgdbnc3r/njty3Iq9D55TZVIEUYMFAmA2A7gLHGhjaEBsc3Qu ZGUACgkQD55TZVIEUYMebw//bkSZ1v1FvGgMd+AQKKnNz+iNHH0MJAlEDhPCynFM QCPg6OtU9IU/5nmyQlO3rgZ1IW+qABCF36TqjPZar6STuTv3dzfvv9xydyOqdPNA ekFzc9FnjvWt4wzL+1pXiB/EfjKDudGAjlMyLhghl653HcLnLvE3LxgpfBMrUHbH DfSBTXt4fTK4ck8ZO6FW2LXOtLgmJvk+qglO1vs9GQv/zcRHXYkIyvqMYTlHwBlh Ltfl+kJzFHQ3taIo3utCeS5Qzctd6tbxy/Me4OHl2VydNAi8awQz4HX4yZyWYxl5 WpIGhHfD9ROKnGroaEhetUO4OczOXiqYdkt6tt5iAAUW2TFA+mgbvph3+Di/zxgl 4IxOQyhdWA38IA00YmNsoPafuuqC7WwASUfCufg+30MgHR3bpM7GyY5X84DIh3tm wlPJBMl2RqWnfxmmvjPYxV2wtN3TkA8KJN/xVcUE8aWL2mV50l1/nDdlvCbmjg60 pQt1cGP8A2hODYwLHTzadm67xc0cLrkC8nQbrnDo/FAKGmDD3aHhS95TAIr+ZoeK cgSFHNkJ1UcJ6nosCB3/MPlIJo1noAIeJnmuOIfhJn0uIof4CGQ5XQgWmJeHFLqO GlwtJAN3F3db4dxMQNn5br049wob7fgFWqMPfTGy51bZ5BClUKWGSpEonavpUMd1 oKM= =papz -----END PGP SIGNATURE----- Merge tag 'dma-mapping-5.12' of git://git.infradead.org/users/hch/dma-mapping Pull dma-mapping updates from Christoph Hellwig: - add support to emulate processing delays in the DMA API benchmark selftest (Barry Song) - remove support for non-contiguous noncoherent allocations, which aren't used and will be replaced by a different API * tag 'dma-mapping-5.12' of git://git.infradead.org/users/hch/dma-mapping: dma-mapping: remove the {alloc,free}_noncoherent methods dma-mapping: benchmark: pretend DMA is transmitting
This commit is contained in:
commit
a4dec04c7f
@ -526,46 +526,6 @@ for the kernel vs the device.
|
||||
If you don't understand how cache line coherency works between a processor and
|
||||
an I/O device, you should not be using this part of the API.
|
||||
|
||||
::
|
||||
|
||||
void *
|
||||
dma_alloc_noncoherent(struct device *dev, size_t size,
|
||||
dma_addr_t *dma_handle, enum dma_data_direction dir,
|
||||
gfp_t gfp)
|
||||
|
||||
This routine allocates a region of <size> bytes of consistent memory. It
|
||||
returns a pointer to the allocated region (in the processor's virtual address
|
||||
space) or NULL if the allocation failed. The returned memory may or may not
|
||||
be in the kernel direct mapping. Drivers must not call virt_to_page on
|
||||
the returned memory region.
|
||||
|
||||
It also returns a <dma_handle> which may be cast to an unsigned integer the
|
||||
same width as the bus and given to the device as the DMA address base of
|
||||
the region.
|
||||
|
||||
The dir parameter specified if data is read and/or written by the device,
|
||||
see dma_map_single() for details.
|
||||
|
||||
The gfp parameter allows the caller to specify the ``GFP_`` flags (see
|
||||
kmalloc()) for the allocation, but rejects flags used to specify a memory
|
||||
zone such as GFP_DMA or GFP_HIGHMEM.
|
||||
|
||||
Before giving the memory to the device, dma_sync_single_for_device() needs
|
||||
to be called, and before reading memory written by the device,
|
||||
dma_sync_single_for_cpu(), just like for streaming DMA mappings that are
|
||||
reused.
|
||||
|
||||
::
|
||||
|
||||
void
|
||||
dma_free_noncoherent(struct device *dev, size_t size, void *cpu_addr,
|
||||
dma_addr_t dma_handle, enum dma_data_direction dir)
|
||||
|
||||
Free a region of memory previously allocated using dma_alloc_noncoherent().
|
||||
dev, size and dma_handle and dir must all be the same as those passed into
|
||||
dma_alloc_noncoherent(). cpu_addr must be the virtual address returned by
|
||||
dma_alloc_noncoherent().
|
||||
|
||||
::
|
||||
|
||||
struct page *
|
||||
@ -600,9 +560,29 @@ reused.
|
||||
dma_addr_t dma_handle, enum dma_data_direction dir)
|
||||
|
||||
Free a region of memory previously allocated using dma_alloc_pages().
|
||||
dev, size and dma_handle and dir must all be the same as those passed into
|
||||
dma_alloc_noncoherent(). page must be the pointer returned by
|
||||
dma_alloc_pages().
|
||||
dev, size, dma_handle and dir must all be the same as those passed into
|
||||
dma_alloc_pages(). page must be the pointer returned by dma_alloc_pages().
|
||||
|
||||
::
|
||||
|
||||
void *
|
||||
dma_alloc_noncoherent(struct device *dev, size_t size,
|
||||
dma_addr_t *dma_handle, enum dma_data_direction dir,
|
||||
gfp_t gfp)
|
||||
|
||||
This routine is a convenient wrapper around dma_alloc_pages that returns the
|
||||
kernel virtual address for the allocated memory instead of the page structure.
|
||||
|
||||
::
|
||||
|
||||
void
|
||||
dma_free_noncoherent(struct device *dev, size_t size, void *cpu_addr,
|
||||
dma_addr_t dma_handle, enum dma_data_direction dir)
|
||||
|
||||
Free a region of memory previously allocated using dma_alloc_noncoherent().
|
||||
dev, size, dma_handle and dir must all be the same as those passed into
|
||||
dma_alloc_noncoherent(). cpu_addr must be the virtual address returned by
|
||||
dma_alloc_noncoherent().
|
||||
|
||||
::
|
||||
|
||||
|
@ -1187,34 +1187,6 @@ static void *iommu_dma_alloc(struct device *dev, size_t size,
|
||||
return cpu_addr;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DMA_REMAP
|
||||
static void *iommu_dma_alloc_noncoherent(struct device *dev, size_t size,
|
||||
dma_addr_t *handle, enum dma_data_direction dir, gfp_t gfp)
|
||||
{
|
||||
if (!gfpflags_allow_blocking(gfp)) {
|
||||
struct page *page;
|
||||
|
||||
page = dma_common_alloc_pages(dev, size, handle, dir, gfp);
|
||||
if (!page)
|
||||
return NULL;
|
||||
return page_address(page);
|
||||
}
|
||||
|
||||
return iommu_dma_alloc_remap(dev, size, handle, gfp | __GFP_ZERO,
|
||||
PAGE_KERNEL, 0);
|
||||
}
|
||||
|
||||
static void iommu_dma_free_noncoherent(struct device *dev, size_t size,
|
||||
void *cpu_addr, dma_addr_t handle, enum dma_data_direction dir)
|
||||
{
|
||||
__iommu_dma_unmap(dev, handle, size);
|
||||
__iommu_dma_free(dev, size, cpu_addr);
|
||||
}
|
||||
#else
|
||||
#define iommu_dma_alloc_noncoherent NULL
|
||||
#define iommu_dma_free_noncoherent NULL
|
||||
#endif /* CONFIG_DMA_REMAP */
|
||||
|
||||
static int iommu_dma_mmap(struct device *dev, struct vm_area_struct *vma,
|
||||
void *cpu_addr, dma_addr_t dma_addr, size_t size,
|
||||
unsigned long attrs)
|
||||
@ -1285,8 +1257,6 @@ static const struct dma_map_ops iommu_dma_ops = {
|
||||
.free = iommu_dma_free,
|
||||
.alloc_pages = dma_common_alloc_pages,
|
||||
.free_pages = dma_common_free_pages,
|
||||
.alloc_noncoherent = iommu_dma_alloc_noncoherent,
|
||||
.free_noncoherent = iommu_dma_free_noncoherent,
|
||||
.mmap = iommu_dma_mmap,
|
||||
.get_sgtable = iommu_dma_get_sgtable,
|
||||
.map_page = iommu_dma_map_page,
|
||||
|
@ -22,11 +22,6 @@ struct dma_map_ops {
|
||||
gfp_t gfp);
|
||||
void (*free_pages)(struct device *dev, size_t size, struct page *vaddr,
|
||||
dma_addr_t dma_handle, enum dma_data_direction dir);
|
||||
void *(*alloc_noncoherent)(struct device *dev, size_t size,
|
||||
dma_addr_t *dma_handle, enum dma_data_direction dir,
|
||||
gfp_t gfp);
|
||||
void (*free_noncoherent)(struct device *dev, size_t size, void *vaddr,
|
||||
dma_addr_t dma_handle, enum dma_data_direction dir);
|
||||
int (*mmap)(struct device *, struct vm_area_struct *,
|
||||
void *, dma_addr_t, size_t, unsigned long attrs);
|
||||
|
||||
|
@ -263,10 +263,19 @@ struct page *dma_alloc_pages(struct device *dev, size_t size,
|
||||
dma_addr_t *dma_handle, enum dma_data_direction dir, gfp_t gfp);
|
||||
void dma_free_pages(struct device *dev, size_t size, struct page *page,
|
||||
dma_addr_t dma_handle, enum dma_data_direction dir);
|
||||
void *dma_alloc_noncoherent(struct device *dev, size_t size,
|
||||
dma_addr_t *dma_handle, enum dma_data_direction dir, gfp_t gfp);
|
||||
void dma_free_noncoherent(struct device *dev, size_t size, void *vaddr,
|
||||
dma_addr_t dma_handle, enum dma_data_direction dir);
|
||||
|
||||
static inline void *dma_alloc_noncoherent(struct device *dev, size_t size,
|
||||
dma_addr_t *dma_handle, enum dma_data_direction dir, gfp_t gfp)
|
||||
{
|
||||
struct page *page = dma_alloc_pages(dev, size, dma_handle, dir, gfp);
|
||||
return page ? page_address(page) : NULL;
|
||||
}
|
||||
|
||||
static inline void dma_free_noncoherent(struct device *dev, size_t size,
|
||||
void *vaddr, dma_addr_t dma_handle, enum dma_data_direction dir)
|
||||
{
|
||||
dma_free_pages(dev, size, virt_to_page(vaddr), dma_handle, dir);
|
||||
}
|
||||
|
||||
static inline dma_addr_t dma_map_single_attrs(struct device *dev, void *ptr,
|
||||
size_t size, enum dma_data_direction dir, unsigned long attrs)
|
||||
|
@ -21,6 +21,7 @@
|
||||
#define DMA_MAP_BENCHMARK _IOWR('d', 1, struct map_benchmark)
|
||||
#define DMA_MAP_MAX_THREADS 1024
|
||||
#define DMA_MAP_MAX_SECONDS 300
|
||||
#define DMA_MAP_MAX_TRANS_DELAY (10 * NSEC_PER_MSEC)
|
||||
|
||||
#define DMA_MAP_BIDIRECTIONAL 0
|
||||
#define DMA_MAP_TO_DEVICE 1
|
||||
@ -36,7 +37,8 @@ struct map_benchmark {
|
||||
__s32 node; /* which numa node this benchmark will run on */
|
||||
__u32 dma_bits; /* DMA addressing capability */
|
||||
__u32 dma_dir; /* DMA data direction */
|
||||
__u8 expansion[84]; /* For future use */
|
||||
__u32 dma_trans_ns; /* time for DMA transmission in ns */
|
||||
__u8 expansion[80]; /* For future use */
|
||||
};
|
||||
|
||||
struct map_benchmark_data {
|
||||
@ -87,6 +89,9 @@ static int map_benchmark_thread(void *data)
|
||||
map_etime = ktime_get();
|
||||
map_delta = ktime_sub(map_etime, map_stime);
|
||||
|
||||
/* Pretend DMA is transmitting */
|
||||
ndelay(map->bparam.dma_trans_ns);
|
||||
|
||||
unmap_stime = ktime_get();
|
||||
dma_unmap_single(map->dev, dma_addr, PAGE_SIZE, map->dir);
|
||||
unmap_etime = ktime_get();
|
||||
@ -218,6 +223,11 @@ static long map_benchmark_ioctl(struct file *file, unsigned int cmd,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (map->bparam.dma_trans_ns > DMA_MAP_MAX_TRANS_DELAY) {
|
||||
pr_err("invalid transmission delay\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (map->bparam.node != NUMA_NO_NODE &&
|
||||
!node_possible(map->bparam.node)) {
|
||||
pr_err("invalid numa node\n");
|
||||
|
@ -517,46 +517,6 @@ void dma_free_pages(struct device *dev, size_t size, struct page *page,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dma_free_pages);
|
||||
|
||||
void *dma_alloc_noncoherent(struct device *dev, size_t size,
|
||||
dma_addr_t *dma_handle, enum dma_data_direction dir, gfp_t gfp)
|
||||
{
|
||||
const struct dma_map_ops *ops = get_dma_ops(dev);
|
||||
void *vaddr;
|
||||
|
||||
if (!ops || !ops->alloc_noncoherent) {
|
||||
struct page *page;
|
||||
|
||||
page = dma_alloc_pages(dev, size, dma_handle, dir, gfp);
|
||||
if (!page)
|
||||
return NULL;
|
||||
return page_address(page);
|
||||
}
|
||||
|
||||
size = PAGE_ALIGN(size);
|
||||
vaddr = ops->alloc_noncoherent(dev, size, dma_handle, dir, gfp);
|
||||
if (vaddr)
|
||||
debug_dma_map_page(dev, virt_to_page(vaddr), 0, size, dir,
|
||||
*dma_handle);
|
||||
return vaddr;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dma_alloc_noncoherent);
|
||||
|
||||
void dma_free_noncoherent(struct device *dev, size_t size, void *vaddr,
|
||||
dma_addr_t dma_handle, enum dma_data_direction dir)
|
||||
{
|
||||
const struct dma_map_ops *ops = get_dma_ops(dev);
|
||||
|
||||
if (!ops || !ops->free_noncoherent) {
|
||||
dma_free_pages(dev, size, virt_to_page(vaddr), dma_handle, dir);
|
||||
return;
|
||||
}
|
||||
|
||||
size = PAGE_ALIGN(size);
|
||||
debug_dma_unmap_page(dev, dma_handle, size, dir);
|
||||
ops->free_noncoherent(dev, size, vaddr, dma_handle, dir);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dma_free_noncoherent);
|
||||
|
||||
int dma_supported(struct device *dev, u64 mask)
|
||||
{
|
||||
const struct dma_map_ops *ops = get_dma_ops(dev);
|
||||
|
@ -12,9 +12,12 @@
|
||||
#include <sys/mman.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#define NSEC_PER_MSEC 1000000L
|
||||
|
||||
#define DMA_MAP_BENCHMARK _IOWR('d', 1, struct map_benchmark)
|
||||
#define DMA_MAP_MAX_THREADS 1024
|
||||
#define DMA_MAP_MAX_SECONDS 300
|
||||
#define DMA_MAP_MAX_TRANS_DELAY (10 * NSEC_PER_MSEC)
|
||||
|
||||
#define DMA_MAP_BIDIRECTIONAL 0
|
||||
#define DMA_MAP_TO_DEVICE 1
|
||||
@ -36,7 +39,8 @@ struct map_benchmark {
|
||||
__s32 node; /* which numa node this benchmark will run on */
|
||||
__u32 dma_bits; /* DMA addressing capability */
|
||||
__u32 dma_dir; /* DMA data direction */
|
||||
__u8 expansion[84]; /* For future use */
|
||||
__u32 dma_trans_ns; /* time for DMA transmission in ns */
|
||||
__u8 expansion[80]; /* For future use */
|
||||
};
|
||||
|
||||
int main(int argc, char **argv)
|
||||
@ -46,12 +50,12 @@ int main(int argc, char **argv)
|
||||
/* default single thread, run 20 seconds on NUMA_NO_NODE */
|
||||
int threads = 1, seconds = 20, node = -1;
|
||||
/* default dma mask 32bit, bidirectional DMA */
|
||||
int bits = 32, dir = DMA_MAP_BIDIRECTIONAL;
|
||||
int bits = 32, xdelay = 0, dir = DMA_MAP_BIDIRECTIONAL;
|
||||
|
||||
int cmd = DMA_MAP_BENCHMARK;
|
||||
char *p;
|
||||
|
||||
while ((opt = getopt(argc, argv, "t:s:n:b:d:")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "t:s:n:b:d:x:")) != -1) {
|
||||
switch (opt) {
|
||||
case 't':
|
||||
threads = atoi(optarg);
|
||||
@ -68,6 +72,9 @@ int main(int argc, char **argv)
|
||||
case 'd':
|
||||
dir = atoi(optarg);
|
||||
break;
|
||||
case 'x':
|
||||
xdelay = atoi(optarg);
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
@ -85,6 +92,12 @@ int main(int argc, char **argv)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (xdelay < 0 || xdelay > DMA_MAP_MAX_TRANS_DELAY) {
|
||||
fprintf(stderr, "invalid transmit delay, must be in 0-%ld\n",
|
||||
DMA_MAP_MAX_TRANS_DELAY);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* suppose the mininum DMA zone is 1MB in the world */
|
||||
if (bits < 20 || bits > 64) {
|
||||
fprintf(stderr, "invalid dma mask bit, must be in 20-64\n");
|
||||
@ -109,6 +122,8 @@ int main(int argc, char **argv)
|
||||
map.node = node;
|
||||
map.dma_bits = bits;
|
||||
map.dma_dir = dir;
|
||||
map.dma_trans_ns = xdelay;
|
||||
|
||||
if (ioctl(fd, cmd, &map)) {
|
||||
perror("ioctl");
|
||||
exit(1);
|
||||
|
Loading…
Reference in New Issue
Block a user