Tech Insider					     Technology and Trends


		        GNOME Mailing List Archives

From: di...@netcom.com (William R. Dirks)
Subject: vmalloc() and DMA
Date: 1998/07/18
Message-ID: <dirksEw9pCH.Grn@netcom.com>#1/1
X-Deja-AN: 372536286
Sender: di...@netcom8.netcom.com
Organization: Netcom
Newsgroups: comp.os.linux.development.system

Hello. I am new to Linux, and I have a kernel-mode programming question.
I am using RH5.0, with 2.1.106 kernel in place of the 2.0.? kernel.

I am writing a modular kernel-mode driver for a PCI video capture card
with bus mastering capability.
I am having difficulty deciding how to allocate the DMA buffer. The
buffer may need to be quite large for a whole image, 200K would not
be unusual. The card uses a scatter list so the buffer does not have to
be physically contiguous. The only requirement is that all the pages be
mapped to physical RAM, and stay that way, and don't physically move.

kmalloc() is inappropriate because the buffer is too big, and kmalloc() 
allocates physically contiguous pages which is unnecessary for me.
vmalloc() looks like what I want, but I am unable to use the pages of a
vmalloc()ed buffer. Are vmalloc()ed pages fixed in physical RAM, or are 
they subject to being swapped out to disk? If they are swappable, is there
a way to lock them in, like what the PageLock() function does in Windows?

What I would *like* to do (roughly):
buffer = vmalloc(...);
for (i = 0, addr = buffer; ....)
{
	scatterlist[i].addr = virt_to_bus(addr);
	scatterlist[i].len = PAGE_SIZE;
	addr += PAGE_SIZE;
}

The problem is virt_to_bus() does not return a valid physical address.
My system has 32M physical RAM, so addresses go 00000000-01FFFFFF. A call
to vmalloc() will return something like C2812000, and then virt_to_bus()
will return 02812000, which is beyond physical RAM. OTOH, get_free_page()
might return something like C0ABC000, and virt_to_bus() gives 00ABC000,
which is in physical RAM, and I can DMA to that buffer. I tried using
pte_offset() et al. to get the pte's, but they just bring compiler errors.

Can I do what I want? If I can't use vmalloc() for this then it looks like
I will have to allocate pages one by one with get_free_page(), and copy
the data out page by page, etc. But then I am effectively writing my own
software MMU and my own software page table, and that is senseless
duplication because there is a perfectly good hardware MMU that does
exacly what I want, if only I had PageLock() and a function to give me the
pte's! 

I'm ignorant of the in's and out's of Linux. Can anybody advise? 
Thanks!

Bill.

From: a...@muc.de
Subject: Re: vmalloc() and DMA
Date: 1998/07/18
Message-ID: <m3k95b6bjg.fsf@fred.muc.de>#1/1
X-Deja-AN: 372562481
Distribution: world
Sender: an...@fred.muc.de
References: <dirksEw9pCH.Grn@netcom.com>
Organization: [posted via] Leibniz-Rechenzentrum, Muenchen (Germany)
Newsgroups: comp.os.linux.development.system

di...@netcom.com (William R. Dirks) writes:

> kmalloc() is inappropriate because the buffer is too big, and kmalloc() 
> allocates physically contiguous pages which is unnecessary for me.
> vmalloc() looks like what I want, but I am unable to use the pages of a
> vmalloc()ed buffer. Are vmalloc()ed pages fixed in physical RAM, or are 
> they subject to being swapped out to disk? If they are swappable, is there
> a way to lock them in, like what the PageLock() function does in Windows?

vmalloc() pages are not swapped, so no special action is required. 

> Can I do what I want? If I can't use vmalloc() for this then it looks like
> I will have to allocate pages one by one with get_free_page(), and copy
> the data out page by page, etc. But then I am effectively writing my own
> software MMU and my own software page table, and that is senseless
> duplication because there is a perfectly good hardware MMU that does
> exacly what I want, if only I had PageLock() and a function to give me the
> pte's! 

You unfortunately have to do it by hand, because the hardware won't give
you the address.

Just vmalloc() the space and then use something like this:

/* Only pass page aligned addresses */ 
unsigned long vm_virt_to_bus(unsigned long addr)
{
		pgd_t *pgd;
		pmd_t *pmd; 
		pte_t **pte;

		pgd = pgd_offset(current->mm, addr); 
		if (pgd_none(pgd)) 
				return 0; 
		pmd = pmd_offset(pgd, addr); 
		if (pmd_none(pmd))
				return 0;
		pte = pte_offset(pmd, addr);
		if (pte_none(pte))
				return 0;
		return virt_to_bus((void *) pte_page(pte));
}
		

-Andi

From: di...@netcom.com (William R. Dirks)
Subject: Re: vmalloc() and DMA
Date: 1998/07/18
Message-ID: <dirksEwA56I.M43@netcom.com>#1/1
X-Deja-AN: 372591235
Sender: di...@netcom18.netcom.com
References: <dirksEw9pCH.Grn@netcom.com> <m3k95b6bjg.fsf@fred.muc.de>
Organization: Netcom
Newsgroups: comp.os.linux.development.system

In article <m3k95b6...@fred.muc.de>,  <a...@muc.de> wrote:
>di...@netcom.com (William R. Dirks) writes:
>>[how to get bus address of vmalloc()ed memory?]
>
>You unfortunately have to do it by hand, because the hardware won't give
>you the address.
>
>Just vmalloc() the space and then use something like this:
>[subroutine to get bus address]

Thanks, Andi! I got it working. It's just what I wanted!

Andi's code wouldn't compile exactly as he wrote it, so below is
a corrected version in case anyone else needs it. I also changed the
parameter to void * so it's the same as virt_to_bus().

Bill.

/* Only pass page aligned addresses */ 
unsigned long vm_virt_to_bus(void *virt)
{
	pgd_t *pgd;
	pmd_t *pmd;
	pte_t *pte;
	unsigned long addr = (unsigned long)virt;

	pgd = pgd_offset(current->mm, addr); 
	if (pgd_none(*pgd)) 
		return 0; 
	pmd = pmd_offset(pgd, addr); 
	if (pmd_none(*pmd))
		return 0;
	pte = pte_offset(pmd, addr);
	if (pte_none(*pte))
		return 0;
	return virt_to_bus((void *)pte_page(*pte));
}

			        About USENET

USENET (Users’ Network) was a bulletin board shared among many computer
systems around the world. USENET was a logical network, sitting on top
of several physical networks, among them UUCP, BLICN, BERKNET, X.25, and
the ARPANET. Sites on USENET included many universities, private companies
and research organizations. See USENET Archives.

		       SCO Files Lawsuit Against IBM

March 7, 2003 - The SCO Group filed legal action against IBM in the State 
Court of Utah for trade secrets misappropriation, tortious interference, 
unfair competition and breach of contract. The complaint alleges that IBM 
made concentrated efforts to improperly destroy the economic value of 
UNIX, particularly UNIX on Intel, to benefit IBM's Linux services 
business. See SCO vs IBM.

The materials and information included in this website may only be used
for purposes such as criticism, review, private study, scholarship, or
research.

Electronic mail:			       WorldWideWeb:
   tech-insider@outlook.com			  http://tech-insider.org/