* [PATCH, RFC] PCI: deal with device incorrectly reporting I/O decoding being enabled
@ 2009-11-07 13:56 Lennert Buytenhek
2009-11-07 15:03 ` [PATCH,RFC] " Matthew Wilcox
0 siblings, 1 reply; 7+ messages in thread
From: Lennert Buytenhek @ 2009-11-07 13:56 UTC (permalink / raw)
To: linux-arm-kernel
At least the Lava Quattro quad-port 16550A card can incorrectly report
I/O decoding being enabled while it is in fact not, which means that
the check in pcibios_enable_device() to see whether the new command
word that we're intending to write into the device is different from
the old current can trigger inadvertently, resulting in the write to
enable I/O decoding never being done, and I/O decoding never being
enabled.
Work around this by doing the write unconditionally (while still
only doing the printk if the new word is different from the old one,
to avoid dmesg spam).
Signed-off-by: Lennert Buytenhek <buytenh@wantstofly.org>
--
This is probably at least slightly controversial. Any thoughts?
diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c
index 8096819..cf170b9 100644
--- a/arch/arm/kernel/bios32.c
+++ b/arch/arm/kernel/bios32.c
@@ -662,11 +662,17 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)
if ((dev->class >> 16) == PCI_BASE_CLASS_BRIDGE)
cmd |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
- if (cmd != old_cmd) {
+ /*
+ * Some devices (e.g. the Lava Quattro quad-port 16550A card)
+ * can incorrectly report I/O decoding being enabled while it
+ * is in fact not, so unconditionally perform the config space
+ * write.
+ */
+ if (cmd != old_cmd)
printk("PCI: enabling device %s (%04x -> %04x)\n",
pci_name(dev), old_cmd, cmd);
- pci_write_config_word(dev, PCI_COMMAND, cmd);
- }
+ pci_write_config_word(dev, PCI_COMMAND, cmd);
+
return 0;
}
diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c
index 706f82d..96fe13d 100644
--- a/drivers/pci/setup-res.c
+++ b/drivers/pci/setup-res.c
@@ -322,10 +322,16 @@ int pci_enable_resources(struct pci_dev *dev, int mask)
cmd |= PCI_COMMAND_MEMORY;
}
- if (cmd != old_cmd) {
+ /*
+ * Some devices (e.g. the Lava Quattro quad-port 16550A card)
+ * can incorrectly report I/O decoding being enabled while it
+ * is in fact not, so unconditionally perform the config space
+ * write.
+ */
+ if (cmd != old_cmd)
dev_info(&dev->dev, "enabling device (%04x -> %04x)\n",
old_cmd, cmd);
- pci_write_config_word(dev, PCI_COMMAND, cmd);
- }
+ pci_write_config_word(dev, PCI_COMMAND, cmd);
+
return 0;
}
--
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH,RFC] PCI: deal with device incorrectly reporting I/O decoding being enabled
2009-11-07 13:56 [PATCH, RFC] PCI: deal with device incorrectly reporting I/O decoding being enabled Lennert Buytenhek
@ 2009-11-07 15:03 ` Matthew Wilcox
2009-11-08 9:04 ` Russell King - ARM Linux
0 siblings, 1 reply; 7+ messages in thread
From: Matthew Wilcox @ 2009-11-07 15:03 UTC (permalink / raw)
To: linux-arm-kernel
On Sat, Nov 07, 2009 at 02:56:15PM +0100, Lennert Buytenhek wrote:
> At least the Lava Quattro quad-port 16550A card can incorrectly report
> I/O decoding being enabled while it is in fact not, which means that
> the check in pcibios_enable_device() to see whether the new command
> word that we're intending to write into the device is different from
> the old current can trigger inadvertently, resulting in the write to
> enable I/O decoding never being done, and I/O decoding never being
> enabled.
>
> Work around this by doing the write unconditionally (while still
> only doing the printk if the new word is different from the old one,
> to avoid dmesg spam).
>
> Signed-off-by: Lennert Buytenhek <buytenh@wantstofly.org>
> --
> This is probably at least slightly controversial. Any thoughts?
I'm OK with this ... it might provoke bugs in some _other_ piece of hardware,
but that seems pretty unlikely.
Reviewed-by: Matthew Wilcox <willy@linux.intel.com>
--
Matthew Wilcox Intel Open Source Technology Centre
"Bill, look, we understand that you're interested in selling us this
operating system, but compare it to ours. We can't possibly take such
a retrograde step."
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH,RFC] PCI: deal with device incorrectly reporting I/O decoding being enabled
2009-11-07 15:03 ` [PATCH,RFC] " Matthew Wilcox
@ 2009-11-08 9:04 ` Russell King - ARM Linux
2009-11-08 15:23 ` Matthew Wilcox
0 siblings, 1 reply; 7+ messages in thread
From: Russell King - ARM Linux @ 2009-11-08 9:04 UTC (permalink / raw)
To: linux-arm-kernel
On Sat, Nov 07, 2009 at 08:03:05AM -0700, Matthew Wilcox wrote:
> I'm OK with this ... it might provoke bugs in some _other_ piece of hardware,
> but that seems pretty unlikely.
Please remember that some ARM hardware only has the capability to read
and write full 32-bit quantities of configuration space, which means
writing the control register can result in the status register being
written as well.
That shouldn't be a problem, but is merely something else to consider
which isn't obvious.
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH,RFC] PCI: deal with device incorrectly reporting I/O decoding being enabled
2009-11-08 9:04 ` Russell King - ARM Linux
@ 2009-11-08 15:23 ` Matthew Wilcox
2009-11-08 15:41 ` Russell King - ARM Linux
0 siblings, 1 reply; 7+ messages in thread
From: Matthew Wilcox @ 2009-11-08 15:23 UTC (permalink / raw)
To: linux-arm-kernel
On Sun, Nov 08, 2009 at 09:04:51AM +0000, Russell King - ARM Linux wrote:
> On Sat, Nov 07, 2009 at 08:03:05AM -0700, Matthew Wilcox wrote:
> > I'm OK with this ... it might provoke bugs in some _other_ piece of hardware,
> > but that seems pretty unlikely.
>
> Please remember that some ARM hardware only has the capability to read
> and write full 32-bit quantities of configuration space, which means
> writing the control register can result in the status register being
> written as well.
>
> That shouldn't be a problem, but is merely something else to consider
> which isn't obvious.
Wow, that's horrid. You must have to special case each config register
that's accessed in a 16-bit way, since some bits are 'preserve' and others
are 'write 1 to clear'. What a nightmare.
--
Matthew Wilcox Intel Open Source Technology Centre
"Bill, look, we understand that you're interested in selling us this
operating system, but compare it to ours. We can't possibly take such
a retrograde step."
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH,RFC] PCI: deal with device incorrectly reporting I/O decoding being enabled
2009-11-08 15:23 ` Matthew Wilcox
@ 2009-11-08 15:41 ` Russell King - ARM Linux
2009-11-08 16:15 ` Matthew Wilcox
2009-11-10 0:35 ` Dan Williams
0 siblings, 2 replies; 7+ messages in thread
From: Russell King - ARM Linux @ 2009-11-08 15:41 UTC (permalink / raw)
To: linux-arm-kernel
On Sun, Nov 08, 2009 at 08:23:10AM -0700, Matthew Wilcox wrote:
> On Sun, Nov 08, 2009 at 09:04:51AM +0000, Russell King - ARM Linux wrote:
> > On Sat, Nov 07, 2009 at 08:03:05AM -0700, Matthew Wilcox wrote:
> > > I'm OK with this ... it might provoke bugs in some _other_ piece of hardware,
> > > but that seems pretty unlikely.
> >
> > Please remember that some ARM hardware only has the capability to read
> > and write full 32-bit quantities of configuration space, which means
> > writing the control register can result in the status register being
> > written as well.
> >
> > That shouldn't be a problem, but is merely something else to consider
> > which isn't obvious.
>
> Wow, that's horrid. You must have to special case each config register
> that's accessed in a 16-bit way, since some bits are 'preserve' and others
> are 'write 1 to clear'. What a nightmare.
Yes, it's horrid, and it can be found on all IOP ARM stuff, eg:
val = iop3xx_read(addr);
if (iop3xx_pci_status())
return PCIBIOS_SUCCESSFUL;
where = (where & 3) * 8;
if (size == 1)
val &= ~(0xff << where);
else
val &= ~(0xffff << where);
*IOP3XX_OCCDR = val | value << where;
This covers IOP32x, IOP33x, and there's similar code for IOP13xx.
This does mean that if we make this change, we may do more accidental
writes to the status register on such hardware. Whether that matters
in reality isn't something I can answer - I suspect we can get away
with this without causing problems.
CC'ing Dan for his info: the proposed change@the start of this thread
is to make the write to the command register in pcibios_enable_device()
unconditional. This will guarantee that IOP platforms to copy-back the
status register on to itself on pci_enable_device(), thereby causing
"write 1 to clear" status bits to be cleared.
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH,RFC] PCI: deal with device incorrectly reporting I/O decoding being enabled
2009-11-08 15:41 ` Russell King - ARM Linux
@ 2009-11-08 16:15 ` Matthew Wilcox
2009-11-10 0:35 ` Dan Williams
1 sibling, 0 replies; 7+ messages in thread
From: Matthew Wilcox @ 2009-11-08 16:15 UTC (permalink / raw)
To: linux-arm-kernel
On Sun, Nov 08, 2009 at 03:41:03PM +0000, Russell King - ARM Linux wrote:
> On Sun, Nov 08, 2009 at 08:23:10AM -0700, Matthew Wilcox wrote:
> > On Sun, Nov 08, 2009 at 09:04:51AM +0000, Russell King - ARM Linux wrote:
> > > Please remember that some ARM hardware only has the capability to read
> > > and write full 32-bit quantities of configuration space, which means
> > > writing the control register can result in the status register being
> > > written as well.
> > >
> > > That shouldn't be a problem, but is merely something else to consider
> > > which isn't obvious.
> >
> > Wow, that's horrid. You must have to special case each config register
> > that's accessed in a 16-bit way, since some bits are 'preserve' and others
> > are 'write 1 to clear'. What a nightmare.
>
> Yes, it's horrid, and it can be found on all IOP ARM stuff, eg:
>
> val = iop3xx_read(addr);
> if (iop3xx_pci_status())
> return PCIBIOS_SUCCESSFUL;
>
> where = (where & 3) * 8;
>
> if (size == 1)
> val &= ~(0xff << where);
> else
> val &= ~(0xffff << where);
>
> *IOP3XX_OCCDR = val | value << where;
>
> This covers IOP32x, IOP33x, and there's similar code for IOP13xx.
>
> This does mean that if we make this change, we may do more accidental
> writes to the status register on such hardware. Whether that matters
> in reality isn't something I can answer - I suspect we can get away
> with this without causing problems.
You can fix this for the status register like so:
val = iop3xx_read(addr);
if (iop3xx_pci_status())
return PCIBIOS_SUCCESSFUL;
+ /* Don't clear the RW1C bits in the Status register */
+ if (where == PCI_COMMAND)
+ val &= 0xffff;
where = (where & 3) * 8;
if (size == 1)
val &= ~(0xff << where);
else
val &= ~(0xffff << where);
*IOP3XX_OCCDR = val | value << where;
Unfortunately, this status register is not the only one with RW1C, RW1CS
or RsvdZ bits. There's the Secondary Status Register (for bridges), a
dozen PCIe Status Registers, the Dynamic Power Allocation Status Register,
the Power Management Control/Status Register ... SHPC defines a RW1C
bit in a register, not sure if we'll hit that case. I bet there's others.
I can only hope that in general, one does not find many PCI devices
attached to an IOP3xx.
--
Matthew Wilcox Intel Open Source Technology Centre
"Bill, look, we understand that you're interested in selling us this
operating system, but compare it to ours. We can't possibly take such
a retrograde step."
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH,RFC] PCI: deal with device incorrectly reporting I/O decoding being enabled
2009-11-08 15:41 ` Russell King - ARM Linux
2009-11-08 16:15 ` Matthew Wilcox
@ 2009-11-10 0:35 ` Dan Williams
1 sibling, 0 replies; 7+ messages in thread
From: Dan Williams @ 2009-11-10 0:35 UTC (permalink / raw)
To: linux-arm-kernel
On Sun, Nov 8, 2009 at 8:41 AM, Russell King - ARM Linux
<linux@arm.linux.org.uk> wrote:
> On Sun, Nov 08, 2009 at 08:23:10AM -0700, Matthew Wilcox wrote:
>> On Sun, Nov 08, 2009 at 09:04:51AM +0000, Russell King - ARM Linux wrote:
>> > On Sat, Nov 07, 2009 at 08:03:05AM -0700, Matthew Wilcox wrote:
>> > > I'm OK with this ... it might provoke bugs in some _other_ piece of hardware,
>> > > but that seems pretty unlikely.
>> >
>> > Please remember that some ARM hardware only has the capability to read
>> > and write full 32-bit quantities of configuration space, which means
>> > writing the control register can result in the status register being
>> > written as well.
>> >
>> > That shouldn't be a problem, but is merely something else to consider
>> > which isn't obvious.
>>
>> Wow, that's horrid. ?You must have to special case each config register
>> that's accessed in a 16-bit way, since some bits are 'preserve' and others
>> are 'write 1 to clear'. ?What a nightmare.
>
> Yes, it's horrid, and it can be found on all IOP ARM stuff, eg:
>
> ? ? ? ? ? ? ? ?val = iop3xx_read(addr);
> ? ? ? ? ? ? ? ?if (iop3xx_pci_status())
> ? ? ? ? ? ? ? ? ? ? ? ?return PCIBIOS_SUCCESSFUL;
>
> ? ? ? ? ? ? ? ?where = (where & 3) * 8;
>
> ? ? ? ? ? ? ? ?if (size == 1)
> ? ? ? ? ? ? ? ? ? ? ? ?val &= ~(0xff << where);
> ? ? ? ? ? ? ? ?else
> ? ? ? ? ? ? ? ? ? ? ? ?val &= ~(0xffff << where);
>
> ? ? ? ? ? ? ? ?*IOP3XX_OCCDR = val | value << where;
>
> This covers IOP32x, IOP33x, and there's similar code for IOP13xx.
>
> This does mean that if we make this change, we may do more accidental
> writes to the status register on such hardware. ?Whether that matters
> in reality isn't something I can answer - I suspect we can get away
> with this without causing problems.
>
> CC'ing Dan for his info: the proposed change at the start of this thread
> is to make the write to the command register in pcibios_enable_device()
> unconditional. ?This will guarantee that IOP platforms to copy-back the
> status register on to itself on pci_enable_device(), thereby causing
> "write 1 to clear" status bits to be cleared.
>
Thanks for the CC. I am hoping that this is just an initial
misreading of the IOP specification that was blindly forward ported
from the iop32x days. In my interpretation it says that accesses may
not *cross* a dword boundary, it says nothing about sub-dword.
>From bogus@does.not.exist.com Fri Nov 6 13:01:15 2009
From: bogus@does.not.exist.com ()
Date: Fri, 06 Nov 2009 18:01:15 -0000
Subject: No subject
Message-ID: <mailman.4.1257813337.2170.linux-arm-kernel@lists.infradead.org>
"Configuration cycles are non-burst and restricted to a single 32-bit
word cycle"
...
"The user should designate the memory region containing the OCCDR as
non-cacheable and non-bufferable from the Intel XScale=AE core. This
guarantees that all load/stores to the OCCDR is only of DWORD
quantities. In event the user inadvertently issues a read to the OCCDR
that crosses a DWORD address boundary, the ATU target aborts the
transaction. All writes is terminated with a Single-Phase-Disconnect
and only bytes 3:0 is relevant."
I believe sub-dword access were once verified to work, but I no longer
have access to those test results. However, the following at least
boots on my iop13xx, so I'll look into this a bit more.
Thanks,
Dan
diff --git a/arch/arm/mach-iop13xx/pci.c b/arch/arm/mach-iop13xx/pci.c
index 4873f26..1b6a65a 100644
--- a/arch/arm/mach-iop13xx/pci.c
+++ b/arch/arm/mach-iop13xx/pci.c
@@ -190,7 +190,7 @@ static u32 iop13xx_atux_cfg_address(struct pci_bus
*bus, int devfn, int where)
else
addr =3D bus->number << 16 | PCI_SLOT(devfn) << 11 | 1;
- addr |=3D PCI_FUNC(devfn) << 8 | ((where & 0xff) & ~3);
+ addr |=3D PCI_FUNC(devfn) << 8 | (where & 0xff);
addr |=3D ((where & 0xf00) >> 8) << 24; /* upper register number */
return addr;
@@ -264,7 +264,7 @@ static u32 iop13xx_atux_read(unsigned long addr)
{
u32 val;
- __asm__ __volatile__(
+ asm volatile(
"str %1, [%2]\n\t"
"ldr %0, [%3]\n\t"
"mov %0, %0\n\t"
@@ -281,7 +281,7 @@ static int
iop13xx_atux_read_config(struct pci_bus *bus, unsigned int devfn, int wher=
e,
int size, u32 *value)
{
- unsigned long addr =3D iop13xx_atux_cfg_address(bus, devfn, where);
+ unsigned long addr =3D iop13xx_atux_cfg_address(bus, devfn, where &=
~3);
u32 val =3D iop13xx_atux_read(addr) >> ((where & 3) * 8);
if (iop13xx_atux_pci_status(1) || is_atux_occdr_error()) {
@@ -300,25 +300,14 @@ iop13xx_atux_write_config(struct pci_bus *bus,
unsigned int devfn, int where,
int size, u32 value)
{
unsigned long addr =3D iop13xx_atux_cfg_address(bus, devfn, where);
- u32 val;
-
- if (size !=3D 4) {
- val =3D iop13xx_atux_read(addr);
- if (!iop13xx_atux_pci_status(1) =3D=3D 0)
- return PCIBIOS_SUCCESSFUL;
-
- where =3D (where & 3) * 8;
- if (size =3D=3D 1)
- val &=3D ~(0xff << where);
- else
- val &=3D ~(0xffff << where);
-
- __raw_writel(val | value << where, IOP13XX_ATUX_OCCDR);
- } else {
- __raw_writel(addr, IOP13XX_ATUX_OCCAR);
+ __raw_writel(addr, IOP13XX_ATUX_OCCAR);
+ if (size =3D=3D 1)
+ __raw_writeb(value, IOP13XX_ATUX_OCCDR);
+ else if (size =3D=3D 2)
+ __raw_writew(value, IOP13XX_ATUX_OCCDR);
+ else
__raw_writel(value, IOP13XX_ATUX_OCCDR);
- }
return PCIBIOS_SUCCESSFUL;
}
^ permalink raw reply related [flat|nested] 7+ messages in thread
end of thread, other threads:[~2009-11-10 0:35 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-11-07 13:56 [PATCH, RFC] PCI: deal with device incorrectly reporting I/O decoding being enabled Lennert Buytenhek
2009-11-07 15:03 ` [PATCH,RFC] " Matthew Wilcox
2009-11-08 9:04 ` Russell King - ARM Linux
2009-11-08 15:23 ` Matthew Wilcox
2009-11-08 15:41 ` Russell King - ARM Linux
2009-11-08 16:15 ` Matthew Wilcox
2009-11-10 0:35 ` Dan Williams
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).