* Endian problem when accessing internel regs on 8347
@ 2008-01-17 6:26 Bruce_Leonard
2008-01-17 15:01 ` Ben Warren
2008-01-17 17:39 ` Scott Wood
0 siblings, 2 replies; 11+ messages in thread
From: Bruce_Leonard @ 2008-01-17 6:26 UTC (permalink / raw)
To: linuxppc-embedded
Hi,
I've got an MPC8347 running the 2.6.24-rc5 kernel and I'm trying to access
the GPIO registers. I already have a driver that's doing related work
(tho across PCI) and I just want to remap the internal CPU address to a
kernal address and be able to read/write the register using an IOCTL call
from user space. My problem is, every accessor I try does an endian
conversion before giving me my data. So here's some code snipits of what
I'm doing:
request_mem_region(0xe0000c00, 24, "my driver"); // 0xe0000c00 is the
memory mapped location of the GPIO regs
data_ptr2 = ioremap(0xe0000c00, 24);
Then in the IOCTL function I try to read from the register. First I
tried:
ioread32(data_ptr2);
I know that the mapping is working okay because I got the data from the
GPIO direction register, but it's been byte swapped. The contents of the
register are 0xFFFFFFE7, but what my user space app gets back is
0xE7FFFFFF. I've tried all the varients I can find, readl(), inl(),
in_be32(), in_le32(), even __raw_readl(). They all give me back byte
swapped data. I'm very confused. Especially since I've looked at
in_be32() and in_le32(), they're both inline assembly, and they use
different instructions. They can't be giving me the same results. I'm
sure I'm not the first person to want to access PowerPC internal registers
through a driver. Can anyone give me a hint what I'm doing wrong?
As an additional question related to PowerPC inline assembly, can anyone
tell me what "%U1%X1" means in the following:
__asm__ __volatile__("lwz%U1%X1 %0,%1; twi 0,%0,0; isync" : "=r" (ret) :
"m" (*addr));
Thanks.
See 'ya!
Bruce
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: Endian problem when accessing internel regs on 8347
2008-01-17 6:26 Endian problem when accessing internel regs on 8347 Bruce_Leonard
@ 2008-01-17 15:01 ` Ben Warren
2008-01-17 18:01 ` Bruce_Leonard
2008-01-17 17:39 ` Scott Wood
1 sibling, 1 reply; 11+ messages in thread
From: Ben Warren @ 2008-01-17 15:01 UTC (permalink / raw)
To: Bruce_Leonard; +Cc: linuxppc-embedded
[-- Attachment #1: Type: text/plain, Size: 2065 bytes --]
Hi Bruce,
Bruce_Leonard@selinc.com wrote:
> Hi,
>
> I've got an MPC8347 running the 2.6.24-rc5 kernel and I'm trying to access
> the GPIO registers. I already have a driver that's doing related work
> (tho across PCI) and I just want to remap the internal CPU address to a
> kernal address and be able to read/write the register using an IOCTL call
> from user space. My problem is, every accessor I try does an endian
> conversion before giving me my data. So here's some code snipits of what
> I'm doing:
>
> request_mem_region(0xe0000c00, 24, "my driver"); // 0xe0000c00 is the
> memory mapped location of the GPIO regs
> data_ptr2 = ioremap(0xe0000c00, 24);
>
> Then in the IOCTL function I try to read from the register. First I
> tried:
>
> ioread32(data_ptr2);
>
> I know that the mapping is working okay because I got the data from the
> GPIO direction register, but it's been byte swapped. The contents of the
> register are 0xFFFFFFE7, but what my user space app gets back is
> 0xE7FFFFFF. I've tried all the varients I can find, readl(), inl(),
> in_be32(), in_le32(), even __raw_readl(). They all give me back byte
> swapped data. I'm very confused. Especially since I've looked at
> in_be32() and in_le32(), they're both inline assembly, and they use
> different instructions. They can't be giving me the same results. I'm
> sure I'm not the first person to want to access PowerPC internal registers
> through a driver. Can anyone give me a hint what I'm doing wrong?
>
> As an additional question related to PowerPC inline assembly, can anyone
> tell me what "%U1%X1" means in the following:
>
> __asm__ __volatile__("lwz%U1%X1 %0,%1; twi 0,%0,0; isync" : "=r" (ret) :
> "m" (*addr));
>
> Thanks.
>
> See 'ya!
>
> Bruce
> _______________________________________________
>
I've attached a poorly-written-yet-functional GPIO driver that I wrote a
while ago for the MPC8349 (same as what you have for all intents and
purposes). It uses in_be32() and out_be32().
Let me know if you have any questions.
regards,
Ben
[-- Attachment #2: mpc83xx_gpio.c --]
[-- Type: text/x-csrc, Size: 6289 bytes --]
/******************************************************************************
*
* gpio_driver.c
* Copyright Qstreams Networks 2006
*
* This file contains a simple Linux device driver for accessing GPIO ports
* It is originally targeted for the MPC8349 PowerQUICC II Pro processor,
* although with simple modifications it should work with lots of CPUs. Note
* that all CPU accesses are big-endian.
*
* History:
* 04/11/2006 BAW Initial Creation
*
*****************************************************************************/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/ioport.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include "gpio.h"
struct gpio_dev {
struct gpio_reg *regs;
struct cdev cdev;
};
MODULE_AUTHOR("Ben Warren");
MODULE_LICENSE("GPL");
static int gpio_major_num;
static struct gpio_dev *gpio_devices;
static spinlock_t gpioLock[GPIO_NUM_BANKS];
extern phys_addr_t get_immrbase(void);
static u32 readGpioReg(u8 bank, u32 * addr)
{
u32 value;
spin_lock(&gpioLock[bank]);
value = in_be32(addr);
spin_unlock(&gpioLock[bank]);
return value;
}
static void writeGpioReg(u8 bank, u32 * addr, u32 val, u32 mask)
{
spin_lock(&gpioLock[bank]);
out_be32(addr, (in_be32(addr) & ~mask) | val);
spin_unlock(&gpioLock[bank]);
}
/*****
* Kernel-mode GPIO access functions.
* DO NOT CALL FROM USERSPACE
*****/
int kgpio_set_dir(u8 bank, u8 bit, u8 isOutput)
{
u32 value = GPIO_BIT(bit);
if ((bank >= GPIO_NUM_BANKS) || !gpio_devices) {
return -ENODEV;
}
writeGpioReg(bank, &gpio_devices[bank].regs->gpxdir,
isOutput ? value : 0, value);
return 0;
}
EXPORT_SYMBOL(kgpio_set_dir);
int kgpio_get_dir(u8 bank, u8 bit)
{
u32 value;
if ((bank >= GPIO_NUM_BANKS) || !gpio_devices) {
return -ENODEV;
}
value = readGpioReg(bank, &gpio_devices[bank].regs->gpxdir);
return (value & GPIO_BIT(bit) ? 1 : 0);
}
EXPORT_SYMBOL(kgpio_get_dir);
int kgpio_set_data(u8 bank, u8 bit, u8 isHigh)
{
u32 value = GPIO_BIT(bit);
if ((bank >= GPIO_NUM_BANKS) || !gpio_devices) {
return -ENODEV;
}
writeGpioReg(bank, &gpio_devices[bank].regs->gpxdat,
isHigh ? value : 0, value);
return 0;
}
EXPORT_SYMBOL(kgpio_set_data);
int kgpio_get_data(u8 bank, u8 bit)
{
u32 value;
if ((bank >= GPIO_NUM_BANKS) || !gpio_devices) {
return -ENODEV;
}
value = readGpioReg(bank, &gpio_devices[bank].regs->gpxdat);
return (value & GPIO_BIT(bit) ? 1 : 0);
}
EXPORT_SYMBOL(kgpio_get_data);
int gpio_open(struct inode *inode, struct file *filp)
{
struct gpio_dev *dev;
/* Set things up so other methods can access private data */
dev = container_of(inode->i_cdev, struct gpio_dev, cdev);
filp->private_data = dev;
return 0;
}
int gpio_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
int rc = 0;
gpioDataAccess gpioData = { 0, 0 };
struct gpio_dev *dev;
u8 bank;
/* Check that the caller really wanted GPIO */
if (_IOC_TYPE(cmd) != GPIO_IOC_MAGIC)
return -ENOTTY;
if (_IOC_NR(cmd) > GPIO_IOC_MAXNR)
return -ENOTTY;
/* Check access controls */
if (_IOC_DIR(cmd) & _IOC_READ)
rc = !access_ok(VERIFY_WRITE, (void __user *)arg,
_IOC_SIZE(cmd));
else if (_IOC_DIR(cmd) & _IOC_WRITE)
rc = !access_ok(VERIFY_READ, (void __user *)arg,
_IOC_SIZE(cmd));
if (rc)
return -EFAULT;
bank = (u8) iminor(inode);
dev = filp->private_data;
switch (cmd) {
/* Direction Register access */
case GPIO_IOC_GET_DIR:
return readGpioReg(bank, &dev->regs->gpxdir);
case GPIO_IOC_SET_DIR:
if (copy_from_user(&gpioData,
(const void __user *)arg,
sizeof(gpioDataAccess))) {
printk(KERN_ERR "copy_from_user failed\n");
return -EFAULT;
}
writeGpioReg(bank, &dev->regs->gpxdir,
gpioData.value, gpioData.mask);
break;
/* Data Register access */
case GPIO_IOC_GET_DATA:
return readGpioReg(bank, &dev->regs->gpxdat);
case GPIO_IOC_SET_DATA:
if (copy_from_user(&gpioData,
(const void __user *)arg,
sizeof(gpioDataAccess))) {
printk(KERN_ERR "copy_from_user failed\n");
return -EFAULT;
}
writeGpioReg(bank, &dev->regs->gpxdat,
gpioData.value, gpioData.mask);
break;
default:
return -ENOTTY;
}
return rc;
}
/* File operations structure. Pretty limited on this device */
struct file_operations gpio_fops = {
.owner = THIS_MODULE,
.open = gpio_open,
.ioctl = gpio_ioctl,
};
static void gpio_cleanup(void)
{
int i;
u32 addr;
dev_t devno = MKDEV(gpio_major_num, 0);
if (gpio_devices) {
for (i = 0; i < GPIO_NUM_BANKS; i++) {
cdev_del(&gpio_devices[i].cdev);
}
iounmap(gpio_devices);
}
addr = get_immrbase() + GPIO1_IO_OFFSET;
release_mem_region(addr, sizeof(struct gpio_reg));
addr = get_immrbase() + GPIO2_IO_OFFSET;
release_mem_region(addr, sizeof(struct gpio_reg));
unregister_chrdev_region(devno, GPIO_NUM_BANKS);
}
static void gpio_setup_cdev(struct gpio_dev *dev, int index)
{
int rc, devno = MKDEV(gpio_major_num, index);
cdev_init(&dev->cdev, &gpio_fops);
dev->cdev.owner = THIS_MODULE;
dev->cdev.ops = &gpio_fops;
if ((rc = cdev_add(&dev->cdev, devno, 1)))
printk(KERN_CRIT "Error %d adding gpio%d", rc, index);
}
static int gpio_init(void)
{
int i, rc;
dev_t dev = 0;
u32 addr;
/* Grab a dynamic major number and GPIO_NUM_BANKS minors */
rc = alloc_chrdev_region(&dev, 0, GPIO_NUM_BANKS, "gpio");
gpio_major_num = MAJOR(dev);
if (rc < 0) {
printk(KERN_CRIT "GPIO: couldn't get major number\n");
return rc;
}
if (!(gpio_devices = kmalloc(GPIO_NUM_BANKS * sizeof(struct gpio_dev),
GFP_KERNEL))) {
gpio_cleanup();
return -ENOMEM;
}
for (i = 0; i < GPIO_NUM_BANKS; i++) {
spin_lock_init(&gpioLock[i]);
gpio_setup_cdev(&gpio_devices[i], i);
addr =
get_immrbase() + (i ==
0 ? GPIO1_IO_OFFSET : GPIO2_IO_OFFSET);
if (!request_mem_region(addr,
sizeof(struct gpio_reg), "gpio")) {
printk(KERN_CRIT "gpio: I/O memory request failed\n");
return -ENODEV;
}
gpio_devices[i].regs = (struct gpio_reg *)ioremap_nocache(addr,
sizeof (struct gpio_reg));
if (!gpio_devices[i].regs) {
printk(KERN_CRIT "gpio: can't remap I/O memory\n");
return -ENODEV;
}
}
return 0;
}
module_init(gpio_init);
module_exit(gpio_cleanup);
[-- Attachment #3: gpio.h --]
[-- Type: text/x-chdr, Size: 829 bytes --]
#ifndef GPIO_INCLUDE_H
#define GPIO_INCLUDE_H
#include <asm/ioctl.h>
#define GPIO1_IO_OFFSET 0x00000c00
#define GPIO2_IO_OFFSET 0x00000d00
typedef struct _gpioDatAccess
{
unsigned int value;
unsigned int mask;
} gpioDataAccess;
#define GPIO_IOC_MAGIC 0xaa
#define GPIO_IOC_GET_DIR _IO(GPIO_IOC_MAGIC, 1)
#define GPIO_IOC_SET_DIR _IOW(GPIO_IOC_MAGIC, 2, gpioDataAccess)
#define GPIO_IOC_GET_DATA _IO(GPIO_IOC_MAGIC, 3)
#define GPIO_IOC_SET_DATA _IOW(GPIO_IOC_MAGIC, 4, gpioDataAccess)
#define GPIO_IOC_MAXNR 5
#define GPIO_NUM_BANKS 2
struct gpio_reg
{
unsigned int gpxdir;
unsigned int gpxdr;
unsigned int gpxdat;
unsigned int gpxier;
unsigned int gpximr;
unsigned int gpxicr;
};
/* On our CPU, bit 0 is the MS bit, so go from the left */
#define GPIO_BIT(x) (0x80000000 >> (x))
#endif /* GPIO_INCLUDE_H */
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: Endian problem when accessing internel regs on 8347
2008-01-17 6:26 Endian problem when accessing internel regs on 8347 Bruce_Leonard
2008-01-17 15:01 ` Ben Warren
@ 2008-01-17 17:39 ` Scott Wood
2008-01-17 18:38 ` Bruce_Leonard
1 sibling, 1 reply; 11+ messages in thread
From: Scott Wood @ 2008-01-17 17:39 UTC (permalink / raw)
To: Bruce_Leonard; +Cc: linuxppc-embedded
Bruce_Leonard@selinc.com wrote:
> As an additional question related to PowerPC inline assembly, can anyone
> tell me what "%U1%X1" means in the following:
>
> __asm__ __volatile__("lwz%U1%X1 %0,%1; twi 0,%0,0; isync" : "=r" (ret) :
> "m" (*addr));
They allow the compiler to use update and/or index mode for the memory
operand.
-Scott
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: Endian problem when accessing internel regs on 8347
2008-01-17 15:01 ` Ben Warren
@ 2008-01-17 18:01 ` Bruce_Leonard
2008-01-17 18:25 ` Ben Warren
0 siblings, 1 reply; 11+ messages in thread
From: Bruce_Leonard @ 2008-01-17 18:01 UTC (permalink / raw)
To: Ben Warren; +Cc: linuxppc-embedded
Ben Warren <biggerbadderben@gmail.com> wrote on 01/17/2008 07:01:10 AM:
> >
> I've attached a poorly-written-yet-functional GPIO driver that I wrote a
> while ago for the MPC8349 (same as what you have for all intents and
> purposes). It uses in_be32() and out_be32().
>
Ben,
Thanks for the answer. Hummmm, at first glance it looks like you're doing
the same thing I am. Only difference I can see is you use get_immrbase()
to figure out the address to ask for and I've got it hardcoded. Other
than that we're both using request_mem_region() in in/out_be32(). Yet
your's works for you and mine doesn't. Well, I'll take a closer look
tonight and see if there's something you're doing that I missed.
Unfortunately, I've gotten a higher level interrupt this morning and it
may ba a day or so before I get back to this and can give you any
feedback. Thanks again.
See 'ya!
Bruce
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: Endian problem when accessing internel regs on 8347
2008-01-17 18:01 ` Bruce_Leonard
@ 2008-01-17 18:25 ` Ben Warren
0 siblings, 0 replies; 11+ messages in thread
From: Ben Warren @ 2008-01-17 18:25 UTC (permalink / raw)
To: Bruce_Leonard; +Cc: linuxppc-embedded
Bruce_Leonard@selinc.com wrote:
> Ben Warren <biggerbadderben@gmail.com> wrote on 01/17/2008 07:01:10 AM:
>
>
>> I've attached a poorly-written-yet-functional GPIO driver that I wrote a
>>
>
>
>> while ago for the MPC8349 (same as what you have for all intents and
>> purposes). It uses in_be32() and out_be32().
>>
>>
> Ben,
>
> Thanks for the answer. Hummmm, at first glance it looks like you're doing
> the same thing I am. Only difference I can see is you use get_immrbase()
> to figure out the address to ask for and I've got it hardcoded. Other
> than that we're both using request_mem_region() in in/out_be32(). Yet
> your's works for you and mine doesn't. Well, I'll take a closer look
> tonight and see if there's something you're doing that I missed.
> Unfortunately, I've gotten a higher level interrupt this morning and it
> may ba a day or so before I get back to this and can give you any
> feedback. Thanks again.
>
> See 'ya!
>
> Bruce
>
>
Something else to consider is that I've never tried this beyond 2.6.19.
Maybe things have changed since then.
Anyway, glad to help if I can.
cheers,
Ben
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: Endian problem when accessing internel regs on 8347
2008-01-17 17:39 ` Scott Wood
@ 2008-01-17 18:38 ` Bruce_Leonard
2008-01-17 22:18 ` Scott Wood
0 siblings, 1 reply; 11+ messages in thread
From: Bruce_Leonard @ 2008-01-17 18:38 UTC (permalink / raw)
To: Scott Wood; +Cc: linuxppc-embedded
> > __asm__ __volatile__("lwz%U1%X1 %0,%1; twi 0,%0,0; isync" : "=r" (ret)
:
> > "m" (*addr));
>
> They allow the compiler to use update and/or index mode for the memory
> operand.
Well that makes sense, U for update and X for index, but I'm not sure
they're applicable to this particular instruction and I'm not sure that
the memory operand makes sense for PowerPC. However, before I post
anything that makes me look like I've got hoof-n-mouth disease I'm going
to do some more digging. Is the GCC manual the only "official"
documentation on this (I've found a couple of web sites but none of them
gun.org) or is there another manual I should be looking for?
Thanks for the pointers.
Bruce
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: Endian problem when accessing internel regs on 8347
2008-01-17 18:38 ` Bruce_Leonard
@ 2008-01-17 22:18 ` Scott Wood
2008-01-21 7:21 ` Bruce_Leonard
0 siblings, 1 reply; 11+ messages in thread
From: Scott Wood @ 2008-01-17 22:18 UTC (permalink / raw)
To: Bruce_Leonard; +Cc: linuxppc-embedded
Bruce_Leonard@selinc.com wrote:
>>> __asm__ __volatile__("lwz%U1%X1 %0,%1; twi 0,%0,0; isync" : "=r" (ret)
> :
>>> "m" (*addr));
>> They allow the compiler to use update and/or index mode for the memory
>> operand.
>
> Well that makes sense, U for update and X for index, but I'm not sure
> they're applicable to this particular instruction and I'm not sure that
> the memory operand makes sense for PowerPC.
Why not?
> However, before I post
> anything that makes me look like I've got hoof-n-mouth disease I'm going
> to do some more digging. Is the GCC manual the only "official"
> documentation on this (I've found a couple of web sites but none of them
> gun.org)
I believe so... other than the sources, of course. :-)
-Scott
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: Endian problem when accessing internel regs on 8347
2008-01-17 22:18 ` Scott Wood
@ 2008-01-21 7:21 ` Bruce_Leonard
2008-01-21 15:16 ` Ben Warren
2008-01-21 16:40 ` Scott Wood
0 siblings, 2 replies; 11+ messages in thread
From: Bruce_Leonard @ 2008-01-21 7:21 UTC (permalink / raw)
To: Scott Wood; +Cc: linuxppc-embedded
> >>> __asm__ __volatile__("lwz%U1%X1 %0,%1; twi 0,%0,0; isync" : "=r"
(ret)
> > :
> >>> "m" (*addr));
> >> They allow the compiler to use update and/or index mode for the
memory
> >> operand.
> >
> > Well that makes sense, U for update and X for index, but I'm not sure
> > they're applicable to this particular instruction and I'm not sure
that
> > the memory operand makes sense for PowerPC.
>
> Why not?
Okay, after much digging and experimenting, I'll agree that the memory
operand makes sense. When I first said that I was thinking of direct
manipulation of memory, which the PPC doesn't support. (Don't ask, my
brain sometimes goes off into la-la land without me :-> ) Also, update
mode is applicable and makes sense. But I do still have a problem with
the index mode, though it could be compiler magic. Here's why: the index
mode of the 'lwz' instruction requires three operands, i.e., 'lwzx
rD,rA,rB', and there's only place holders for two operands. Is the
compiler smart enough to add the third operand for the index mode? If so,
what does it put for the third operand?
Another question is how does the compiler know which mode to pick? And
what is the significance of the trailing number? Some places in the code
have %U1%X1 and others have %U2%X2? I've found documentation for the #
and ## tokens, but I can't find anything for the %U or %X tokens.
Now this has all been very interesting to learn but doesn't solve my
underlying problem which I've finally drilled down to. At first I thought
in_be32() might be broken because I wasn't getting back the value I knew
to be in the internal register. I knew I had the address and the mapping
to kernel space correct because I could use in_le32 and get the right
value though it was byte swapped. The value in the register was
0xFFFFFFE7 but what I was getting from in_be32 was 0xFFFFFFFF. Then I
started playing and here's what I found:
Register value in_be32 value
0x12345678 0x1234567
0xff345678 0xff345678
0xffff5678 0xffff5678
0xfffff678 0xfffff678
0xfffffe78 0xffffffff
0xffffff78 0xffffffff
This isn't an exhastive list but I tried about twenty values and pretty
much what I found was that if bits 0 through 22 are set to 1 then in_be32
reads 0xffffffff. I've also tried it at a variety of addresses and the
behaviour is the same. in_le32 works fine as does in_be16. I've got no
ideas as to what may be wrong. I don't want to just arbitrarily point to
that %U1%X1 parameter list, but I get compiler errors if I try to remove
them so I can't prove or disprove it and I can't find any documentation on
it I can't even form a theroy. Has anyone ever seen anything like this?
Can't anyone suggest anything I can try?
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: Endian problem when accessing internel regs on 8347
2008-01-21 7:21 ` Bruce_Leonard
@ 2008-01-21 15:16 ` Ben Warren
2008-01-21 16:40 ` Scott Wood
1 sibling, 0 replies; 11+ messages in thread
From: Ben Warren @ 2008-01-21 15:16 UTC (permalink / raw)
To: Bruce_Leonard; +Cc: Scott Wood, linuxppc-embedded
Hey Bruce,
Bruce_Leonard@selinc.com wrote:
>>>>> __asm__ __volatile__("lwz%U1%X1 %0,%1; twi 0,%0,0; isync" : "=r"
>>>>>
> (ret)
>
>>> :
>>>
>>>>> "m" (*addr));
>>>>>
>>>> They allow the compiler to use update and/or index mode for the
>>>>
> memory
>
>>>> operand.
>>>>
>>> Well that makes sense, U for update and X for index, but I'm not sure
>>> they're applicable to this particular instruction and I'm not sure
>>>
> that
>
>>> the memory operand makes sense for PowerPC.
>>>
>> Why not?
>>
>
> Okay, after much digging and experimenting, I'll agree that the memory
> operand makes sense. When I first said that I was thinking of direct
> manipulation of memory, which the PPC doesn't support. (Don't ask, my
> brain sometimes goes off into la-la land without me :-> ) Also, update
> mode is applicable and makes sense. But I do still have a problem with
> the index mode, though it could be compiler magic. Here's why: the index
> mode of the 'lwz' instruction requires three operands, i.e., 'lwzx
> rD,rA,rB', and there's only place holders for two operands. Is the
> compiler smart enough to add the third operand for the index mode? If so,
> what does it put for the third operand?
>
> Another question is how does the compiler know which mode to pick? And
> what is the significance of the trailing number? Some places in the code
> have %U1%X1 and others have %U2%X2? I've found documentation for the #
> and ## tokens, but I can't find anything for the %U or %X tokens.
>
> Now this has all been very interesting to learn but doesn't solve my
> underlying problem which I've finally drilled down to. At first I thought
> in_be32() might be broken because I wasn't getting back the value I knew
> to be in the internal register. I knew I had the address and the mapping
> to kernel space correct because I could use in_le32 and get the right
> value though it was byte swapped. The value in the register was
> 0xFFFFFFE7 but what I was getting from in_be32 was 0xFFFFFFFF. Then I
> started playing and here's what I found:
>
> Register value in_be32 value
> 0x12345678 0x1234567
> 0xff345678 0xff345678
> 0xffff5678 0xffff5678
> 0xfffff678 0xfffff678
> 0xfffffe78 0xffffffff
> 0xffffff78 0xffffffff
>
> This isn't an exhastive list but I tried about twenty values and pretty
> much what I found was that if bits 0 through 22 are set to 1 then in_be32
> reads 0xffffffff. I've also tried it at a variety of addresses and the
> behaviour is the same. in_le32 works fine as does in_be16. I've got no
> ideas as to what may be wrong. I don't want to just arbitrarily point to
> that %U1%X1 parameter list, but I get compiler errors if I try to remove
> them so I can't prove or disprove it and I can't find any documentation on
> it I can't even form a theroy. Has anyone ever seen anything like this?
> Can't anyone suggest anything I can try?
>
Are you sure that all the bits are configured as GPIO? Almost every
peripheral pin on these chips is muxed at least two ways. Maybe some of
the bits that you think are GPIO are configured as some other bus,
possibly explaining goofy behavior and perceived volatility of data.
This is pretty well-vetted code on a reasonably mature product, and in
my experience it's very rarely the tools ...
Just a thought.
regards,
Ben
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: Endian problem when accessing internel regs on 8347
2008-01-21 7:21 ` Bruce_Leonard
2008-01-21 15:16 ` Ben Warren
@ 2008-01-21 16:40 ` Scott Wood
2008-01-22 5:33 ` Bruce_Leonard
1 sibling, 1 reply; 11+ messages in thread
From: Scott Wood @ 2008-01-21 16:40 UTC (permalink / raw)
To: Bruce_Leonard; +Cc: linuxppc-embedded
On Sun, Jan 20, 2008 at 11:21:48PM -0800, Bruce_Leonard@selinc.com wrote:
> Okay, after much digging and experimenting, I'll agree that the memory
> operand makes sense. When I first said that I was thinking of direct
> manipulation of memory, which the PPC doesn't support. (Don't ask, my
> brain sometimes goes off into la-la land without me :-> ) Also, update
> mode is applicable and makes sense. But I do still have a problem with
> the index mode, though it could be compiler magic. Here's why: the index
> mode of the 'lwz' instruction requires three operands, i.e., 'lwzx
> rD,rA,rB', and there's only place holders for two operands. Is the
> compiler smart enough to add the third operand for the index mode? If so,
> what does it put for the third operand?
When the compiler decides to use index mode, the second "operand" is a
string containing "rX, rY", just as when it decides not to, the second
operand is a string containing "offset(rX)".
> Another question is how does the compiler know which mode to pick?
The same way it decides which mode to use for internally generated loads
and stores. Compiler optimization implementation is beyond the scope of
this list. :-)
> And what is the significance of the trailing number? Some places in
> the code have %U1%X1 and others have %U2%X2? I've found documentation
> for the # and ## tokens, but I can't find anything for the %U or %X
> tokens.
The number is an index into the operand list at the end of the asm
statement.
> Now this has all been very interesting to learn but doesn't solve my
> underlying problem which I've finally drilled down to. At first I thought
> in_be32() might be broken because I wasn't getting back the value I knew
> to be in the internal register. I knew I had the address and the mapping
> to kernel space correct because I could use in_le32 and get the right
> value though it was byte swapped.
Are you absolutely sure that in_le32 to in_be32 is the only thing that
changed? If you change it back now, does it resume returning a byte-swap
of the correct value?
If that is indeed what is making the difference, then perhaps it's some
subtle timing (or memory corruption) difference caused by different code
generation because the compiler is forced to use index mode for in_le32
(though it appears that the same operand list is given to GCC in either
case -- is GCC smart enough to optimize away preperation of inputs that
aren't actually referenced in the asm statement?). Is there any
difference in the generated assembly besides the specific load
instruction used?
Alternatively, maybe your chip is just fried. :-)
> I don't want to just arbitrarily point to that %U1%X1 parameter list,
So please don't.
> but I get compiler errors if I try to remove them
That's why it's there. :-)
> Can't anyone suggest anything I can try?
Beer.
-Scott
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: Endian problem when accessing internel regs on 8347
2008-01-21 16:40 ` Scott Wood
@ 2008-01-22 5:33 ` Bruce_Leonard
0 siblings, 0 replies; 11+ messages in thread
From: Bruce_Leonard @ 2008-01-22 5:33 UTC (permalink / raw)
To: Scott Wood; +Cc: linuxppc-embedded
> > Can't anyone suggest anything I can try?
>
> Beer.
>
> -Scott
Right there with you Scott! I have to apologize for the noise on the
list. Turns out my problem doesn't have anything to do with in_be32. I
didn't have print statements in enough places. I was only printing out
what was returned from the ioctl call in user space and assumed (we know
what that means ;) ) that what was coming back from the ioctl call was
what was coming back from io_read32. With better instrumenting I find
that io_read32 is just fine. Apparently my return value from the ioctl
function in my driver is getting corrupted by the time it gets to my user
space app. I don't have an answer for that one yet, but now that I'm
turned in the correct direction hopefully it'll fall out pretty quickly.
Thanks for the patience.
See 'ya!
Bruce
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2008-01-22 5:34 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-01-17 6:26 Endian problem when accessing internel regs on 8347 Bruce_Leonard
2008-01-17 15:01 ` Ben Warren
2008-01-17 18:01 ` Bruce_Leonard
2008-01-17 18:25 ` Ben Warren
2008-01-17 17:39 ` Scott Wood
2008-01-17 18:38 ` Bruce_Leonard
2008-01-17 22:18 ` Scott Wood
2008-01-21 7:21 ` Bruce_Leonard
2008-01-21 15:16 ` Ben Warren
2008-01-21 16:40 ` Scott Wood
2008-01-22 5:33 ` Bruce_Leonard
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).