Re: Accessing memory mapped PCI device?

Linus Torvalds (torvalds@transmeta.com)
7 Mar 1997 18:25:08 GMT


In article <Pine.LNX.3.95.970306001638.6439A-100000@batman>,
Hannu Savolainen <hannu@voxware.pp.fi> wrote:
>
>I have the following PCI device which has it's registers mapped to PCI
>memory space. How do I access the device in a driver? Accessing a pointer
>obtained using phys_to_virt(0xffae0000) causes a protection fault.
>
> Bus 0, device 16, function 0:
> Multimedia controller: Unknown vendor Unknown device (rev 1).
> Vendor id=1057. Device id=1801.
> Medium devsel. Fast back-to-back capable. Master Capable. Latency=32.
> Non-prefetchable 32 bit memory at 0xffae0000.

The way to handle these accesses is through the "ioremap()" function.
See linux/Documentation/IO-mapping.txt for full details on PCI memory
mapping.

Notice that when you access PCI memory, you can _never_ just dereference
a pointer and expect to be at all portable. Generally you have something
like this:

dev_init():

/* get a cookie for a 1MB PCI area starting at 0xffae0000 */
char * baseptr = ioremap(0xffae0000, 1024*1024);
if (!baseptr) {
printk("Unable to map PCI memory for XXXX\n");
return -ENODEV;
}
device->baseptr = baseptr;

using the device:

/* copy 200 bytes to "kernel_buffer" from the PCI area at offset 100 */
memcpy_fromio(kernel_buffer, device->baseptr+100, 200);

/* Get a 4-byte value from the PCI area at offset 32 */
signature = readl(device->baseptr + 32);

NOTE! NOTE! NOTE! You _really_ should never use anything like this:

signature = *(unsigned int) (device->baseptr + 32);

It may happen to work on the x86 (at least on _some_ kernel versions),
but there is no guarantee that it works on all kernels and certainly not
on all architectures (it certainly won't work on alpha or PowerPC, and
probably won't work on Sparc either when the PCI sparcs appear). So you
really must use the read[bwl]/write[bwl]/memcopy_fromio/memcopy_toio etc
functions for it to reliably work.

Linus