linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* Physical address
@ 2003-12-08 15:07 moi toi
  2003-12-08 15:23 ` William Lee Irwin III
                   ` (2 more replies)
  0 siblings, 3 replies; 5+ messages in thread
From: moi toi @ 2003-12-08 15:07 UTC (permalink / raw)
  To: linux-kernel

Hi

I am a newbie in the development of Linux driver. I
have some
difficulties to understand how the memory management
works.

I am working on a Pentium IV ( 512M of RAM), with the
Red Hat 9.0.
I want to create buffers in the RAM which are
available for DMA
transfer, and I want that process can map them.

I reserve at boot time some space in the RAM
(mem=400M).
And then I remap a buffer into the driver with the
following command: 

>unsigned long Ram_Buffer_addr;
>#define       POSITION 0x19000000 
//400*1024*1024=400M
>#define SIZE  8*1024
>
>Ram_Buffer_addr = (unsigned long) ioremap (POSITION,
SIZE);

The addresses of the buffer are the following: 
Ram_Buffer_addr               = 0xD9DCB000
Virt_to_phys(Ram_Buffer_addr) = 0x19DCB000
Virt_to_bus(Ram_Buffer_addr)  = 0x19DCB000

The virtual address is of course different from the
physical address,
and the physical address and the bus address are the
same, because I m
working on a PC. But I don t understand why the
physical address is
different from the one I gave to the function ioremap.

I did a second test: I change the position of the
buffer instead of
taking it at the address 0x19000000, the buffer start
at the address:
0x1f400000 (500M).

>unsigned long Ram_Buffer_addr;
>#define       POSITION 0x1F400000 
//500*1024*1024=500M
>#define SIZE  8*1024
>
>Ram_Buffer_addr = (unsigned long) ioremap (POSITION,
SIZE);

The addresses of the buffer are the following: 
Ram_Buffer_addr               = 0xD9DCB000
Virt_to_phys(Ram_Buffer_addr) = 0x19DCB000
Virt_to_bus(Ram_Buffer_addr)  = 0x19DCB000

The addresses are exactly the same. I m ok for the
virtual addresses,
but it sounds pretty weird for the physical and bus
addresses, they
shouldn t be the same than in the first test.

----------------------------------------------------------------------
When I map the buffer from a process, I use the
virtual address of the
buffer with the function mmap, but in the mmap
call-back function in
the driver, I use the true physical address with the
function:
remap_page_range( vma,  vma->vm_start,
POSITION,(vma->vm_end -
vma->vm_start), (pgprot_t) vma->vm_page_prot);
And it seems work! 
But if instead of POSITION, I set
Virt_to_phys(Ram_Buffer_addr), it
doesn t work anymore.

Does that mean that the functions virt_to_phys and
virt_to_bus don t
work on virtual addresses? Does anyone know, how to
get the real
physical address of the buffer.

Thanks

Francois.

____________________________________________________________________________________
Do You Yahoo!? -- Avec Yahoo! soyez au coeur de la récolte de dons pour le Téléthon.
http://fr.promotions.yahoo.com/caritatif/

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Physical address
  2003-12-08 15:07 Physical address moi toi
