Engineers at TI are looking to get the TI CMEM module into the Linux
kernel mainline in the near future.  In order to progress to this goal
we need to address some items.  One of the items that needs addressing
is the CMEM driver get_phys() function.  Currently it just decodes page
mappings at a low level, using pgd/pmd/pte low-level functions/macros.
Kevin Hilman provided an improved version, one that is much more
portable and correct.  However, there's a problem with this new version
in that it doesn't translate some kernel virtual addresses correctly, so
I'm asking the list for help.
 
CMEM is responsible for allocating contiguous memory blocks.  It is
granted a block of physical memory during module insertion time.
Typically this block is one not managed by the kernel, i.e., the kernel
has been "told" to not touch this memory, by virtue of the "mem=" boot
command line arg.  In order to manage this memory block, CMEM performs
an ioremap() (either ioremap_nocache() or ioremap_cached()), getting a
kernel virtual pointer as a result.  At some later time (as a result of
a user request) CMEM calls get_phys() on a kernel virtual address within
this block (get_phys() also is called for user mappings to the same
block).  The "new" get_phys() doesn't handle this kernel translation
correctly - the returned phys addr is always some constant offset from
the correct one.
 
The ioremap functions obtain a virtual address block large enough for
the physical block through the kernel get_vm_area() function.  This
function traverses the list 'vmlist' for an area that is large enough to
satisfy the request.  The chosen virtual address is then mapped to the
requested physical address.  The problem with get_phys() is that it uses
the 'virt_to_phys()' API which assumes a fixed, constant relationship
between a kernel virt addr and the corresponding phys addr, but in this
case the virt addr is some arbitrary address found to be free somewhere
between VMALLOC_START->VMALLOC_END.  From what I can see, the only way
to do this translation is to traverse the 'vmlist' and find the
vm_struct for the virt addr, and return the phys_addr element of the
vm_struct.  However, vmlist is not exported, and I would expect that
there is a helper function somewhere for traversing vmlist, but I can't
find anything.
 
The following code will return the wrong physp:
 
    block_virtp = (unsigned long) ioremap_nocache(start, length);
    ...
    physp = get_phys(block_virtp);
 
And here is the code in get_phys() that is returning the wrong value:

    /* For kernel direct-mapped memory, take the easy way */
    if (virtp >= PAGE_OFFSET) {
        physp = virt_to_phys((void *)virtp);
    }
So, for example, if the physical block starts at 0x87800000 and we do
    block_virtp = (unsigned long) ioremap_nocache(0x87800000, 0x800000);
we get block_virtp = 0xc80800000, and the call
    physp = get_phys(0xc8080000);
returns a physp of 0x88080000, but it should be 0x87800000 (and all phys
addrs it returns are the same amount too high - 0x00880000).
 
Moving to a different chip w/ a different Linux, we get
    block_virtp = 0xce000000
and
    get_phys(0xce000000)
returns 0x8e000000.  Clearly both these systems have a virt_to_phys()
macro/function that simply subtracts 0x40000000, but for virt addrs that
were allocated by ioremap() there is no such fixed relationship and the
vmlist must be consulted, but the CMEM module can't get to the
unexported symbol 'vmlist'.
 
Please advise on how to successfully translate these types of virtual
addresses.
 
Thanks in advance for any "pointers" you can provide :)
 
Regards,
 
- Rob Tivy
Texas Instruments, Santa Barbara
 
_______________________________________________
Davinci-linux-open-source mailing list
[email protected]
http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source

Reply via email to