Setting Kernel Allocated Memory Uncached on the PPC460
Judd Gilbert
JuddG at tanisys.com
Tue May 5 04:55:42 EST 2009
Hello Everyone,
This is my first post to this list, so hopefully I read all the
instructions correctly and am posting to the correct list.
I have a driver which maps some kernel allocated memory to user space
which works, and now I am trying to set that memory non-cacheable, on a
power PC using the Denx ELDK (linux-2.6.24) on a PPC460ex.
I have attempted several ways of doing this:
1. Calling the macro SetPageUncached() in linux/page-flags.h. This fails
because for some reason the bit PG_uncached is only defined for
processors whose BITS_PER_LONG > 32.
2. Calling the macro pgprot_noncached() in asm/pgtable-ppc32.h. This
just doesn't seem to have any effect.
3. Setting flags in the struct vm_area_struct->vm_flags before calling
remap_pfn_range(). This doesn't work because the flag I expected to find
VM_NONCACHED is not defined anywhere.
4. Calling the function dma_alloc_coherent() instead of kmalloc() to
allocate the memory(). This causes some kind of bus error or exception
in the kernel - I believe because I passed in NULL for the device which
I read is a bug with the kernel.
Has anyone done this successfuly on a PPC440 or PPC460?
Any tips would be appreciated. Code snippets below...
Thanks!
//
// allocating the memory in the kernel
//
static int __init mapper_init_module(void)
{
int rc;
unsigned int i = 0;
phys_addr_t phys_addr;
MDEBUG("Initializing module...\n");
/* allocate the memory and pad with pages so that we can
* make sure to page align
*/
km.raw = kmalloc((2*PAGE_COUNT+1)*PAGE_SIZE, GFP_KERNEL);
if (!km.raw)
return -ENOMEM;
/* now need to adjust our other pointer to page align to 64 Kb
boundary*/
/* Note, that we just do the mal and set pal to it since if it is 64Kb
aligned
* then it is also page aligned
*/
km.mal = (int *)((((unsigned long)km.raw) + ((1<<16) - 1)) &
0xFFFF0000);
/*km.pal = (int *)((((unsigned long)km.raw) + (PAGE_SIZE - 1)) &
PAGE_MASK);*/
km.pal = km.mal;
MDEBUG("Allocated %ld bytes of kernel space for driver at kernel
logical address %p...\n",
PAGE_COUNT*PAGE_SIZE, km.raw);
MDEBUG("page aligned = %p 64k aligned = %p\n", km.pal, km.mal);
MDEBUG("Physical address = 0x%lx...\n", __pa(km.raw));
.
.
.
.
/* lock down / reserve the pages in memory */
{
int k;
for (k=0; k<PAGE_COUNT*PAGE_SIZE; k+=PAGE_SIZE)
{
struct page* pg = virt_to_page(((unsigned long)km.pal) + k);
SetPageReserved(pg);
//SetPageUncached(pg);
}
}
.
.
.
.
}
//
// mapping the kernel space to user space
//
static int mapper_mmap(struct file *fip, struct vm_area_struct *vma)
{
int rc;
/*
* make sure to allocate the proper number of pages when using
* mmap. We check it for correctness here.
*/
unsigned long len = vma->vm_end - vma->vm_start;
/* if user tries to map bigger space than we have, error */
if (PAGE_COUNT * PAGE_SIZE < len)
return -EIO;
pgprot_noncached(vma->vm_page_prot);
//vma->vm_flags |= VM_NONCACHED | VM_RESERVED;
vma->vm_flags |= VM_RESERVED;
/* map the physical area into one buffer */
rc = remap_pfn_range(vma, vma->vm_start,
virt_to_phys( (void*)km.pal)>>PAGE_SHIFT,
len,
vma->vm_page_prot);
MDEBUG("Mapped %ld bytes at virt address 0x%lx to mapper file
descriptor...\n", len, vma->vm_start);
/* return an error to the caller if remap fails */
return (rc < 0 ? rc : 0);
}
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.ozlabs.org/pipermail/linuxppc-dev/attachments/20090504/9267cdc2/attachment.htm>
More information about the Linuxppc-dev
mailing list