@ 2003-12-08 15:23 ` William Lee Irwin III
  2003-12-08 15:42 ` Richard B. Johnson
  2003-12-09 16:04 ` Jesper Juhl
  2 siblings, 0 replies; 5+ messages in thread
From: William Lee Irwin III @ 2003-12-08 15:23 UTC (permalink / raw)
  To: moi toi; +Cc: linux-kernel

On Mon, Dec 08, 2003 at 04:07:13PM +0100, moi toi wrote:
> Does that mean that the functions virt_to_phys and
> virt_to_bus don't work on virtual addresses? Does anyone know, how to
> get the real physical address of the buffer.

Linux assumes 1:1 mapping of kernel virtual addresses, with various
exceptions.

virt_to_bus() and virt_to_phys() only work on that statically mapped
area's virtual addreses.

ioremap() dynamically establishes translations for the areas, and
the virtual addresses returned by it are not valid to resolve to
physical addresses with virt_to_bus() and virt_to_phys().

Probably the best way to find the physical address is by a direct
pagetable lookup. Something like the following (untested) may be of use:

static dma_addr_t ioremap_to_phys(unsigned long vaddr)
{
	pgd_t *pgd;
	pmd_t *pmd;
	pte_t *pte;

	pgd = pgd_offset_k(vaddr);
	if (!pgd_present(*pgd))
		return 0;
	pmd = pmd_offset(pgd, vaddr);
	if (!pmd_present(*pmd))
		return 0;
	pte = pte_offset_kernel(pmd, vaddr);
	if (!pte_present(*pte))
		return 0;
	return ((dma_addr_t)pte_pfn(*pte) << PAGE_SHIFT) | (addr & ~PAGE_MASK);
}


-- wli

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Physical address
  2003-12-08 15:07 Physical address moi toi
  2003-12-08 15:23 ` William Lee Irwin III
@ 2003-12-08 15:42 ` Richard B. Johnson
  2003-12-08 16:05   ` Matthias Urlichs
  2003-12-09 16:04 ` Jesper Juhl
  2 siblings, 1 reply; 5+ messages in thread
From: Richard B. Johnson @ 2003-12-08 15:42 UTC (permalink / raw)
  To: moi toi; +Cc: linux-kernel

On Mon, 8 Dec 2003, [iso-8859-1] moi toi wrote:

> Hi
>
> I am a newbie in the development of Linux driver. I
> have some
> difficulties to understand how the memory management
> works.
>
> I am working on a Pentium IV ( 512M of RAM), with the
> Red Hat 9.0.
> I want to create buffers in the RAM which are
> available for DMA
> transfer, and I want that process can map them.
>
> I reserve at boot time some space in the RAM
> (mem=400M).
> And then I remap a buffer into the driver with the
> following command:
>
> >unsigned long Ram_Buffer_addr;
> >#define       POSITION 0x19000000
> //400*1024*1024=400M
> >#define SIZE  8*1024
> >
> >Ram_Buffer_addr = (unsigned long) ioremap (POSITION,
> SIZE);
>
> The addresses of the buffer are the following:
> Ram_Buffer_addr               = 0xD9DCB000
> Virt_to_phys(Ram_Buffer_addr) = 0x19DCB000
> Virt_to_bus(Ram_Buffer_addr)  = 0x19DCB000
>
> The virtual address is of course different from the
> physical address,
> and the physical address and the bus address are the
> same, because I m
> working on a PC. But I don t understand why the
> physical address is
> different from the one I gave to the function ioremap.
>
> I did a second test: I change the position of the
> buffer instead of
> taking it at the address 0x19000000, the buffer start
> at the address:
> 0x1f400000 (500M).
>
> >unsigned long Ram_Buffer_addr;
> >#define       POSITION 0x1F400000
> //500*1024*1024=500M
> >#define SIZE  8*1024
> >
> >Ram_Buffer_addr = (unsigned long) ioremap (POSITION,
> SIZE);
>
> The addresses of the buffer are the following:
> Ram_Buffer_addr               = 0xD9DCB000
> Virt_to_phys(Ram_Buffer_addr) = 0x19DCB000
> Virt_to_bus(Ram_Buffer_addr)  = 0x19DCB000
>
> The addresses are exactly the same. I m ok for the
> virtual addresses,
> but it sounds pretty weird for the physical and bus
> addresses, they
> shouldn t be the same than in the first test.
>
> ----------------------------------------------------------------------
> When I map the buffer from a process, I use the
> virtual address of the
> buffer with the function mmap, but in the mmap
> call-back function in
> the driver, I use the true physical address with the
> function:
> remap_page_range( vma,  vma->vm_start,
> POSITION,(vma->vm_end -
> vma->vm_start), (pgprot_t) vma->vm_page_prot);
> And it seems work!
> But if instead of POSITION, I set
> Virt_to_phys(Ram_Buffer_addr), it
> doesn t work anymore.
>
> Does that mean that the functions virt_to_phys and
> virt_to_bus don t
> work on virtual addresses? Does anyone know, how to
> get the real
> physical address of the buffer.
>
> Thanks
>
> Francois.

The way pages are set up on Linux makes the virtual address =
physical + PAGE_OFFSET.

So, a __non__portable__ driver can just use that information
to access physical addresses. But, you really should use
the macros provided to make a driver that has a chance of
running on different systems.

In your case, you oremap(0x1f400000) = df400000 which makes
sense. However, depending upon the kernel version you are
using, some "portable pedantics" corrupted the return values
into "cookies", not real addresses. This forces you to use
the macros provided to access these addresses. In other words,
they are __not__ pointers, so they don't make any sense.

A trick to get around all this stuff is to just save the
junk returned from ioremap(). You use this for iounmap().
Then just take the address you asked for (the physical address)
and use that for your hardware, and the virtual address (add
PAGE_OFFSET to it) for your pointer(s). Don't expect any help
from some LK pedantics, but this hack will get you started if
you are not using any special addresses (like high RAM).
Also, don't tell anybody .... <grin>...


Cheers,
Dick Johnson
Penguin : Linux version 2.4.22 on an i686 machine (797.90 BogoMips).
            Note 96.31% of all statistics are fiction.



^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Physical address
  2003-12-08 15:42 ` Richard B. Johnson
