Accessing PCI Memory Mapped Registers in Linux Kernel

YOUNGWHAN SONG breadncup at
Tue Dec 21 04:04:52 EST 2010


A few days ago, I posted about accessing PCI memory mapped registers. (FYI, the platform I use is 32bit  architecture and Linux kernel compiled in 32 bit intel based architecture.)

Now, I found that there is a problem to access 16b aligned registers. For example,

struct foo {
    unsigned int TEST1;
    unsigned short int a1[256];
void * regsva;

struct foo *test_foo;

    if ((regsva = ioremap_nocache(dev->base_addr, (16 * 1024))) == NULL) {
        printk("ioremap() failed\n");
        goto fail;

test_foo = (struct foo*)regsva;
printk(KERN_DBG "value TEST1: 0x%lx\n", readl(test_foo->TEST1));
printk(KERN_DBG "value 0: 0x%x\n", readw(&test_foo->a1[0]);
printk(KERN_DBG "value 1: 0x%x\n", readw(&test_foo->a1[1]);

The above code in PC (intel based 32bit architecture) with the same h/w module shows that

value TEST1: 0x8080
value 0: 0x9090
value 1: 0xa0a0

So, that's valid value. (I have datasheet to check if the value is correct or not.)

But, when the code is run on our platform (32bit) with the same h/w module, it
shows that

value TEST1: 0x8080
value 0: 0xFFFF
value 1: 0xFFFF

Now, if I change the printk as

printk(KERN_DBG "value 0: 0x%x\n", readl(&test_foo->a1[0]);
printk(KERN_DBG "value 1: 0x%x\n", readl(&test_foo->a1[1]);

Then, even PC shows 0xFFFF like this:

value 0: 0xFFFFFFFF
value 1: 0xFFFFFFFF

So, if the read bit is not aligned correctly, it looks it cannot read correctly.

OK, then, 

How can our platform (32 bit) read correctly 16b aligned PCI memory mapped register? (As long as the register is 32 bit, there is no problem.)

At least, I would like to understand why the 16 bit registers and 32 bit registers are responding differently.


More information about the Kernelnewbies mailing list