Messages in this thread | | | From | Bret Indrelee <> | Subject | When is a kernel VA not a virt_to_xxx() address? | Date | Mon, 13 Dec 1999 14:37:06 -0600 |
| |
Hello,
I'm having some problems setting up a DMA between a PCI device and kernel memory space. I haven't fully debugged it, but one of the areas that looks suspicious is obtaining the PCI address of a kernel buffer.
I've allocated a buffer in kernel space using vmalloc(). I had originally thought that I could just do a virt_to_bus() in order to get the PCI address of the buffer. Looking through various other drivers, I'm seeing them go through the pgd/pmd/pte before calling virt_to_bus().
The converstion routine I'm using is based on what I found in the drivers/char/bttv.c and drivers/char/planb.c files. I'm not clear on the hows or whys of this area. Could someone explain some of what is happening here?
What is so different about the kernel virtual address that vmalloc() returns, and why doesn't virt_to_bus() just handle it?
Thanks,
-Bret
Conversion routine is as follows: /*************************************************************************** *** ** ** Name: bt_kvm2bus ** ** Purpose: Converts from a vmalloc() address to the bus address. ** ** Args: ** addr A vmalloc()ed address in kernel virtual address space. ** ** Returns: ** 0 Failed to convert ** Otherwise PCI bus address of buffer ** ** Notes: ** I haven't figured out exactly why the virt_to_phys() routine alone ** isn't sufficient for this, but it isn't. Yet another corner case of ** the Linux kernel. ** **************************************************************************** */
unsigned long bt_kvm2bus( void * vm_addr_p ) { FUNCTION("bt_kvm2bus"); LOG_UNKNOWN_UNIT;
unsigned long ret_addr = 0;
unsigned long addr = (unsigned long) vm_addr_p;
pgd_t *pgd_p; /* Page Global Descriptor */ pmd_t *pmd_p; /* Page Middle Descriptor */ pte_t *pte_p; /* Page Table Descriptor */
/* FENTRY; */
pgd_p = pgd_offset(current->mm, addr); if (!pgd_none(*pgd_p)) { pmd_p = pmd_offset(pgd_p, addr); if (!pmd_none(*pmd_p)) { pte_p = pte_offset(pmd_p, addr); if (!pte_none(*pte_p)) { ret_addr = virt_to_bus((void *) pte_page(*pte_p)) + (addr & (PAGE_SIZE-1)); } } } TRC_MSG(BT_TRC_DMA|BT_TRC_DETAIL, (LOG_FMT "Kernel VA %p = PCI addr 0x%lx.\n", LOG_ARG, vm_addr_p, ret_addr));
/* FEXIT(ret_addr); */ return ret_addr; }
------------------------------------------------------------- SBS Technologies, Connectivity Products ... solutions for real-time connectivity
Bret Indrelee, Engineer SBS Technologies, Inc., Connectivity Products 1284 Corporate Center Drive, St. Paul MN 55121 Direct: (651) 905-4731 Main: (651) 905-4700 Fax: (651) 905-4701 E-mail: bindrelee@sbs-cp.com http://www.sbs.com -------------------------------------------------------------
- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/
| |