@ 2003-12-08 16:05   ` Matthias Urlichs
  0 siblings, 0 replies; 5+ messages in thread
From: Matthias Urlichs @ 2003-12-08 16:05 UTC (permalink / raw)
  To: linux-kernel

Hi, Richard B. Johnson wrote:

> Don't expect any help
> from some LK pedantics, but this hack will get you started if
> you are not using any special addresses (like high RAM).

... and if the driver will never run on non-PC-like or non-x86 systems.

> Also, don't tell anybody .... <grin>...

*Grumble*. IMHO you(generic) should do this right the first time.
The learning curve may be a bit steeper, but OTOH you won't get into any
bad habits, and you won't leave a mess for other people to debug.

-- 
Matthias Urlichs   |   {M:U} IT Design @ m-u-it.de   |  smurf@smurf.noris.de
Disclaimer: The quote was selected randomly. Really. | http://smurf.noris.de
 - -
We are bits of stellar matter that got cold
by accident, bits of a star gone wrong.
		-- Sir Arthur Eddington


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Physical address
  2003-12-08 15:07 Physical address moi toi
  2003-12-08 15:23 ` William Lee Irwin III
  2003-12-08 15:42 ` Richard B. Johnson
@ 2003-12-09 16:04 ` Jesper Juhl
  2 siblings, 0 replies; 5+ messages in thread
From: Jesper Juhl @ 2003-12-09 16:04 UTC (permalink / raw)
  To: moi toi; +Cc: linux-kernel


On Mon, 8 Dec 2003, moi toi wrote:

> Hi
>
> I am a newbie in the development of Linux driver. I
> have some
> difficulties to understand how the memory management
> works.
>
> I am working on a Pentium IV ( 512M of RAM), with the
> Red Hat 9.0.
> I want to create buffers in the RAM which are
> available for DMA
> transfer, and I want that process can map them.
>

I recently came across a good article in Linux Journal by Robert Love that
explains how to allocate memory in the kernel and the various options you
have.
The article was called "Allocating Memory in the Kernel" and appeared in
the December 2003 issue. You can also find it online here:
http://www.linuxjournal.com/article.php?sid=6930


Hope this helps you.


Kind regards,

Jesper Juhl


^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2003-12-09 16:07 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-12-08 15:07 Physical address moi toi
2003-12-08 15:23 ` William Lee Irwin III
2003-12-08 15:42 ` Richard B. Johnson
2003-12-08 16:05   ` Matthias Urlichs
2003-12-09 16:04 ` Jesper Juhl

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).