* G4 + Linux + PCI device + x86 driver = 0
@ 1999-11-14 0:55 David W. Patmore
1999-11-14 11:41 ` Takashi Oe
` (2 more replies)
0 siblings, 3 replies; 12+ messages in thread
From: David W. Patmore @ 1999-11-14 0:55 UTC (permalink / raw)
To: linuxppc-dev
Hi,
I'm trying to port a device driver from working x86 code over to a G4 (early
350MHz) running LinuxPPC. The driver will load up, but the memory access
isn't working.
Linux version: 2.2.6 Sat Oct 30 1999
gcc version: egcs-2.91.66
warning sign: I get warning message "pcidrv.o was compiled for kernel
version
2.2.6-15apmac, while this kernel is version 2.2.6". I force the driver to
load
using "insmod -f pcidrv.o".
The original x86 (Redhat 6.0) driver uses virt_to_bus() to get the address
to write to. In LinuxPPC, that function is not available (not in name
table). I guess that I'm supposed to use ioremap(), but that doesn't seem
to do it for me either.
Code snip:
ul_reg_addr = p_dev->base_address[0];
pul_remapped =ioremap( ul_reg_addr, 32 );
printk( "pcidrv: base addr %08X \n", ul_reg_addr );
printk( "pcidrv: pul_remapped %08X \n", pul_remapped );
printk( "pcidrv: remapped data: %08X \n", *pul_remapped );
iounmap( pul_remapped );
The outcome of running this code is: pci base address (0x80890000),
remapped (0xC8271000), data (0xFFFFFFFF). The data is a status word which I
expect to be not
all "F"s. Note that iounmap is "TBD" in the source, so each time the code
runs per
reboot, iomap returns a new address.
If anyone has some advice, I'd be very pleased to hear it. I need to go on
the G4, because that is what I have on hand.
Thanks very much,
David Patmore
** Sent via the linuxppc-dev mail list. See http://lists.linuxppc.org/
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: G4 + Linux + PCI device + x86 driver = 0
1999-11-14 0:55 G4 + Linux + PCI device + x86 driver = 0 David W. Patmore
@ 1999-11-14 11:41 ` Takashi Oe
1999-11-14 23:50 ` Paul Mackerras
1999-11-15 9:33 ` Adrian Cox
2 siblings, 0 replies; 12+ messages in thread
From: Takashi Oe @ 1999-11-14 11:41 UTC (permalink / raw)
To: David W. Patmore; +Cc: linuxppc-dev
On Sat, 13 Nov 1999, David W. Patmore wrote:
[...]
> The original x86 (Redhat 6.0) driver uses virt_to_bus() to get the address
> to write to. In LinuxPPC, that function is not available (not in name
> table). I guess that I'm supposed to use ioremap(), but that doesn't seem
> to do it for me either.
>
> Code snip:
> ul_reg_addr = p_dev->base_address[0];
>
> pul_remapped =ioremap( ul_reg_addr, 32 );
>
> printk( "pcidrv: base addr %08X \n", ul_reg_addr );
> printk( "pcidrv: pul_remapped %08X \n", pul_remapped );
> printk( "pcidrv: remapped data: %08X \n", *pul_remapped );
>
> iounmap( pul_remapped );
>
> The outcome of running this code is: pci base address (0x80890000),
> remapped (0xC8271000), data (0xFFFFFFFF). The data is a status word which I
> expect to be not
> all "F"s. Note that iounmap is "TBD" in the source, so each time the code
Most likely, you need to enable I/O or/and memory access by hand. OF
probably didn't enable it automatically. For example,
(void) pci_read_config_word(p_dev, PCI_COMMAND, &command);
if (!(command & PCI_COMMAND_IO)) {
command |= PCI_COMMAND_IO;
(void) pci_write_config_word(p_dev, PCI_COMMAND, command);
(void) pci_read_config_word(p_dev, PCI_COMMAND, &command);
if (!(command & PCI_COMMAND_IO)) {
printk(KERN_DEBUG "IO access enable failed\n");
return 0;
}
}
if (!(command & PCI_COMMAND_MEMORY)) {
command |= PCI_COMMAND_MEMORY;
(void) pci_write_config_word(p_dev, PCI_COMMAND, command);
(void) pci_read_config_word(p_dev, PCI_COMMAND, &command);
if (!(command & PCI_COMMAND_MEMORY)) {
printk(KERN_DEBUG "Memory access enable failed\n");
return 0;
}
}
This would make *pul_remapped return something different, I'd think. See
other ppc drivers for more details. You may need additional PCI fixups.
Takashi Oe
** Sent via the linuxppc-dev mail list. See http://lists.linuxppc.org/
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: G4 + Linux + PCI device + x86 driver = 0
1999-11-14 0:55 G4 + Linux + PCI device + x86 driver = 0 David W. Patmore
1999-11-14 11:41 ` Takashi Oe
@ 1999-11-14 23:50 ` Paul Mackerras
1999-11-15 9:33 ` Adrian Cox
2 siblings, 0 replies; 12+ messages in thread
From: Paul Mackerras @ 1999-11-14 23:50 UTC (permalink / raw)
To: linuxppc-dev, David W. Patmore
On Sun, 14 Nov 1999, David W. Patmore wrote:
> The original x86 (Redhat 6.0) driver uses virt_to_bus() to get the address
> to write to. In LinuxPPC, that function is not available (not in name
> table). I guess that I'm supposed to use ioremap(), but that doesn't seem
> to do it for me either.
virt_to_bus is an extern inline function in <asm/io.h>, so you should be
able to use it. What undefined symbols do you get when you try? (Note
that you have to compile with at least -O2 otherwise gcc doesn't do inline
functions.)
If you want to access the device register within your driver, ioremap is
what you want, though, rather than virt_to_bus. You would use virt_to_bus
to translate the virtual address of some kernel memory into a bus address
to program into a DMA controller.
> The outcome of running this code is: pci base address (0x80890000),
> remapped (0xC8271000), data (0xFFFFFFFF). The data is a status word which I
> expect to be not
> all "F"s.
Most likely the device doesn't have PCI memory space accesses enabled, as
Ryuichi pointed out.
Paul.
** Sent via the linuxppc-dev mail list. See http://lists.linuxppc.org/
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: G4 + Linux + PCI device + x86 driver = 0
1999-11-14 0:55 G4 + Linux + PCI device + x86 driver = 0 David W. Patmore
1999-11-14 11:41 ` Takashi Oe
1999-11-14 23:50 ` Paul Mackerras
@ 1999-11-15 9:33 ` Adrian Cox
1999-12-03 23:00 ` Update: " David W. Patmore
2 siblings, 1 reply; 12+ messages in thread
From: Adrian Cox @ 1999-11-15 9:33 UTC (permalink / raw)
To: David W. Patmore; +Cc: linuxppc-dev
"David W. Patmore" wrote:
[snip]
> The original x86 (Redhat 6.0) driver uses virt_to_bus() to get the address
> to write to. In LinuxPPC, that function is not available (not in name
> table). I guess that I'm supposed to use ioremap(), but that doesn't seem
> to do it for me either.
You should include <asm/io.h>. But virt_to_bus(), phys_to_virt(), and
their relatives, only apply to RAM.
> Code snip:
> ul_reg_addr = p_dev->base_address[0];
>
> pul_remapped =ioremap( ul_reg_addr, 32 );
>
> printk( "pcidrv: base addr %08X \n", ul_reg_addr );
> printk( "pcidrv: pul_remapped %08X \n", pul_remapped );
> printk( "pcidrv: remapped data: %08X \n", *pul_remapped );
>
> iounmap( pul_remapped );
Note that as a general principal of cross platform Linux programming,
the thing returned by ioremap is not a true pointer, and should only be
used with readl(), writel(), etc.
These are not your problem - the problem is most likely the device not
being enabled by the boot firmware. This may mean that
(1) The PCI fixup code is broken on the G4s.
(2) The device has unusual startup requirements.
- Adrian Cox, AG Electronics
** Sent via the linuxppc-dev mail list. See http://lists.linuxppc.org/
^ permalink raw reply [flat|nested] 12+ messages in thread
* Update: RE: G4 + Linux + PCI device + x86 driver = 0
1999-11-15 9:33 ` Adrian Cox
@ 1999-12-03 23:00 ` David W. Patmore
1999-12-04 0:50 ` David Edelsohn
1999-12-04 11:57 ` Update: RE: G4 + Linux + PCI device + x86 driver = 0 Michel Lanners
0 siblings, 2 replies; 12+ messages in thread
From: David W. Patmore @ 1999-12-03 23:00 UTC (permalink / raw)
To: linuxppc-dev
I posted a question about getting a PCI device working on LinuxPPC (G4!).
Thanks to those who responded; your assistance made a big difference. I
finally finished my project, and wanted to post a few dribs that I had to
deal with (that were different from the Linux x86 driver).
1. I had to enable memory writes (PCI_COMMAND_MEMORY), which was somehow
handled automataically on x86, but not here.
{
pci_read_config_word( pDev, PCI_COMMAND, &value );
value |= PCI_COMMAND_MEMORY;
pci_write_config_word( pDev, PCI_COMMAND, value );
}
For good measure, I also set PCI_COMMAND_MASTER, though I also call
pci_set_master(), which covers the issue.
2. I had to byte-swap all pointers that I supply to my device. For
portability, I made a set of macros, "SYS_TO_LE() and LE_TO_SYS(), etc. so
that both endian architectures could work out.
3. I had to byte-swap all data that I supply to my device, except the data
that is handled as a byte stream. This involved major discussions with my
colleagues, because of the need to consider Big Endian, Little Endian, and
Network Byte Order.
Now I'm going to put my feet up and take an asprin. Thanks again for your
help.
David Patmore
www.BlueSteelNet.com
> -----Original Message-----
> From: apc@multi59.netcomi.com [mailto:apc@multi59.netcomi.com]On Behalf
> Of Adrian Cox
> Sent: Monday, November 15, 1999 1:34 AM
> To: David W. Patmore
> Cc: linuxppc-dev@lists.linuxppc.org
> Subject: Re: G4 + Linux + PCI device + x86 driver = 0
>
>
> "David W. Patmore" wrote:
> [snip]
> > The original x86 (Redhat 6.0) driver uses virt_to_bus() to get
> the address
> > to write to. In LinuxPPC, that function is not available (not in name
> > table). I guess that I'm supposed to use ioremap(), but that
> doesn't seem
> > to do it for me either.
>
> You should include <asm/io.h>. But virt_to_bus(), phys_to_virt(), and
> their relatives, only apply to RAM.
>
> > Code snip:
> > ul_reg_addr = p_dev->base_address[0];
> >
> > pul_remapped =ioremap( ul_reg_addr, 32 );
> >
> > printk( "pcidrv: base addr %08X \n", ul_reg_addr );
> > printk( "pcidrv: pul_remapped %08X \n", pul_remapped );
> > printk( "pcidrv: remapped data: %08X \n", *pul_remapped );
> >
> > iounmap( pul_remapped );
>
> Note that as a general principal of cross platform Linux programming,
> the thing returned by ioremap is not a true pointer, and should only be
> used with readl(), writel(), etc.
>
> These are not your problem - the problem is most likely the device not
> being enabled by the boot firmware. This may mean that
> (1) The PCI fixup code is broken on the G4s.
> (2) The device has unusual startup requirements.
>
> - Adrian Cox, AG Electronics
>
** Sent via the linuxppc-dev mail list. See http://lists.linuxppc.org/
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: Update: RE: G4 + Linux + PCI device + x86 driver = 0
1999-12-03 23:00 ` Update: " David W. Patmore
@ 1999-12-04 0:50 ` David Edelsohn
1999-12-04 1:13 ` endian-swapping Hollis R Blanchard
1999-12-04 11:57 ` Update: RE: G4 + Linux + PCI device + x86 driver = 0 Michel Lanners
1 sibling, 1 reply; 12+ messages in thread
From: David Edelsohn @ 1999-12-04 0:50 UTC (permalink / raw)
To: David W. Patmore; +Cc: linuxppc-dev
>>>>> "David W Patmore" writes:
avid> 1. I had to enable memory writes (PCI_COMMAND_MEMORY), which was somehow
David> handled automataically on x86, but not here.
David> {
David> pci_read_config_word( pDev, PCI_COMMAND, &value );
David> value |= PCI_COMMAND_MEMORY;
David> pci_write_config_word( pDev, PCI_COMMAND, value );
David> }
David> For good measure, I also set PCI_COMMAND_MASTER, though I also call
David> pci_set_master(), which covers the issue.
It is up to the device driver or the card to set all of these bits
if necessary.
David> 2. I had to byte-swap all pointers that I supply to my device. For
David> portability, I made a set of macros, "SYS_TO_LE() and LE_TO_SYS(), etc. so
David> that both endian architectures could work out.
Linux already provides macros like le16_to_cpu(), etc. for this.
David
** Sent via the linuxppc-dev mail list. See http://lists.linuxppc.org/
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: endian-swapping
1999-12-04 0:50 ` David Edelsohn
@ 1999-12-04 1:13 ` Hollis R Blanchard
1999-12-04 1:56 ` endian-swapping David Edelsohn
1999-12-04 19:13 ` endian-swapping Gabriel Paubert
0 siblings, 2 replies; 12+ messages in thread
From: Hollis R Blanchard @ 1999-12-04 1:13 UTC (permalink / raw)
To: David Edelsohn; +Cc: David W. Patmore, linuxppc-dev
On Fri, 3 Dec 1999, David Edelsohn wrote:
>
> Linux already provides macros like le16_to_cpu(), etc. for this.
For the sake of someone (like me) who doesn't know how to use these, can you
give an example? Just a snippet like
#include <endian.h>
#ifdef __BIG_ENDIAN
cpu_to_le16(blah);
#endif
I don't know which headers are supposed to be used for this. endian.h, for
example, does a #define __BIG_ENDIAN 4321, so __BIG_ENDIAN should *always* be
defined... so that doesn't seem like the right header to include... but lots
of drivers do that exact #ifdef test.
Also, the macros are in which header? I'm having trouble finding them too...
-Hollis
** Sent via the linuxppc-dev mail list. See http://lists.linuxppc.org/
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: endian-swapping
1999-12-04 1:13 ` endian-swapping Hollis R Blanchard
@ 1999-12-04 1:56 ` David Edelsohn
1999-12-04 19:13 ` endian-swapping Gabriel Paubert
1 sibling, 0 replies; 12+ messages in thread
From: David Edelsohn @ 1999-12-04 1:56 UTC (permalink / raw)
To: Hollis R Blanchard; +Cc: David W. Patmore, linuxppc-dev
>>>>> Hollis R Blanchard writes:
Hollis> On Fri, 3 Dec 1999, David Edelsohn wrote:
>>
>> Linux already provides macros like le16_to_cpu(), etc. for this.
Hollis> For the sake of someone (like me) who doesn't know how to use these, can you
Hollis> give an example?
See drivers/net/pcnet32.c for one example of its use. There are
no #ifdef's like NetBSD uses. le16_to_cpu() is a no-op on LE machines, so
one uses it directly like
short x = le16_to_cpu(dev_flag);
Hollis> Also, the macros are in which header? I'm having trouble finding them too...
The macros seem to be included via <asm/bitops.h> which then
include <linux/byteorder/big_endian.h> (for example).
David
** Sent via the linuxppc-dev mail list. See http://lists.linuxppc.org/
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: Update: RE: G4 + Linux + PCI device + x86 driver = 0
1999-12-03 23:00 ` Update: " David W. Patmore
1999-12-04 0:50 ` David Edelsohn
@ 1999-12-04 11:57 ` Michel Lanners
1999-12-05 19:42 ` Geert Uytterhoeven
1 sibling, 1 reply; 12+ messages in thread
From: Michel Lanners @ 1999-12-04 11:57 UTC (permalink / raw)
To: dwp; +Cc: linuxppc-dev
Hi David,
On 3 Dec, this message from David W. Patmore echoed through cyberspace:
> I posted a question about getting a PCI device working on LinuxPPC (G4!).
> Thanks to those who responded; your assistance made a big difference. I
> finally finished my project, and wanted to post a few dribs that I had to
> deal with (that were different from the Linux x86 driver).
;-)
> 1. I had to enable memory writes (PCI_COMMAND_MEMORY), which was somehow
> handled automataically on x86, but not here.
As far as I understand, i86 BIOS does this by default. However,
OpenFirmware does not. I've heard of numerous people run into this;
I've put together a kernel patch that adds a PCI fixup function on
PowerMacs, which enables memory and IO access if necessary.
> For good measure, I also set PCI_COMMAND_MASTER, though I also call
> pci_set_master(), which covers the issue.
This, however, should have been enabled by OF. Are you sure setting
master 'sticks'? There is no other way to detect whether a deivce
supports bus mastering other then setting PCI_COMMAND_MASTER, and then
checking it really got set.
> 2. I had to byte-swap all pointers that I supply to my device. For
> portability, I made a set of macros, "SYS_TO_LE() and LE_TO_SYS(), etc. so
> that both endian architectures could work out.
Why do you need to pass pointers to your device? For DMA? If so, you
should not only byteswap your pointers, but also convert them between
CPU address space and PCI bus address space. Some PCI host bridges do
address transaltion, so you're not guaranteed both sides see the same
address. I use:
pci_device->dma_target = virt_to_bus(my_buffer);
I'ts defined in asm/io.h
> 3. I had to byte-swap all data that I supply to my device, except the data
> that is handled as a byte stream. This involved major discussions with my
> colleagues, because of the need to consider Big Endian, Little Endian, and
> Network Byte Order.
David pointed out le16_to_cpu() et al; personally, I use in_/out_le32
et al for access to PCI memory space like this:
out_le32 (&device->register, val);
These functions are available under both big- and little-endian
systems, and always do 'the right thing'. They are defined in
asm-ppc/io.h, and include I/O barrier instructions (preventing
reordering on the CPU).
If you don't want I/O barriers, there are also ld_/st_le_32 et al,
which are defined in asm-ppc/byteorder.h (included from asm/io.h).
Michel
-------------------------------------------------------------------------
Michel Lanners | " Read Philosophy. Study Art.
23, Rue Paul Henkes | Ask Questions. Make Mistakes.
L-1710 Luxembourg |
email mlan@cpu.lu |
http://www.cpu.lu/~mlan | Learn Always. "
** Sent via the linuxppc-dev mail list. See http://lists.linuxppc.org/
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: endian-swapping
1999-12-04 1:13 ` endian-swapping Hollis R Blanchard
1999-12-04 1:56 ` endian-swapping David Edelsohn
@ 1999-12-04 19:13 ` Gabriel Paubert
1 sibling, 0 replies; 12+ messages in thread
From: Gabriel Paubert @ 1999-12-04 19:13 UTC (permalink / raw)
To: Hollis R Blanchard; +Cc: David Edelsohn, David W. Patmore, linuxppc-dev
On Fri, 3 Dec 1999, Hollis R Blanchard wrote:
>
> On Fri, 3 Dec 1999, David Edelsohn wrote:
> >
> > Linux already provides macros like le16_to_cpu(), etc. for this.
>
> For the sake of someone (like me) who doesn't know how to use these, can you
> give an example? Just a snippet like
>
> #include <endian.h>
>
> #ifdef __BIG_ENDIAN
> cpu_to_le16(blah);
> #endif
>
> I don't know which headers are supposed to be used for this. endian.h, for
> example, does a #define __BIG_ENDIAN 4321, so __BIG_ENDIAN should *always* be
> defined... so that doesn't seem like the right header to include... but lots
> of drivers do that exact #ifdef test.
>
> Also, the macros are in which header? I'm having trouble finding them too...
#include <asm/byteorder.h>
Several other header files include it but you should not rely on it since
for example asm/bitops.h includes it on moost architectures but not on
Intel.
Gabriel.
** Sent via the linuxppc-dev mail list. See http://lists.linuxppc.org/
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: Update: RE: G4 + Linux + PCI device + x86 driver = 0
1999-12-04 11:57 ` Update: RE: G4 + Linux + PCI device + x86 driver = 0 Michel Lanners
@ 1999-12-05 19:42 ` Geert Uytterhoeven
1999-12-06 6:51 ` Michel Lanners
0 siblings, 1 reply; 12+ messages in thread
From: Geert Uytterhoeven @ 1999-12-05 19:42 UTC (permalink / raw)
To: Michel Lanners; +Cc: dwp, linuxppc-dev
On Sat, 4 Dec 1999, Michel Lanners wrote:
> > 3. I had to byte-swap all data that I supply to my device, except the data
> > that is handled as a byte stream. This involved major discussions with my
> > colleagues, because of the need to consider Big Endian, Little Endian, and
> > Network Byte Order.
>
> David pointed out le16_to_cpu() et al; personally, I use in_/out_le32
> et al for access to PCI memory space like this:
>
> out_le32 (&device->register, val);
Which is wrong! Portable PCI memory space accesses must be done using
{read,write}[bwl]()!
See linux/Documentation/IO-mapping.txt
Gr{oetje,eeting}s,
--
Geert Uytterhoeven -- Linux/{m68k~Amiga,PPC~CHRP} -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
** Sent via the linuxppc-dev mail list. See http://lists.linuxppc.org/
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: Update: RE: G4 + Linux + PCI device + x86 driver = 0
1999-12-05 19:42 ` Geert Uytterhoeven
@ 1999-12-06 6:51 ` Michel Lanners
0 siblings, 0 replies; 12+ messages in thread
From: Michel Lanners @ 1999-12-06 6:51 UTC (permalink / raw)
To: geert; +Cc: dwp, linuxppc-dev
Hi Geert,
On 5 Dec, this message from Geert Uytterhoeven echoed through cyberspace:
>> David pointed out le16_to_cpu() et al; personally, I use in_/out_le32
>> et al for access to PCI memory space like this:
>>
>> out_le32 (&device->register, val);
>
> Which is wrong! Portable PCI memory space accesses must be done using
> {read,write}[bwl]()!
Ooopppss.... Thanks for letting me know. I guess it doesn't make much
difference, because the code I use it in is purely PowerMac, but
anyway... I'll go read...
> See linux/Documentation/IO-mapping.txt
....that ;-)
Michel
-------------------------------------------------------------------------
Michel Lanners | " Read Philosophy. Study Art.
23, Rue Paul Henkes | Ask Questions. Make Mistakes.
L-1710 Luxembourg |
email mlan@cpu.lu |
http://www.cpu.lu/~mlan | Learn Always. "
** Sent via the linuxppc-dev mail list. See http://lists.linuxppc.org/
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~1999-12-06 6:51 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
1999-11-14 0:55 G4 + Linux + PCI device + x86 driver = 0 David W. Patmore
1999-11-14 11:41 ` Takashi Oe
1999-11-14 23:50 ` Paul Mackerras
1999-11-15 9:33 ` Adrian Cox
1999-12-03 23:00 ` Update: " David W. Patmore
1999-12-04 0:50 ` David Edelsohn
1999-12-04 1:13 ` endian-swapping Hollis R Blanchard
1999-12-04 1:56 ` endian-swapping David Edelsohn
1999-12-04 19:13 ` endian-swapping Gabriel Paubert
1999-12-04 11:57 ` Update: RE: G4 + Linux + PCI device + x86 driver = 0 Michel Lanners
1999-12-05 19:42 ` Geert Uytterhoeven
1999-12-06 6:51 ` Michel Lanners
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).