Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
17 years ago

Linux with MMU on NEEK

Hi, all.

I'm testing Linux MMU version, on my NEEK.

http://www.nioswiki.com/linux

It works fine and I can use "bash" shell. This is the evident proof that we are using the true 'fork' instead of 'vfork'.

May be this will depends on the version, but TSE driver claims an error and doesn't work on this design. The error is


ERROR: altera_tse.c:1666: request_mem_region() failed
I think that this error is caused by misunderstanding of the usage for the function request_mem_region(). Inside of the request_mem_region(), the function __request_region() is called. If the resource has been already registered, this function returns a non-NULL value, that is the pointer for its resource. But the resource 'sgdma_rx_base' is already registered in the initialization process, so this function returns the 'conflict' and


    if (!request_mem_region(sgdma_rx_base, sgdma_rx_size, "altera_tse")) {
is always true. So I made a dirty patch,


    if (!request_mem_region(sgdma_rx_base, sgdma_rx_size, "altera_tse")) {
        reg_resource = __request_region(&iomem_resource, sgdma_rx_base, sgdma_rx_size, "altera_tse", 0);
        if (reg_resource != NULL && reg_resource->flags & IORESOURCE_BUSY) {
            printk(KERN_ERR "ERROR: %s:%d: request_mem_region() failed\n", __FILE__, __LINE__);
            ret = -EBUSY;
            goto out_sgdma_rx;
        }
    }
Moreover, the author is forgetting that the DMA is working in the physical address world,

so we need to set the pointers of descripters like


//    desc->source = read_addr;
    desc->source = virt_to_phys(read_addr);
//    desc->destination = write_addr;
    desc->destination = virt_to_phys(write_addr);
//    desc->next = (unsigned int *)next;
    desc->next = (unsigned int *)((unsigned long)next & 0x1fffffffUL);
and so on.

Also the frame buffer fb0 will not work well, because the driver 'altfb.c' is not implemented for Linux with MMU version. So I put some codes for altfb_mmap(), like


/* We implement our own mmap to set MAY_SHARE and add the correct size */
static int altfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
{
    unsigned long phys_addr, phys_size;
    unsigned long addr;
    unsigned long size = vma->vm_end - vma->vm_start;
    unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
//    vma->vm_flags |= VM_MAYSHARE | VM_SHARED;
//    vma->vm_start = info->screen_base;
//    vma->vm_end = vma->vm_start + info->fix.smem_len;
    /* check range */
    if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
        return -EINVAL;
    if (offset + size > altfb_fix.smem_len)
        return -EINVAL;
    vma->vm_flags |= VM_IO | VM_RESERVED;
    addr = vma->vm_start;
    phys_addr = altfb_fix.smem_start + offset;
    if ((offset + size) < altfb_fix.smem_len)
        phys_size = size;
    else
        phys_size = altfb_fix.smem_len - offset;
    vma->vm_page_prot = __pgprot(_PAGE_PRESENT|_PAGE_READ|_PAGE_WRITE);
    if (remap_pfn_range(vma, addr, phys_addr >> PAGE_SHIFT, phys_size, vma->vm_page_prot))
        return -EAGAIN;
    return 0;
}
and rewrite the DMA descripters like


            desc->next = (void *)virt_to_phys((desc + 1));
So now, I can evoke telnetd and control NEEK through ethernet, and use Nano-X on Linux MMU version, but can't enter ftp session, because 'getservbyname()' function will not work well.

I don't know the directory that the souce of 'getservbyname()' is included. Would anyone please tell me where is it?

Thank you, in advance.

95 Replies

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    --- Quote Start ---

    I'm using the Linux version 2.6.30 with my patches individually. And these patches are described all in this thread, but not included into the community distribution. (I don't know the reason.)

    Kazu

    --- Quote End ---

    Hi Kazu,

    The community distribution is maintained through this mailing list:

    http://sopc.et.ntust.edu.tw/cgi-bin/mailman/listinfo/nios2-dev

    I think it would be awesome if you could submit your patches -- you seem very knowledgeable and very helpful on this forum. The maintainers have been offering git accounts so active contributors can commit directly as well.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    --- Quote Start ---

    Moreover, the author is forgetting that the DMA is working in the physical address world,

    so we need to set the pointers of descripters like

    
    //    desc->source = read_addr;
        desc->source = virt_to_phys(read_addr);
    //    desc->destination = write_addr;
        desc->destination = virt_to_phys(write_addr);
    //    desc->next = (unsigned int *)next;
        desc->next = (unsigned int *)((unsigned long)next & 0x1fffffffUL);
    
    and so on.

    --- Quote End ---

    The current altera_tse code works, but does not do this translation. Any idea why setting virtual addresses here actually does work?
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Hi,

    --- Quote Start ---

    The current altera_tse code works, but does not do this translation. Any idea why setting virtual addresses here actually does work?

    --- Quote End ---

    In the kernel, a physical address 0x00000000 is translated to the virtual address 0xc0000000 for cached area or 0xe0000000 for non-cached area. For the DMA registers, we must convert these virtual addresses to physical ones again, but the range of physical addresses are limited within 0x00000000~0x1fffffff (that means totally 512MBytes), so the DMA does not use upper 3 bits. Thus we don't need to use the function virt_to_phys(...), because the DMA and Avalon bus will ignore upper 3bits automatically, but this is wrong from the view point of the logic.

    Kazu
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    --- Quote Start ---

    Hi,

    In the kernel, a physical address 0x00000000 is translated to the virtual address 0xc0000000 for cached area or 0xe0000000 for non-cached area. For the DMA registers, we must convert these virtual addresses to physical ones again, but the range of physical addresses are limited within 0x00000000~0x1fffffff (that means totally 512MBytes), so the DMA does not use upper 3 bits. Thus we don't need to use the function virt_to_phys(...), because the DMA and Avalon bus will ignore upper 3bits automatically, but this is wrong from the view point of the logic.

    Kazu

    --- Quote End ---

    Thanks for the explanation Kazu, I was getting to that conclusion. Just to clarify -- these are kernel virtual addresses (e.g. from kmalloc()) if given an address from vmalloc() this would not work, right?
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Hi,

    --- Quote Start ---

    Just to clarify -- these are kernel virtual addresses (e.g. from kmalloc()) if given an address from vmalloc() this would not work, right?

    --- Quote End ---

    Yes, it's right. For the difference of the 'kmalloc()' and 'vmalloc()', please refer the next site.

    http://book.chinaunix.net/special/ebook/linux_kernel_development/0672327201/ch11lev1sec5.html

    Of course, the kernel can access the address area from vmalloc(), but must use MMU and page tables, so the 'pure' hardware like DMA can't access those without complicated address conversions, while kmalloc() uses simple straight mapping like 0xC0000000 to 0x00000000.

    Kazu