check out the DMA_HIGH flag to qnx_segment_alloc_flags()
using it will cause the allocation to start on a 64k boundary above 1M
here’s some code to illustrate… notice also how you can get phys from the
virtual address.
/*-
SYNOPSIS
alloc_dmabuf, free_dmabuf – access memory for direct
memory access devices.
DESCRIPTION
This module provides two routines, which encapsulate
mechanisms for allocating and addressing memory regions
which are appropriate for use with direct memory access
devices.
alloc_dmabuf requires two arguments, a number of bytes, and
a pointer to a dma_t. The dma_t should not be modified nor
accessed directly by calling routines. The useful members
are exported through the manifests PADDR, VADDR for Physical
ADDRess and Virtual ADDRess respectively.
The actual amount of dma memory allocated may be more than
nbytes, but applications should not rely upon this.
free_dmabuf removes the mapping and allocation of memory for
the dma region. After calling free_dmabuf, the value of
the dma_t structure is undefined.
*/
#include <limits.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/kernel.h>
#include <sys/proc_msg.h>
#include <sys/seginfo.h>
#include <fcntl.h>
#include <sys/mman.h>
/*-
- alloc_dmabuf, free_dmabuf - access dma buffers.
*/
#ifndef dma_alloc_h
#define dma_alloc_h
#endif
#ifndef __TYPES_H_INCLUDED
#include <sys/types.h>
#endif
#define PHYSICAL_MEMORY “Physical”
typedef struct {
int segno; /* allocated segment number /
int seglen; / length of segment /
paddr_t phys_addr; / physical address /
caddr_t bufp; / logical address */
} dma_t;
int alloc_dmabuf(dma_t * dbuf, int nbytes);
int free_dmabuf(dma_t * dbuf);
#define P_ADDR(d) ((d)->phys_addr)
#define V_ADDR(d) ((d)->bufp)
int
alloc_dmabuf(dma_t *p, int nbytes)
{
struct _seginfo sbuf;
int selector;
int fd;
if ((selector = qnx_segment_alloc_flags(nbytes,
_PMF_DMA_SAFE | _PMF_DMA_HIGH )) == -1) {
return -1;
}
if (qnx_segment_info(PROC_PID, 0, selector, &sbuf) == -1) {
qnx_segment_free(selector);
return -1;
}
P_ADDR(p) = sbuf.addr;
if ((fd=shm_open(PHYSICAL_MEMORY,O_RDWR,0)) == -1) {
qnx_segment_free(selector);
return -1;
}
p->segno = selector;
p->seglen = nbytes;
V_ADDR(p) = mmap(0,nbytes, PROT_READ|PROT_WRITE, MAP_SHARED,
fd, P_ADDR(p));
close(fd);
if (P_ADDR(p) == (paddr_t)-1) {
qnx_segment_free(selector);
return -1;
}
return 0;
}
int
free_dmabuf(dma_t *dp)
{
munmap(V_ADDR(dp), dp->seglen);
qnx_segment_free(dp->segno);
return 0;
}
main(int argc, char **argv)
{
int ret;
dma_t d1;
unsigned nbytes = 0;
nbytes = atoi(argv[1]);
if ( nbytes == 0 ) {
printf(“use dma1 nbytes\n”);
exit(1);
}
printf(“allocating %u bytes in dma safe, high memory\n”, nbytes );
ret = alloc_dmabuf(&d1, nbytes);
printf(“ret=%d\n”, ret);
if ( ret != -1 ) {
printf(“d1: segno=%d, seglen=%d, phsy=0x%lx, log=0x%x\n”,
d1.segno, d1.seglen,
d1.phys_addr,
d1.bufp
);
}
sleep(500);
printf(“check out the mem with ‘sin mem’ … ctrl-c to quit\n”);
}
Dmitry Ivanov <id@pa.ru> wrote:
Hello!
How do I allocate contiguos regions of physical memory in QNX4?
I’ve tried qnx_segment_alloc_* functions and I have found
two options here.
-
Use qnx_segment_alloc_flags() with _PMF_DMA_SAFE flag. Then use
qnx_segment_query() to obtain physical address (using
flags other then _PMF_DMA_SAFE will result in that
qnx_segment_query() gives me virtual address - not physical)
The problem here is that I cannot allocate more than 64k
of contiguos memory this way. (But I need 500k!!!)
-
Use qnx_segment_alloc_raw().
But how do I access this memory?
I’m not sure that I can use
shm_open and mmap funtions, because the memory chunk is
removed from the system.
Can I use shm_open(“Physical”, ) and mmap() for this purpose?
In this case if I give certain phys_addr and buf_len to mmap as parameters
how do I
know this memory chunk isn’t used by QNX for other purpose?
Any suggestions or weblinks are welcome.
Best regards
Dmitri
–
Randy Martin randy@qnx.com
Manager of FAE Group, North America
QNX Software Systems www.qnx.com
175 Terence Matthews Crescent, Kanata, Ontario, Canada K2M 1W8
Tel: 613-591-0931 Fax: 613-591-3579