summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSuren A. Chilingaryan <csa@dside.dyndns.org>2012-11-12 17:11:05 +0100
committerSuren A. Chilingaryan <csa@dside.dyndns.org>2012-11-12 17:11:05 +0100
commit273c238f85be99e7ac01a05cfdd6d3176ed0e7ad (patch)
treef56d95b4c5b00e0a88bd07b22a4195cf4d898fe4
parent595066585f3100babefab816d8460bde1edcf260 (diff)
downloadpcitool-273c238f85be99e7ac01a05cfdd6d3176ed0e7ad.tar.gz
pcitool-273c238f85be99e7ac01a05cfdd6d3176ed0e7ad.tar.bz2
pcitool-273c238f85be99e7ac01a05cfdd6d3176ed0e7ad.tar.xz
pcitool-273c238f85be99e7ac01a05cfdd6d3176ed0e7ad.zip
Kernel memory allocation
-rw-r--r--cli.c187
-rw-r--r--kmem.c16
-rw-r--r--kmem.h2
-rw-r--r--pcilib_types.h3
4 files changed, 195 insertions, 13 deletions
diff --git a/cli.c b/cli.c
index 6b831e9..852b82c 100644
--- a/cli.c
+++ b/cli.c
@@ -77,6 +77,7 @@ typedef enum {
MODE_LIST_DMA_BUFFERS,
MODE_READ_DMA_BUFFER,
MODE_WAIT_IRQ,
+ MODE_ALLOC_KMEM,
MODE_LIST_KMEM,
MODE_READ_KMEM,
MODE_FREE_KMEM
@@ -142,9 +143,13 @@ typedef enum {
OPT_STOP_DMA,
OPT_WAIT_IRQ,
OPT_ITERATIONS,
+ OPT_ALLOC_KMEM,
OPT_LIST_KMEM,
OPT_FREE_KMEM,
OPT_READ_KMEM,
+ OPT_BLOCK_SIZE,
+ OPT_ALIGNMENT,
+ OPT_TYPE,
OPT_FORCE,
OPT_VERIFY,
OPT_WAIT,
@@ -184,9 +189,13 @@ static struct option long_options[] = {
{"list-dma-buffers", required_argument, 0, OPT_LIST_DMA_BUFFERS },
{"read-dma-buffer", required_argument, 0, OPT_READ_DMA_BUFFER },
{"wait-irq", optional_argument, 0, OPT_WAIT_IRQ },
- {"list-kernel-memory", no_argument, 0, OPT_LIST_KMEM },
+ {"list-kernel-memory", optional_argument, 0, OPT_LIST_KMEM },
{"read-kernel-memory", required_argument, 0, OPT_READ_KMEM },
+ {"alloc-kernel-memory", required_argument, 0, OPT_ALLOC_KMEM },
{"free-kernel-memory", required_argument, 0, OPT_FREE_KMEM },
+ {"type", required_argument, 0, OPT_TYPE },
+ {"block-size", required_argument, 0, OPT_BLOCK_SIZE },
+ {"alignment", required_argument, 0, OPT_ALIGNMENT },
{"quiete", no_argument, 0, OPT_QUIETE },
{"verbose", optional_argument, 0, OPT_VERBOSE },
{"force", no_argument, 0, OPT_FORCE },
@@ -237,12 +246,20 @@ void Usage(int argc, char *argv[], const char *format, ...) {
" --wait-irq <source> - Wait for IRQ\n"
"\n"
" Kernel Modes:\n"
-" --list-kernel-memory - List kernel buffers\n"
+" --list-kernel-memory [use] - List kernel buffers\n"
" --read-kernel-memory <blk> - Read the specified block of the kernel memory\n"
" block is specified as: use:block_number\n"
+" --alloc-kernel-memory <use> - Allocate kernel buffers (DANGEROUS)\n"
" --free-kernel-memory <use> - Cleans lost kernel space buffers (DANGEROUS)\n"
" dma - Remove all buffers allocated by DMA subsystem\n"
" #number - Remove all buffers with the specified use id\n"
+" --type <type> - Type of kernel memory to allocate\n"
+" consistent - Consistent memory\n"
+" s2c - DMA S2C (write) memory\n"
+" c2s - DMA C2S (read) memory\n"
+" --page-size <size> - Size of kernel buffer in bytes (default: page)\n"
+" -s <size> - Number of buffers to allocate (default: 1)\n"
+" --allignment <alignment> - Buffer alignment (default: page)\n"
"\n"
" Addressing:\n"
" -d <device> - FPGA device (/dev/fpga0)\n"
@@ -1765,17 +1782,27 @@ size_t FindUse(size_t *n_uses, kmem_use_info_t *uses, unsigned long use) {
return (*n_uses)++;
}
-int ListKMEM(pcilib_t *handle, const char *device) {
+kmem_use_info_t *GetUse(size_t n_uses, kmem_use_info_t *uses, unsigned long use) {
+ size_t i;
+ for (i = 0; i < n_uses; i++) {
+ if (uses[i].use == use) {
+ if (uses[i].count) return uses + i;
+ else return NULL;
+ }
+ }
+ return NULL;
+}
+
+
+int ParseKMEM(pcilib_t *handle, const char *device, size_t *uses_number, kmem_use_info_t *uses) {
DIR *dir;
struct dirent *entry;
const char *pos;
char sysdir[256];
char fname[256];
char info[256];
- char stmp[256];
-
- size_t useid, i, n_uses = 1; // Use 0 is for others
- kmem_use_info_t uses[MAX_USES];
+
+ size_t useid, n_uses = 1; // Use 0 is for others
memset(uses, 0, sizeof(uses));
@@ -1824,6 +1851,21 @@ int ListKMEM(pcilib_t *handle, const char *device) {
}
closedir(dir);
+ *uses_number = n_uses;
+
+ return 0;
+}
+
+int ListKMEM(pcilib_t *handle, const char *device) {
+ int err;
+ char stmp[256];
+
+ size_t i, useid, n_uses;
+ kmem_use_info_t uses[MAX_USES];
+
+ err = ParseKMEM(handle, device, &n_uses, uses);
+ if (err) Error("Failed to parse kernel memory information provided through sysfs");
+
if ((n_uses == 1)&&(uses[0].count == 0)) {
printf("No kernel memory is allocated\n");
return 0;
@@ -1841,6 +1883,7 @@ int ListKMEM(pcilib_t *handle, const char *device) {
if (!i) printf("All Others ");
else if ((uses[i].use >> 16) == PCILIB_KMEM_USE_DMA_RING) printf("DMA%lu %s Ring ", uses[i].use&0x7F, ((uses[i].use&0x80)?"S2C":"C2S"));
else if ((uses[i].use >> 16) == PCILIB_KMEM_USE_DMA_PAGES) printf("DMA%lu %s Pages ", uses[i].use&0x7F, ((uses[i].use&0x80)?"S2C":"C2S"));
+ else if ((uses[i].use >> 16) == PCILIB_KMEM_USE_USER) printf("User %04lx ", uses[i].use&0xFFFF);
else printf (" ");
printf(" ");
printf("% 6lu", uses[i].count);
@@ -1865,11 +1908,59 @@ int ListKMEM(pcilib_t *handle, const char *device) {
return 0;
}
+int DetailKMEM(pcilib_t *handle, const char *device, pcilib_kmem_use_t use, size_t block) {
+ int err;
+ void *data;
+ size_t size;
+ size_t i, n;
+ pcilib_kmem_handle_t *kbuf;
+
+ size_t n_uses;
+ kmem_use_info_t uses[MAX_USES];
+ kmem_use_info_t *use_info;
+
+ if (block == (size_t)-1) {
+ err = ParseKMEM(handle, device, &n_uses, uses);
+ if (err) Error("Failed to parse kernel memory information provided through sysfs");
+ use_info = GetUse(n_uses, uses, use);
+ if (!use_info) Error("No kernel buffers is allocated for the specified use (%lx)", use);
+
+ i = 0;
+ n = use_info->count;
+ } else {
+ i = block;
+ n = block + 1;
+ }
+
+ kbuf = pcilib_alloc_kernel_memory(handle, 0, n, 0, 0, use, PCILIB_KMEM_FLAG_REUSE|PCILIB_KMEM_FLAG_TRY);
+ if (!kbuf) {
+ Error("Allocation of kernel buffer (use %lx, count %lu) is failed\n", use, n);
+ return 0;
+ }
+
+ printf("Buffer Address Hardware Address Bus Address\n");
+ printf("--------------------------------------------------------------------------------\n");
+ for (; i < n; i++) {
+ void *data = pcilib_kmem_get_block_ua(handle, kbuf, i);
+ uintptr_t pa = pcilib_kmem_get_block_pa(handle, kbuf, i);
+ uintptr_t ba = pcilib_kmem_get_block_ba(handle, kbuf, i);
+ printf("%6lu %16p %16lx %16lx\n", i, data, pa, ba);
+ }
+ printf("\n");
+
+ pcilib_free_kernel_memory(handle, kbuf, KMEM_FLAG_REUSE);
+
+ return 0;
+}
+
+
int ReadKMEM(pcilib_t *handle, const char *device, pcilib_kmem_use_t use, size_t block, size_t max_size, FILE *o) {
int err;
void *data;
size_t size;
pcilib_kmem_handle_t *kbuf;
+
+ if (block == (size_t)-1) block = 0;
kbuf = pcilib_alloc_kernel_memory(handle, 0, block + 1, 0, 0, use, PCILIB_KMEM_FLAG_REUSE|PCILIB_KMEM_FLAG_TRY);
if (!kbuf) {
@@ -1901,6 +1992,36 @@ int ReadKMEM(pcilib_t *handle, const char *device, pcilib_kmem_use_t use, size_t
return 0;
}
+int AllocKMEM(pcilib_t *handle, const char *device, const char *use, const char *type, size_t size, size_t block_size, size_t alignment) {
+ int err;
+ unsigned long useid;
+ pcilib_kmem_type_t ktype = PCILIB_KMEM_TYPE_PAGE;
+ pcilib_kmem_flags_t flags = KMEM_FLAG_REUSE;
+ pcilib_kmem_handle_t *kbuf;
+
+ long page_size = sysconf(_SC_PAGESIZE);
+
+ if ((!isxnumber(use))||(sscanf(use, "%lx", &useid) != 1)) Error("Invalid use (%s) is specified", use);
+ if ((useid&PCILIB_KMEM_TYPE_MASK) == 0) useid = PCILIB_KMEM_USE(PCILIB_KMEM_USE_USER,useid);
+
+ if (type) {
+ if (!strcmp(type, "consistent")) ktype = PCILIB_KMEM_TYPE_CONSISTENT;
+ else if (!strcmp(type, "c2s")) ktype = PCILIB_KMEM_TYPE_DMA_C2S_PAGE;
+ else if (!strcmp(type, "s2c")) ktype = PCILIB_KMEM_TYPE_DMA_S2C_PAGE;
+ else Error("Invalid memory type (%s) is specified", type);
+ }
+
+ if ((block_size)&&(ktype != PCILIB_KMEM_TYPE_CONSISTENT))
+ Error("Selected memory type does not allow custom size");
+
+ kbuf = pcilib_alloc_kernel_memory(handle, ktype, size, (block_size?block_size:page_size), (alignment?alignment:page_size), useid, flags|KMEM_FLAG_PERSISTENT);
+ if (!kbuf) Error("Allocation of kernel memory has failed");
+
+ pcilib_free_kernel_memory(handle, kbuf, flags);
+
+ return 0;
+}
+
int FreeKMEM(pcilib_t *handle, const char *device, const char *use, int force) {
int err;
int i;
@@ -2172,18 +2293,20 @@ int main(int argc, char **argv) {
const char *dma_channel = NULL;
const char *use = NULL;
pcilib_kmem_use_t use_id = 0;
- size_t block = 0;
+ size_t block = (size_t)-1;
pcilib_irq_hw_source_t irq_source = PCILIB_IRQ_SOURCE_DEFAULT;
pcilib_dma_direction_t dma_direction = PCILIB_DMA_BIDIRECTIONAL;
pcilib_dma_engine_addr_t dma = PCILIB_DMA_ENGINE_ADDR_INVALID;
long addr_shift = 0;
uintptr_t start = -1;
+ size_t block_size = 0;
size_t size = 1;
access_t access = 4;
// int skip = 0;
int endianess = 0;
size_t timeout = 0;
+ size_t alignment = 0;
const char *output = NULL;
FILE *ofile = NULL;
size_t iterations = BENCHMARK_ITERATIONS;
@@ -2327,6 +2450,28 @@ int main(int argc, char **argv) {
case OPT_LIST_KMEM:
if (mode != MODE_INVALID) Usage(argc, argv, "Multiple operations are not supported");
mode = MODE_LIST_KMEM;
+
+ if (optarg) use = optarg;
+ else if ((optind < argc)&&(argv[optind][0] != '-')) use = argv[optind++];
+
+ if (use) {
+ num_offset = strchr(use, ':');
+
+ if (num_offset) {
+ if (sscanf(num_offset + 1, "%zu", &block) != 1)
+ Usage(argc, argv, "Invalid block number is specified (%s)", num_offset + 1);
+
+ *(char*)num_offset = 0;
+ }
+
+ if (sscanf(use, "%lx", &utmp) != 1)
+ Usage(argc, argv, "Invalid USE number is specified (%s)", optarg);
+
+ if (!utmp)
+ Usage(argc, argv, "Can't detail memory with the unspecific use (use number is 0)");
+
+ use_id = utmp;
+ }
break;
case OPT_READ_KMEM:
if (mode != MODE_INVALID) Usage(argc, argv, "Multiple operations are not supported");
@@ -2349,6 +2494,13 @@ int main(int argc, char **argv) {
use_id = utmp;
break;
+ case OPT_ALLOC_KMEM:
+ if (mode != MODE_INVALID) Usage(argc, argv, "Multiple operations are not supported");
+ mode = MODE_ALLOC_KMEM;
+
+ if (optarg) use = optarg;
+ else if ((optind < argc)&&(argv[optind][0] != '-')) use = argv[optind++];
+ break;
case OPT_FREE_KMEM:
if (mode != MODE_INVALID) Usage(argc, argv, "Multiple operations are not supported");
mode = MODE_FREE_KMEM;
@@ -2369,6 +2521,11 @@ int main(int argc, char **argv) {
// if ((sscanf(optarg,"%li", &itmp) != 1)||(itmp < 0)||(itmp >= PCILIB_MAX_BANKS)) Usage(argc, argv, "Invalid data bank (%s) is specified", optarg);
// else bar = itmp;
break;
+ case OPT_ALIGNMENT:
+ if ((!isnumber(optarg))||(sscanf(optarg, "%zu", &alignment) != 1)) {
+ Usage(argc, argv, "Invalid alignment is specified (%s)", optarg);
+ }
+ break;
case OPT_ACCESS:
if (!strncasecmp(optarg, "fifo", 4)) {
type = "fifo";
@@ -2413,6 +2570,11 @@ int main(int argc, char **argv) {
size_set = 1;
break;
+ case OPT_BLOCK_SIZE:
+ if ((!isnumber(optarg))||(sscanf(optarg, "%zu", &block_size) != 1)) {
+ Usage(argc, argv, "Invalid size is specified (%s)", optarg);
+ }
+ break;
case OPT_ENDIANESS:
if ((*optarg == 'b')||(*optarg == 'B')) {
if (ntohs(1) == 1) endianess = 0;
@@ -2442,6 +2604,9 @@ int main(int argc, char **argv) {
case OPT_EVENT:
event = optarg;
break;
+ case OPT_TYPE:
+ type = optarg;
+ break;
case OPT_DATA_TYPE:
data_type = optarg;
break;
@@ -2763,11 +2928,15 @@ int main(int argc, char **argv) {
WaitIRQ(handle, model_info, irq_source, timeout);
break;
case MODE_LIST_KMEM:
- ListKMEM(handle, fpga_device);
+ if (use) DetailKMEM(handle, fpga_device, use_id, block);
+ else ListKMEM(handle, fpga_device);
break;
case MODE_READ_KMEM:
ReadKMEM(handle, fpga_device, use_id, block, 0, ofile);
break;
+ case MODE_ALLOC_KMEM:
+ AllocKMEM(handle, fpga_device, use, type, size, block_size, alignment);
+ break;
case MODE_FREE_KMEM:
FreeKMEM(handle, fpga_device, use, force);
break;
diff --git a/kmem.c b/kmem.c
index b9ad919..d693b60 100644
--- a/kmem.c
+++ b/kmem.c
@@ -91,7 +91,7 @@ pcilib_kmem_handle_t *pcilib_alloc_kernel_memory(pcilib_t *ctx, pcilib_kmem_type
kh.align = alignment;
kh.use = use;
- if (type != PCILIB_KMEM_TYPE_PAGE) {
+ if ((type&PCILIB_KMEM_TYPE_MASK) != PCILIB_KMEM_TYPE_PAGE) {
kh.size += alignment;
}
@@ -143,11 +143,11 @@ pcilib_kmem_handle_t *pcilib_alloc_kernel_memory(pcilib_t *ctx, pcilib_kmem_type
break;
}
- if ((kh.align)&&(type != PCILIB_KMEM_TYPE_PAGE)) {
+ if ((kh.align)&&((kh.type&PCILIB_KMEM_TYPE_MASK) != PCILIB_KMEM_TYPE_PAGE)) {
if (kh.pa % kh.align) kbuf->buf.blocks[i].alignment_offset = kh.align - kh.pa % kh.align;
kbuf->buf.blocks[i].size -= kh.align;
}
-
+
addr = mmap( 0, kbuf->buf.blocks[i].size + kbuf->buf.blocks[i].alignment_offset, PROT_WRITE | PROT_READ, MAP_SHARED, ctx->handle, 0 );
if ((!addr)||(addr == MAP_FAILED)) {
kbuf->buf.n_blocks = i + 1;
@@ -273,6 +273,11 @@ uintptr_t pcilib_kmem_get_pa(pcilib_t *ctx, pcilib_kmem_handle_t *k) {
return kbuf->buf.addr.pa + kbuf->buf.addr.alignment_offset;
}
+uintptr_t pcilib_kmem_get_ba(pcilib_t *ctx, pcilib_kmem_handle_t *k) {
+ pcilib_kmem_list_t *kbuf = (pcilib_kmem_list_t*)k;
+ return kbuf->buf.addr.pa + kbuf->buf.addr.alignment_offset;
+}
+
void *pcilib_kmem_get_block_ua(pcilib_t *ctx, pcilib_kmem_handle_t *k, size_t block) {
pcilib_kmem_list_t *kbuf = (pcilib_kmem_list_t*)k;
return kbuf->buf.blocks[block].ua + kbuf->buf.blocks[block].alignment_offset + kbuf->buf.blocks[block].mmap_offset;
@@ -283,6 +288,11 @@ uintptr_t pcilib_kmem_get_block_pa(pcilib_t *ctx, pcilib_kmem_handle_t *k, size_
return kbuf->buf.blocks[block].pa + kbuf->buf.blocks[block].alignment_offset;
}
+uintptr_t pcilib_kmem_get_block_ba(pcilib_t *ctx, pcilib_kmem_handle_t *k, size_t block) {
+ pcilib_kmem_list_t *kbuf = (pcilib_kmem_list_t*)k;
+ return kbuf->buf.blocks[block].pa + kbuf->buf.blocks[block].alignment_offset;
+}
+
size_t pcilib_kmem_get_block_size(pcilib_t *ctx, pcilib_kmem_handle_t *k, size_t block) {
pcilib_kmem_list_t *kbuf = (pcilib_kmem_list_t*)k;
return kbuf->buf.blocks[block].size;
diff --git a/kmem.h b/kmem.h
index ef65f64..c093389 100644
--- a/kmem.h
+++ b/kmem.h
@@ -66,8 +66,10 @@ void pcilib_free_kernel_memory(pcilib_t *ctx, pcilib_kmem_handle_t *k, pcilib_km
int pcilib_kmem_sync_block(pcilib_t *ctx, pcilib_kmem_handle_t *k, pcilib_kmem_sync_direction_t dir, size_t block);
void *pcilib_kmem_get_ua(pcilib_t *ctx, pcilib_kmem_handle_t *k);
uintptr_t pcilib_kmem_get_pa(pcilib_t *ctx, pcilib_kmem_handle_t *k);
+uintptr_t pcilib_kmem_get_ba(pcilib_t *ctx, pcilib_kmem_handle_t *k);
void *pcilib_kmem_get_block_ua(pcilib_t *ctx, pcilib_kmem_handle_t *k, size_t block);
uintptr_t pcilib_kmem_get_block_pa(pcilib_t *ctx, pcilib_kmem_handle_t *k, size_t block);
+uintptr_t pcilib_kmem_get_block_ba(pcilib_t *ctx, pcilib_kmem_handle_t *k, size_t block);
size_t pcilib_kmem_get_block_size(pcilib_t *ctx, pcilib_kmem_handle_t *k, size_t block);
pcilib_kmem_reuse_state_t pcilib_kmem_is_reused(pcilib_t *ctx, pcilib_kmem_handle_t *k);
diff --git a/pcilib_types.h b/pcilib_types.h
index 646b1a1..f4f8f20 100644
--- a/pcilib_types.h
+++ b/pcilib_types.h
@@ -21,7 +21,8 @@ typedef enum {
typedef enum {
PCILIB_KMEM_USE_STANDARD = 0,
PCILIB_KMEM_USE_DMA_RING = 1,
- PCILIB_KMEM_USE_DMA_PAGES = 2
+ PCILIB_KMEM_USE_DMA_PAGES = 2,
+ PCILIB_KMEM_USE_USER = 0x10
} pcilib_kmem_use_t;
typedef enum {