I have a PCI card driver that supports most of the card's functions by
allowing userspace to mmap() the two BARs on the card, one for control
registers and one for DPRAM. The driver uses remap_page_range() to
perform the mapping. (This should be updated to use remap_pfn_range,
I know). Up until now, each BAR has been 4096 bytes, equal to
PAGE_SIZE, so the mapping is easy and everything works.
Recently, the vendor has released a new version of the card. There
are several changes, but the one that's causing trouble is that each
BAR is now 2048 bytes. How can mmap() be used on this? If the
userspace code tries to mmap() less than one page, the kernel will
page-align the region before the driver ever sees the request.
Thanks for any suggestions!
- Walt Ogburn
Caltech
Ehh ... and what's the problem with that? Just because you have
theoretically mapped 4096 bytes doesn't mean that you also have to
access them. The other obvious option would be to turn your
PCI-to-userspace glue driver into a real driver and provide a proper
interface for working with the card.
> Ehh ... and what's the problem with that? Just because you have
> theoretically mapped 4096 bytes doesn't mean that you also have to
> access them.
OK, so the kernel will allow this mapping? And the userspace will
just have to make assumptions about where the memory region has
actually been mapped after getting page-aligned? That might be a good
enough solution for this application.
Is it safe to cover more than one BAR in a single mmap()?
> The other obvious option would be to turn your PCI-to-userspace glue
> driver into a real driver and provide a proper interface for working with the card.
Yes, I'll certainly do that if needed. I expect it may be slightly
slower than using mmap(), though, and it would be good to minimize
changes to the overall system.
Thanks again for the response.
- Walt Ogburn
> OK, so the kernel will allow this mapping? And the userspace will
> just have to make assumptions about where the memory region has
> actually been mapped after getting page-aligned?
Hi. Can you please rephrase this question?
Thanks,
-Mike
Sure. There were two questions, so I'll try to rephrase both.
1. Will remap_pfn_range work correctly if I use it to map a PCI BAR,
but with a size that's greater than the size of the BAR?
2. The userspace code calls mmap() with a specified offset and
length. The function in the driver that implements mmap() receives a
vm_area_struct giving the start, end, and offset of the area to be
mapped. The vma is page-aligned, even if the start of the BAR is not
on a page boundary and the length is not an even multiple of the page
size. So how does the userspace program know what range has actually
been mapped?
Thanks,
- Walt
The generic memory management code in Linux knows nothing about 'PCI
bars', consequently, it should.
> 2. The userspace code calls mmap() with a specified offset and
> length. The function in the driver that implements mmap() receives a
> vm_area_struct giving the start, end, and offset of the area to be
> mapped. The vma is page-aligned, even if the start of the BAR is not
> on a page boundary and the length is not an even multiple of the page
> size. So how does the userspace program know what range has actually
> been mapped?
By knowing that the bar does not start on a page boundary.
Great. It was not obvious to me that this should work, but if it
does, then there's no problem.
> By knowing that the bar does not start on a page boundary.
Right, so the application will have to calculate how the kernel will
page-align the request. That should be easy enough.
Thanks for your help, I think that clears it up for me.
- Walt
The kernel cannot do any page-aligning of physical addresses. The lowest
12 bits of a physical address and any of its corresponding virtual
addresses are always exactly the same. If a BAR is not page-aligned
physically, then the virtual address will not be page-aligned.
--
Tim Roberts, ti...@probo.com
Providenza & Boekelheide, Inc.