Forum Discussion
Altera_Forum
Honored Contributor
16 years agoLinux 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
Honored 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
Honored 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
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?// 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); - Altera_Forum
Honored 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
Honored 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
Honored 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