When is a kernel VA not a virt_to_xxx() address?

Bret Indrelee (bindrele@sbs.com)
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/