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