* Re: in_be32() etc
From: Russell King - ARM Linux @ 2012-02-23 20:25 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: linuxppc-dev, Paul Mackerras
In-Reply-To: <1330028339.20389.28.camel@pasglop>
On Fri, Feb 24, 2012 at 07:18:59AM +1100, Benjamin Herrenschmidt wrote:
> On Thu, 2012-02-23 at 11:29 +0000, Russell King - ARM Linux wrote:
> > What's this stuff doing in generic drivers?
>
> Well, I suppose that's because the xilinx stuff used to be ppc
> only ? :-)
Note that's just the first one grep turned up. I've no idea which specific
drivers the ST SPEAr people are wanting these accessors for (they didn't
include that information in their submission adding them to ARM.)
> > See drivers/gpio/gpio-xilinx.c:
> > static int xgpio_get(struct gpio_chip *gc, unsigned int gpio)
> > {
> > struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
> >
> > return (in_be32(mm_gc->regs + XGPIO_DATA_OFFSET) >> gpio) & 1;
> > }
> >
> > include/linux/of_gpio.h:
> > struct of_mm_gpio_chip {
> > struct gpio_chip gc;
> > void (*save_regs)(struct of_mm_gpio_chip *mm_gc);
> > void __iomem *regs;
> > };
> >
> > Why am I being asked to add in_be32() etc to ARMs io.h ? Why do we need
> > yet another set of IO accessors? Is there something wrong with
> > ioread*()/ioread*be() etc?
>
> Nope, nothing wrong with them, the driver should be fixed. in_be* is
> historical ppc stuff.
>
> > My guess is this stems from a lack of proper review
>
> That or history. Our readX/writeX used to be more PCI specific (have
> infrastructure to work around PCI bridge bugs) which some drivers
> avoided using the in_/out_ variants, in some case it's just pure
> history, etc... Some of these things are ancient.
So, if I tell the SPEAr people that any driver they come across using
these old in_XX should be converted to use ioread*() you'll be happy
for that to happen?
^ permalink raw reply
* Re: in_be32() etc
From: Grant Likely @ 2012-02-23 20:27 UTC (permalink / raw)
To: Russell King - ARM Linux; +Cc: Paul Mackerras, linuxppc-dev
In-Reply-To: <20120223202534.GE22562@n2100.arm.linux.org.uk>
On Thu, Feb 23, 2012 at 1:25 PM, Russell King - ARM Linux
<linux@arm.linux.org.uk> wrote:
> On Fri, Feb 24, 2012 at 07:18:59AM +1100, Benjamin Herrenschmidt wrote:
>> On Thu, 2012-02-23 at 11:29 +0000, Russell King - ARM Linux wrote:
>> > What's this stuff doing in generic drivers?
>>
>> Well, I suppose that's because the xilinx stuff used to be ppc
>> only ? :-)
>
> Note that's just the first one grep turned up. =A0I've no idea which spec=
ific
> drivers the ST SPEAr people are wanting these accessors for (they didn't
> include that information in their submission adding them to ARM.)
>
>> > See drivers/gpio/gpio-xilinx.c:
>> > static int xgpio_get(struct gpio_chip *gc, unsigned int gpio)
>> > {
>> > =A0 =A0 =A0 =A0 struct of_mm_gpio_chip *mm_gc =3D to_of_mm_gpio_chip(g=
c);
>> >
>> > =A0 =A0 =A0 =A0 return (in_be32(mm_gc->regs + XGPIO_DATA_OFFSET) >> gp=
io) & 1;
>> > }
>> >
>> > include/linux/of_gpio.h:
>> > struct of_mm_gpio_chip {
>> > =A0 =A0 =A0 =A0 struct gpio_chip gc;
>> > =A0 =A0 =A0 =A0 void (*save_regs)(struct of_mm_gpio_chip *mm_gc);
>> > =A0 =A0 =A0 =A0 void __iomem *regs;
>> > };
>> >
>> > Why am I being asked to add in_be32() etc to ARMs io.h ? =A0Why do we =
need
>> > yet another set of IO accessors? =A0Is there something wrong with
>> > ioread*()/ioread*be() etc?
>>
>> Nope, nothing wrong with them, the driver should be fixed. in_be* is
>> historical ppc stuff.
>>
>> > My guess is this stems from a lack of proper review
>>
>> That or history. Our readX/writeX used to be more PCI specific (have
>> infrastructure to work around PCI bridge bugs) which some drivers
>> avoided using the in_/out_ variants, in some case it's just pure
>> history, etc... Some of these things are ancient.
>
> So, if I tell the SPEAr people that any driver they come across using
> these old in_XX should be converted to use ioread*() you'll be happy
> for that to happen?
yes
g.
--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
^ permalink raw reply
* Re: [PATCH 09/24] PCI, powerpc: Register busn_res for root buses
From: Bjorn Helgaas @ 2012-02-23 20:51 UTC (permalink / raw)
To: Jesse Barnes
Cc: linux-arch, Tony Luck, linuxppc-dev, linux-kernel,
Dominik Brodowski, Linus Torvalds, Paul Mackerras, linux-pci,
Andrew Morton, Yinghai Lu
In-Reply-To: <20120223122536.6a2a7a6b@jbarnes-desktop>
On Thu, Feb 23, 2012 at 12:25 PM, Jesse Barnes <jbarnes@virtuousgeek.org> w=
rote:
> On Fri, 10 Feb 2012 08:35:58 +1100
> Benjamin Herrenschmidt <benh@kernel.crashing.org> wrote:
>
>> On Thu, 2012-02-09 at 11:24 -0800, Bjorn Helgaas wrote:
>> > My point is that the interface between the arch and the PCI core
>> > should be simply the arch telling the core "this is the range of bus
>> > numbers you can use." =A0If the firmware doesn't give you the HW limit=
s,
>> > that's the arch's problem. =A0If you want to assume 0..255 are
>> > available, again, that's the arch's decision.
>> >
>> > But the answer to the question "what bus numbers are available to me"
>> > depends only on the host bridge HW configuration. =A0It does not depen=
d
>> > on what pci_scan_child_bus() found. =A0Therefore, I think we can come =
up
>> > with a design where pci_bus_update_busn_res_end() is unnecessary.
>>
>> In an ideal world yes. In a world where there are reverse engineered
>> platforms on which we aren't 100% sure how thing actually work under the
>> hood and have the code just adapt on "what's there" (and try to fix it
>> up -sometimes-), thinks can get a bit murky :-)
>>
>> But yes, I see your point. As for what is the "correct" setting that
>> needs to be done so that the patch doesn't end up a regression for us,
>> I'll have to dig into some ancient HW to dbl check a few things. I hope
>> 0...255 will just work but I can't guarantee it.
>>
>> What I'll probably do is constraint the core to the values in
>> hose->min/max, and update selected platforms to put 0..255 in there when
>> I know for sure they can cope.
>
> But I think the point is, can't we intiialize the busn resource after
> the first & last bus numbers have been determined? =A0E.g. rather than
> Yinghai's current:
> + =A0 =A0 =A0 pci_bus_insert_busn_res(bus, hose->first_busno, hose->last_=
busno);
> +
> =A0 =A0 =A0 =A0/* Get probe mode and perform scan */
> =A0 =A0 =A0 =A0mode =3D PCI_PROBE_NORMAL;
> =A0 =A0 =A0 =A0if (node && ppc_md.pci_probe_mode)
> @@ -1742,8 +1744,11 @@ void __devinit pcibios_scan_phb(struct pci_control=
ler *hose)
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0of_scan_bus(node, bus);
> =A0 =A0 =A0 =A0}
>
> - =A0 =A0 =A0 if (mode =3D=3D PCI_PROBE_NORMAL)
> + =A0 =A0 =A0 if (mode =3D=3D PCI_PROBE_NORMAL) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 pci_bus_update_busn_res_end(bus, 255);
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0hose->last_busno =3D bus->subordinate =3D =
pci_scan_child_bus(bus);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 pci_bus_update_busn_res_end(bus, bus->subor=
dinate);
> + =A0 =A0 =A0 }
>
> we'd have something more like:
>
> =A0 =A0 =A0 =A0/* Get probe mode and perform scan */
> =A0 =A0 =A0 =A0mode =3D PCI_PROBE_NORMAL;
> =A0 =A0 =A0 =A0if (node && ppc_md.pci_probe_mode)
> @@ -1742,8 +1744,11 @@ void __devinit pcibios_scan_phb(struct pci_control=
ler *hose)
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0of_scan_bus(node, bus);
> =A0 =A0 =A0 =A0}
>
> =A0 =A0 =A0 =A0if (mode =3D=3D PCI_PROBE_NORMAL)
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0hose->last_busno =3D bus->subordinate =3D =
pci_scan_child_bus(bus);
>
> + =A0 =A0 =A0 pci_bus_insert_busn_res(bus, hose->first_busno, hose->last_=
busno);
>
> since we should have the final bus range by then? =A0Setting the end to
> 255 and then changing it again doesn't make sense; and definitely makes
> the code hard to follow.
I have two issues here:
1) hose->last_busno is currently the highest bus number found by
pci_scan_child_bus(). If I understand correctly,
pci_bus_insert_busn_res() is supposed to update the core's idea of the
host bridge's bus number aperture. (Actually, I guess it just updates
the *end* of the aperture, since we supply the start directly to
pci_scan_root_bus()). The aperture and the highest bus number we
found are not related, except that we should have:
hose->first_busno <=3D bus->subordinate <=3D hose->last_busno
If we set the aperture to [first_busno - last_busno], we artificially
prevent some hotplug.
2) We already have a way to add resources to a root bus: the
pci_add_resource() used to add I/O port and MMIO apertures. I think
it'd be a lot simpler to just use that same interface for the bus
number aperture, e.g.,
pci_add_resource(&resources, hose->io_space);
pci_add_resource(&resources, hose->mem_space);
pci_add_resource(&resources, hose->busnr_space);
bus =3D pci_scan_root_bus(dev, next_busno, pci_ops, sysdata, &resources=
);
This is actually a bit redundant, since "next_busno" should be the
same as hose->busnr_space->start. So if we adopted this approach, we
might want to eventually drop the "next_busno" argument.
Bjorn
^ permalink raw reply
* Re: [PATCH v3 22/25] irq_domain/x86: Convert x86 (embedded) to use common irq_domain
From: Sebastian Andrzej Siewior @ 2012-02-23 21:22 UTC (permalink / raw)
To: Grant Likely
Cc: Stephen Rothwell, devicetree-discuss, linux-kernel, Rob Herring,
Milton Miller, Thomas Gleixner, linuxppc-dev, linux-arm-kernel
In-Reply-To: <CACxGe6tQvBZBMynXbknWx1o1s5TPEN7rXrNOOAjC5F_dz9B51w@mail.gmail.com>
On 02/23/2012 08:56 PM, Grant Likely wrote:
> On Wed, Feb 1, 2012 at 11:06 AM, Grant Likely<grant.likely@secretlab.ca> wrote:
>> On Wed, Feb 1, 2012 at 7:17 AM, Sebastian Andrzej Siewior
>> <bigeasy@linutronix.de> wrote:
>>> * Grant Likely | 2012-01-30 12:58:42 [-0700]:
>>>
>>>> Ugh. This isn't easy. The legacy mapping really needs all the
>>>
>>> Feel free to merge this patch. I don't have the time to look at this now
>>> so I take a look at the ioapic later.
>>
>> There's no rush here. I can leave it as-is with IRQ_DOMAIN turned off
>> for x86 for now.
>
> Turns out I have to enable IRQ_DOMAIN for x86 because the TI TWL4030
> driver needs it. I do need to apply this patch. Until something
> better can be implemented, can I change ioapic_add_ofnode() so that it
> allocates all irq_descs immediately. It's not ideal, but every other
> approach I've looked at results in nasty hacks.
>
> Looking at the ioapic code, it appears to handle preallocated
> irq_descs gracefully.
Please merge your initial patch as-it.
> Does adding this loop help (apologies if it is whitespace damaged, I
> cut&paste it):
>
> diff --git a/arch/x86/kernel/devicetree.c b/arch/x86/kernel/devicetree.c
> index 3ae2ced..89c1310 100644
> --- a/arch/x86/kernel/devicetree.c
> +++ b/arch/x86/kernel/devicetree.c
> @@ -345,7 +345,7 @@ const struct irq_domain_ops ioapic_irq_domain_ops = {
> static void __init ioapic_add_ofnode(struct device_node *np)
> {
> struct resource r;
> - int i, ret;
> + int i, j, ret;
>
> ret = of_address_to_resource(np, 0,&r);
> if (ret) {
> @@ -361,6 +361,14 @@ static void __init ioapic_add_ofnode(struct
> device_node *np)
>
> gsi_cfg = mp_ioapic_gsi_routing(i);
>
> + /*
> + * Preallocate irq_descs so that the legacy mapping
> + * works, but don't set them up.
> + * io_apic_setup_irq_pin_once() will finish the set up.
> + */
> + for (j = 0; j< 32; j++)
It is not 32. If I remember correctly the first ioapic had 24 pins so
did the second. This is ioapic specifc.
>
> g.
Sebastian
^ permalink raw reply
* Re: [PATCH v3 22/25] irq_domain/x86: Convert x86 (embedded) to use common irq_domain
From: Grant Likely @ 2012-02-23 21:39 UTC (permalink / raw)
To: Sebastian Andrzej Siewior
Cc: Stephen Rothwell, devicetree-discuss, linux-kernel, Rob Herring,
Milton Miller, Thomas Gleixner, linuxppc-dev, linux-arm-kernel
In-Reply-To: <4F46AE07.2000105@linutronix.de>
On Thu, Feb 23, 2012 at 10:22:15PM +0100, Sebastian Andrzej Siewior wrote:
> On 02/23/2012 08:56 PM, Grant Likely wrote:
> >On Wed, Feb 1, 2012 at 11:06 AM, Grant Likely<grant.likely@secretlab.ca> wrote:
> >>On Wed, Feb 1, 2012 at 7:17 AM, Sebastian Andrzej Siewior
> >><bigeasy@linutronix.de> wrote:
> >>>* Grant Likely | 2012-01-30 12:58:42 [-0700]:
> >>>
> >>>>Ugh. This isn't easy. The legacy mapping really needs all the
> >>>
> >>>Feel free to merge this patch. I don't have the time to look at this now
> >>>so I take a look at the ioapic later.
> >>
> >>There's no rush here. I can leave it as-is with IRQ_DOMAIN turned off
> >>for x86 for now.
> >
> >Turns out I have to enable IRQ_DOMAIN for x86 because the TI TWL4030
> >driver needs it. I do need to apply this patch. Until something
> >better can be implemented, can I change ioapic_add_ofnode() so that it
> >allocates all irq_descs immediately. It's not ideal, but every other
> >approach I've looked at results in nasty hacks.
> >
> >Looking at the ioapic code, it appears to handle preallocated
> >irq_descs gracefully.
>
> Please merge your initial patch as-it.
Okay, will do.
> >Does adding this loop help (apologies if it is whitespace damaged, I
> >cut&paste it):
> >
> >diff --git a/arch/x86/kernel/devicetree.c b/arch/x86/kernel/devicetree.c
> >index 3ae2ced..89c1310 100644
> >--- a/arch/x86/kernel/devicetree.c
> >+++ b/arch/x86/kernel/devicetree.c
> >@@ -345,7 +345,7 @@ const struct irq_domain_ops ioapic_irq_domain_ops = {
> > static void __init ioapic_add_ofnode(struct device_node *np)
> > {
> > struct resource r;
> >- int i, ret;
> >+ int i, j, ret;
> >
> > ret = of_address_to_resource(np, 0,&r);
> > if (ret) {
> >@@ -361,6 +361,14 @@ static void __init ioapic_add_ofnode(struct
> >device_node *np)
> >
> > gsi_cfg = mp_ioapic_gsi_routing(i);
> >
> >+ /*
> >+ * Preallocate irq_descs so that the legacy mapping
> >+ * works, but don't set them up.
> >+ * io_apic_setup_irq_pin_once() will finish the set up.
> >+ */
> >+ for (j = 0; j< 32; j++)
>
> It is not 32. If I remember correctly the first ioapic had 24 pins so
> did the second. This is ioapic specifc.
Is this better (bigger diffstat, but mostly due to renaming a local varable):
---
diff --git a/arch/x86/kernel/devicetree.c b/arch/x86/kernel/devicetree.c
index 3ae2ced..4028dc6 100644
--- a/arch/x86/kernel/devicetree.c
+++ b/arch/x86/kernel/devicetree.c
@@ -345,7 +345,7 @@ const struct irq_domain_ops ioapic_irq_domain_ops = {
static void __init ioapic_add_ofnode(struct device_node *np)
{
struct resource r;
- int i, ret;
+ int i, irq, ret;
ret = of_address_to_resource(np, 0, &r);
if (ret) {
@@ -357,13 +357,22 @@ static void __init ioapic_add_ofnode(struct device_node *np)
for (i = 0; i < nr_ioapics; i++) {
if (r.start == mpc_ioapic_addr(i)) {
struct irq_domain *id;
- struct mp_ioapic_gsi *gsi_cfg;
-
- gsi_cfg = mp_ioapic_gsi_routing(i);
-
- id = irq_domain_add_legacy(np, 32, gsi_cfg->gsi_base, 0,
- &ioapic_irq_domain_ops,
- (void*)i);
+ struct mp_ioapic_gsi *cfg;
+
+ cfg = mp_ioapic_gsi_routing(i);
+
+ /*
+ * Preallocate irq_descs so that the legacy mapping
+ * works, but don't set them up.
+ * io_apic_setup_irq_pin_once() will finish the set up.
+ */
+ for (irq = cfg->gsi_base; irq <= cfg->gsi_end; irq++)
+ irq_alloc_desc_at(irq, cpu_to_node(0));
+
+ id = irq_domain_add_legacy(np,
+ cfg->gsi_end - cfg->gsi_base + 1,
+ cfg->gsi_base, 0,
+ &ioapic_irq_domain_ops, (void*)i);
BUG_ON(!id);
return;
}
^ permalink raw reply related
* RE: [PATCH] powerpc/85xx: allow CONFIG_PHYS_64BIT to be selectable
From: Huang Changming-R66093 @ 2012-02-24 1:54 UTC (permalink / raw)
To: Tabi Timur-B04825
Cc: linuxppc-dev@ozlabs.org, Li Yang-R58472, Wood Scott-B07421
In-Reply-To: <4F463006.7060507@freescale.com>
> -----Original Message-----
> From: Tabi Timur-B04825
> Sent: Thursday, February 23, 2012 8:25 PM
> To: Huang Changming-R66093
> Cc: galak@kernel.crashing.org; benh@kernel.crashing.org; Wood Scott-
> B07421; Li Yang-R58472; linuxppc-dev@ozlabs.org
> Subject: Re: [PATCH] powerpc/85xx: allow CONFIG_PHYS_64BIT to be
> selectable
>=20
> Huang Changming-R66093 wrote:
> > I have one similar patch to remove the "select PHYS_64BIT".
> > http://patchwork.ozlabs.org/patch/132351/
>=20
> That one doesn't update the defconfigs, which means that the default
> kernel will not have PHYS_64BIT enabled.
I think it is not necessary to enable the 64BIT,
if customer want to enable it, he can do it manually.=20
^ permalink raw reply
* RE: [PATCH] powerpc/85xx: allow CONFIG_PHYS_64BIT to be selectable
From: Li Yang-R58472 @ 2012-02-24 2:29 UTC (permalink / raw)
To: Huang Changming-R66093, Tabi Timur-B04825
Cc: linuxppc-dev@ozlabs.org, Wood Scott-B07421
In-Reply-To: <110EED8CC96DFC488B7E717A2027A27C02E4A8@039-SN1MPN1-002.039d.mgd.msft.net>
> > Subject: Re: [PATCH] powerpc/85xx: allow CONFIG_PHYS_64BIT to be
> > selectable
> >
> > Huang Changming-R66093 wrote:
> > > I have one similar patch to remove the "select PHYS_64BIT".
> > > http://patchwork.ozlabs.org/patch/132351/
> >
> > That one doesn't update the defconfigs, which means that the default
> > kernel will not have PHYS_64BIT enabled.
> I think it is not necessary to enable the 64BIT, if customer want to
> enable it, he can do it manually.
I agree with Changming that we shouldn't setting PHYS_64BIT by default. Fo=
r the platforms covered by the mpc85xx_defconfig, most user won't need the =
PHYS_64BIT. We shouldn't set the one with worse performance and unnecessar=
y to most people as default. Also all these platforms supports 32-bit mode=
.
- Leo
^ permalink raw reply
* Re: How to handle cache when I allocate phys memory?
From: Ayman El-Khashab @ 2012-02-23 23:13 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: linuxppc-dev
In-Reply-To: <1318577991.29415.514.camel@pasglop>
I never did get this to work, and now I am back to it again.
On Fri, Oct 14, 2011 at 09:39:51AM +0200, Benjamin Herrenschmidt wrote:
> On Wed, 2011-10-12 at 16:08 -0500, Ayman El-Khashab wrote:
> > I'm using the 460sx (440 core) so no snooping here. What
> > I've done is reserved the top of memory for my driver. My
> > driver can read/write the memory and I can mmap it just
> > fine. The problem is I want to enable caching on the mmap
> > for performance but I don't know / can't figure out how to
> > tell the kernel to sync the cache after it gets dma data
> > from the device or after i put data into it from user space.
> > I know how to do it from regular devices, but not when I've
> > allocated the physical memory myself. I suppose what I am
> > looking for is something akin to dma_sync_single cpu/device.
> >
> > In my device driver, I am allocating the memory like this,
> > in this case the buffer is about 512MB.
> >
> > vma->vm_flags |= VM_LOCKED | VM_RESERVED;
> >
> > /* map the physical area into one buffer */
> > rc = remap_pfn_range(vma, vma->vm_start,
> > (PHYS_MEM_ADDR)>>PAGE_SHIFT,
> > len, vma->vm_page_prot);
> >
> > Is this going to give me the best performance, or is there
> > something more I can do?
> >
> > Failing that, what is the best way to do this (i need a very
> > large contiguous buffer). it runs in batch mode, so it
> > DMAs, stops, cpu reads, cpu writes, repeat ...
>
> Did you try looking at what the dma_* functions do under the hood and
> call it directly (or reproducing it) ?
>
> Basically it boils down to using dcbf instructions to flush dirty data
> or dcbi to invalidate cache lines.
>
I've reserved (using mem=) memory at the top of my system.
In my case, its the upper 1GB of 2GB total. I've got a
small driver that I've written that maps it into user space
using mmap .. that all works fine. I've also got it caching
and that also works. The problem is that depending on how I
do things, I can get some cache-coherency issues. I know in
the user code where to poke things, but I've tried
everything I can think of and *cannot* get flush_dcache_range
to work for me.
My mapping code in the driver is:
static int my_mmap(struct file *fip, struct
vm_area_struct *vma)
{
int rc;
unsigned long len = vma->vm_end - vma->vm_start;
printk(KERN_DEBUG "mapping %ld bytes\n", len);
vma->vm_page_prot = pgprot_cached(vma->vm_page_prot);
kernel_vp = ioremap(PHYS_MEM_ADDR, 1<<20);
rc = remap_pfn_range(vma, vma->vm_start,
(PHYS_MEM_ADDR)>>PAGE_SHIFT,
len, vma->vm_page_prot);
return (rc < 0 ? rc : 0);
}
I've stripped out some comments but otherwise, this is it.
I've tried both with and without ioremap, both fail in the
same way. I've changed the vma->vm_page_prot a number of
ways. In this example, I had knocked the size of ioremap
(and the flush) to 1MB to see if it was a size issue, but
the kernel gives an error as soon as the first dcbf
instruction is executed in the flush loop.
Then I've got an ioctl to flush
case CACHE_FLUSH:
{
u_int32_t phys_start = phys_mem_addr<<20;
u_int32_t phys_stop = (phys_mem_addr +
phys_mem_size)<<20;
//flush_dcache_range(phys_start, phys_stop-1);
flush_dcache_range(kernel_vp, kernel_vp +
(1<<20));
}
break;
kernel_vp is a virtual pointer from ioremap (only 1MB in
size). The phys_stop and phys_start is the physical address
range, which I think might be wrong. It does not work in
either case anyway.
I'd really like to map 1G, make it cachable and do the flush
and invalidate on demand ... what am I missing? Here is the
kernel dump
##########Unable to handle kernel paging request for data at
address 0x40000000
##Faulting instruction address: 0xc000c398
##Oops: Kernel access of bad area, sig: 11 [#1]
PowerPC 44x Platform
last sysfs file:
/sys/devices/plb.0/opb.3/4ef600400.i2c/i2c-0/0-0022/gpio/gpio223/value
Modules linked in: tan_mpt2sas tanomem [last unloaded:
tanomem]
NIP: c000c398 LR: f4fd91d4 CTR: 02000000
REGS: ebad7dc0 TRAP: 0300 Not tainted
(2.6.37.6-tanisys-sx2-24099)
MSR: 00029000 <EE,ME,CE> CR: 48040242 XER: 00000001
DEAR: 40000000, ESR: 00800000
TASK = ebceb0c0[2720] 'testapplication' THREAD: ebad6000
GPR00: 00000400 ebad7e70 ebceb0c0 40000000 02000000 0000001f
28040244 101132b0
GPR08: 0002d000 f4fd9590 ebbda180 c000c37c 00000000 101a47c8
00000003 bfa4d229
GPR16: bfd98f84 1003a5f8 101416c0 101414b0 bfa4baa8 bfa4bb1c
bfa4bd00 00000000
GPR24: 00000000 101a1514 bfa4d69c ebbda180 fffffff7 c0045402
28040244 28040244
NIP [c000c398] invalidate_dcache_range+0x1c/0x30
LR [f4fd91d4] tanomem_ioctl+0xc8/0x200 [tanomem]
Call Trace:
[ebad7e70] [00029000] 0x29000 (unreliable)
[ebad7e90] [c00ac98c] vfs_ioctl+0x40/0x64
[ebad7ea0] [c00acb7c] do_vfs_ioctl+0x88/0x6fc
[ebad7f10] [c00ad230] sys_ioctl+0x40/0x74
[ebad7f40] [c000c7dc] ret_from_syscall+0x0/0x3c
--- Exception: c01 at 0x1011ad90
LR = 0x10021508
Instruction dump:
7c0018ac 38630020 4200fff8 7c0004ac 4e800020 38a0001f
7c632878 7c832050
7c842a14 5484d97f 4d820020 7c8903a6 <7c001bac> 38630020
4200fff8 7c0004ac
# Kernel panic - not syncing: Fatal exception
IRebooting in 5 seconds..dentifyDevice ###############
Thanks,
Ayman
^ permalink raw reply
* Re: [PATCH] powerpc/85xx: allow CONFIG_PHYS_64BIT to be selectable
From: Tabi Timur-B04825 @ 2012-02-24 2:45 UTC (permalink / raw)
To: Li Yang-R58472
Cc: linuxppc-dev@ozlabs.org, Huang Changming-R66093,
Wood Scott-B07421
In-Reply-To: <94F013E7935FF44C83EBE7784D62AD3F0578CD9A@039-SN2MPN1-023.039d.mgd.msft.net>
Li Yang-R58472 wrote:
> I agree with Changming that we shouldn't setting PHYS_64BIT by default.
The default kernel should always be the compatible with as much as=20
possible. Disabling PHYS_64BIT by default means that the default kernel=20
will not work with a 36-bit DTS. If you attempt to boot such a kernel=20
with a 36-bit DTS, there will be no text output. Most people will not=20
know why it's not working.
So the safest option is for PHYS_64BIT to be enabled by default. That=20
way, the kernel will always work.
--=20
Timur Tabi
Linux kernel developer at Freescale=
^ permalink raw reply
* RE: [PATCH] powerpc/85xx: allow CONFIG_PHYS_64BIT to be selectable
From: Li Yang-R58472 @ 2012-02-24 2:59 UTC (permalink / raw)
To: Tabi Timur-B04825
Cc: linuxppc-dev@ozlabs.org, Huang Changming-R66093,
Wood Scott-B07421
In-Reply-To: <4F46F9CF.6040600@freescale.com>
> -----Original Message-----
> From: Tabi Timur-B04825
> Sent: Friday, February 24, 2012 10:46 AM
> To: Li Yang-R58472
> Cc: Huang Changming-R66093; galak@kernel.crashing.org;
> benh@kernel.crashing.org; Wood Scott-B07421; linuxppc-dev@ozlabs.org
> Subject: Re: [PATCH] powerpc/85xx: allow CONFIG_PHYS_64BIT to be
> selectable
>=20
> Li Yang-R58472 wrote:
>=20
> > I agree with Changming that we shouldn't setting PHYS_64BIT by default.
>=20
> The default kernel should always be the compatible with as much as
> possible. Disabling PHYS_64BIT by default means that the default kernel
> will not work with a 36-bit DTS. If you attempt to boot such a kernel
> with a 36-bit DTS, there will be no text output. Most people will not
> know why it's not working.
>=20
> So the safest option is for PHYS_64BIT to be enabled by default. That
> way, the kernel will always work.
Even though the user still need to know the addressing mode that u-boot is =
using. It won't work if the addressing mode of u-boot and device tree are =
different.
- Leo
^ permalink raw reply
* RE: [PATCH] powerpc/85xx: allow CONFIG_PHYS_64BIT to be selectable
From: Huang Changming-R66093 @ 2012-02-24 3:01 UTC (permalink / raw)
To: Li Yang-R58472, Tabi Timur-B04825
Cc: linuxppc-dev@ozlabs.org, Wood Scott-B07421
In-Reply-To: <94F013E7935FF44C83EBE7784D62AD3F0578CFD9@039-SN2MPN1-023.039d.mgd.msft.net>
> > -----Original Message-----
> > From: Tabi Timur-B04825
> > Sent: Friday, February 24, 2012 10:46 AM
> > To: Li Yang-R58472
> > Cc: Huang Changming-R66093; galak@kernel.crashing.org;
> > benh@kernel.crashing.org; Wood Scott-B07421; linuxppc-dev@ozlabs.org
> > Subject: Re: [PATCH] powerpc/85xx: allow CONFIG_PHYS_64BIT to be
> > selectable
> >
> > Li Yang-R58472 wrote:
> >
> > > I agree with Changming that we shouldn't setting PHYS_64BIT by
> default.
> >
> > The default kernel should always be the compatible with as much as
> > possible. Disabling PHYS_64BIT by default means that the default
> > kernel will not work with a 36-bit DTS. If you attempt to boot such a
> > kernel with a 36-bit DTS, there will be no text output. Most people
> > will not know why it's not working.
> >
> > So the safest option is for PHYS_64BIT to be enabled by default. That
> > way, the kernel will always work.
>=20
> Even though the user still need to know the addressing mode that u-boot
> is using. It won't work if the addressing mode of u-boot and device tree
> are different.
>=20
Yes, u-boot must has the same address mode with DTS, otherwise, we can't bo=
ot the kernel.
^ permalink raw reply
* Re: [PATCH] powerpc/85xx: allow CONFIG_PHYS_64BIT to be selectable
From: Tabi Timur-B04825 @ 2012-02-24 3:04 UTC (permalink / raw)
To: Li Yang-R58472
Cc: linuxppc-dev@ozlabs.org, Huang Changming-R66093,
Wood Scott-B07421
In-Reply-To: <94F013E7935FF44C83EBE7784D62AD3F0578CFD9@039-SN2MPN1-023.039d.mgd.msft.net>
Li Yang-R58472 wrote:
> Even though the user still need to know the addressing mode that u-boot
> is using. It won't work if the addressing mode of u-boot and device
> tree are different.
U-Boot will tell the user if the DT does not match. I added code to=20
U-Boot to do that. So if you have a 36-bit U-Boot and a 32-bit DT, then=20
you will get a warning. If you have a 36-bit U-boot and a 36-bit DT and a=
=20
32-bit kernel, you will get nothing. But if you have a 32-bit U-boot and=20
a 32-bit DT and a 36-bit kernel, then that will work. A 36-bit kernel=20
works with 32-bit *and* 36-bit DTs. This is why a 36-bit kernel should be=
=20
the default.
--=20
Timur Tabi
Linux kernel developer at Freescale=
^ permalink raw reply
* RE: [PATCH] powerpc/85xx: allow CONFIG_PHYS_64BIT to be selectable
From: Huang Changming-R66093 @ 2012-02-24 3:24 UTC (permalink / raw)
To: Tabi Timur-B04825, Li Yang-R58472
Cc: linuxppc-dev@ozlabs.org, Wood Scott-B07421
In-Reply-To: <4F46FE3E.1050605@freescale.com>
>=20
> Li Yang-R58472 wrote:
>=20
> > Even though the user still need to know the addressing mode that
> > u-boot is using. It won't work if the addressing mode of u-boot and
> > device tree are different.
>=20
> U-Boot will tell the user if the DT does not match. I added code to U-
> Boot to do that. So if you have a 36-bit U-Boot and a 32-bit DT, then
> you will get a warning. If you have a 36-bit U-boot and a 36-bit DT and
> a 32-bit kernel, you will get nothing. But if you have a 32-bit U-boot
> and a 32-bit DT and a 36-bit kernel, then that will work. A 36-bit
> kernel works with 32-bit *and* 36-bit DTs. This is why a 36-bit kernel
> should be the default.
>=20
> --
Hi, Timur
I want to know if you have the other codes for different address?
The current U-boot just detect the base address of DTS and the CCSR address=
.
If they are different, u-boot will print the warning and return 0,
so the kernel can't been booted.
Jerry.
^ permalink raw reply
* Re: [PATCH] powerpc/85xx: allow CONFIG_PHYS_64BIT to be selectable
From: Tabi Timur-B04825 @ 2012-02-24 3:36 UTC (permalink / raw)
To: Huang Changming-R66093
Cc: linuxppc-dev@ozlabs.org, Wood Scott-B07421, Li Yang-R58472
In-Reply-To: <110EED8CC96DFC488B7E717A2027A27C02E5C3@039-SN1MPN1-002.039d.mgd.msft.net>
Huang Changming-R66093 wrote:
> I want to know if you have the other codes for different address?
>
> The current U-boot just detect the base address of DTS and the CCSR addre=
ss.
> If they are different, u-boot will print the warning and return 0,
> so the kernel can't been booted.
I had a patch that verified some PCI addresses (which are sometimes=20
slightly mismatched), but Kumar rejected it.
I could add some more checks, but the 90% of the time, the only problem is=
=20
using the wrong size (32-bit vs 36-bit) DT.
--=20
Timur Tabi
Linux kernel developer at Freescale=
^ permalink raw reply
* RE: [PATCH] powerpc/85xx: allow CONFIG_PHYS_64BIT to be selectable
From: Li Yang-R58472 @ 2012-02-24 3:40 UTC (permalink / raw)
To: Tabi Timur-B04825
Cc: linuxppc-dev@ozlabs.org, Huang Changming-R66093,
Wood Scott-B07421
In-Reply-To: <4F46FE3E.1050605@freescale.com>
> Subject: Re: [PATCH] powerpc/85xx: allow CONFIG_PHYS_64BIT to be
> selectable
>=20
> Li Yang-R58472 wrote:
>=20
> > Even though the user still need to know the addressing mode that
> > u-boot is using. It won't work if the addressing mode of u-boot and
> > device tree are different.
>=20
> U-Boot will tell the user if the DT does not match. I added code to U-
> Boot to do that. So if you have a 36-bit U-Boot and a 32-bit DT, then
> you will get a warning. If you have a 36-bit U-boot and a 36-bit DT and
> a 32-bit kernel, you will get nothing. But if you have a 32-bit U-boot
> and a 32-bit DT and a 36-bit kernel, then that will work. A 36-bit
> kernel works with 32-bit *and* 36-bit DTs. This is why a 36-bit kernel
> should be the default.
The mpc85xx_defconfig does include silicons with e500v1 core which doesn't =
have the 36-bit support. Won't enabling 36-bit support by default break th=
e support for them?
- Leo
^ permalink raw reply
* Re: [PATCH] powerpc/85xx: allow CONFIG_PHYS_64BIT to be selectable
From: Tabi Timur-B04825 @ 2012-02-24 3:50 UTC (permalink / raw)
To: Li Yang-R58472
Cc: linuxppc-dev@ozlabs.org, Huang Changming-R66093,
Wood Scott-B07421
In-Reply-To: <94F013E7935FF44C83EBE7784D62AD3F0578D305@039-SN2MPN1-023.039d.mgd.msft.net>
Li Yang-R58472 wrote:
> The mpc85xx_defconfig does include silicons with e500v1 core which
> doesn't have the 36-bit support. Won't enabling 36-bit support by
> default break the support for them?
No. The kernel will detect at runtime that that it's an e500v1 core and=20
it won't try to create 36-bit TLBs. (e.g. it won't write to MAS7).
Please remember that the Kconfig for the P1022DS already forced PHYS_64BIT=
=20
for all mpc85xx platforms. All we're doing is making it possible to=20
deselect PHYS_64BIT.
--=20
Timur Tabi
Linux kernel developer at Freescale=
^ permalink raw reply
* RE: [PATCH] powerpc/85xx: allow CONFIG_PHYS_64BIT to be selectable
From: Li Yang-R58472 @ 2012-02-24 4:02 UTC (permalink / raw)
To: Tabi Timur-B04825
Cc: linuxppc-dev@ozlabs.org, Huang Changming-R66093,
Wood Scott-B07421
In-Reply-To: <4F470910.9080008@freescale.com>
> Subject: Re: [PATCH] powerpc/85xx: allow CONFIG_PHYS_64BIT to be
> selectable
>=20
> Li Yang-R58472 wrote:
>=20
> > The mpc85xx_defconfig does include silicons with e500v1 core which
> > doesn't have the 36-bit support. Won't enabling 36-bit support by
> > default break the support for them?
>=20
> No. The kernel will detect at runtime that that it's an e500v1 core and
> it won't try to create 36-bit TLBs. (e.g. it won't write to MAS7).
It's a good point. Why can't we decide to use 32-bit/36-bit TLB at runtime=
even for e500v2?
>=20
> Please remember that the Kconfig for the P1022DS already forced
> PHYS_64BIT for all mpc85xx platforms. All we're doing is making it
> possible to deselect PHYS_64BIT.
I think it's a side-effect introduced by P1022DS support and need to be fix=
ed. There was no mentioning of enforcing 36-bit for all mpc85xx platforms.
- Leo
^ permalink raw reply
* Re: [PATCH] powerpc/85xx: allow CONFIG_PHYS_64BIT to be selectable
From: Tabi Timur-B04825 @ 2012-02-24 4:11 UTC (permalink / raw)
To: Li Yang-R58472
Cc: linuxppc-dev@ozlabs.org, Huang Changming-R66093,
Wood Scott-B07421
In-Reply-To: <94F013E7935FF44C83EBE7784D62AD3F0578D5BD@039-SN2MPN1-023.039d.mgd.msft.net>
Li Yang-R58472 wrote:
> It's a good point. Why can't we decide to use 32-bit/36-bit TLB at runti=
me even for e500v2?
That's not what PHYS_64BIT does. PHYS_64BIT determines whether=20
phys_addr_t is a u64 or a u32. This is something that must be determined=20
at compilation time.
>> Please remember that the Kconfig for the P1022DS already forced
>> PHYS_64BIT for all mpc85xx platforms. All we're doing is making it
>> possible to deselect PHYS_64BIT.
>
> I think it's a side-effect introduced by P1022DS support and need to be f=
ixed.
Exactly. That's what these patches do. And these patches have been=20
applied to the SDK. I'm just waiting for Kumar to apply them to his=20
repository.
> There was no mentioning of enforcing 36-bit for all mpc85xx platforms.
It's not enforcing, it's just the default. If you build with=20
mpc85xx_smp_defconfig, then you'll get a 36-bit kernel. But now you can=20
also use menuconfig to turn off PHYS_64BIT. Before these fixes, that was=20
not possible.
--=20
Timur Tabi
Linux kernel developer at Freescale=
^ permalink raw reply
* Re: linux-next: manual merge of the irqdomain tree with the powerpc tree
From: Stephen Rothwell @ 2012-02-24 5:30 UTC (permalink / raw)
To: Grant Likely
Cc: linux-kernel, linux-next, Paul Mackerras, Kyle Moffett,
linuxppc-dev
In-Reply-To: <20120224162504.49480de981431c3fd95601a2@canb.auug.org.au>
[-- Attachment #1: Type: text/plain, Size: 1506 bytes --]
[Just adding the PPC guys]
On Fri, 24 Feb 2012 16:25:04 +1100 Stephen Rothwell <sfr@canb.auug.org.au> wrote:
>
> Hi Grant,
>
> Today's linux-next merge of the irqdomain tree got a conflict in
> arch/powerpc/sysdev/mpic.c between commits 3a7a7176e840 ("powerpc/mpic:
> Fix use of "flags" variable in mpic_alloc()") and c1b8d45db4db
> ("powerpc/mpic: Add "last-interrupt-source" property to override
> hardware") from the powerpc tree and commit a8db8cf0d894 ("irq_domain:
> Replace irq_alloc_host() with revmap-specific initializers") from the
> irqdomain tree.
>
> I fixed it up (see below) and can carry the fix as necessary.
> --
> Cheers,
> Stephen Rothwell sfr@canb.auug.org.au
>
> diff --cc arch/powerpc/sysdev/mpic.c
> index b9b989d,c83a512..0000000
> --- a/arch/powerpc/sysdev/mpic.c
> +++ b/arch/powerpc/sysdev/mpic.c
> @@@ -1351,9 -1345,9 +1351,8 @@@ struct mpic * __init mpic_alloc(struct
> mpic->isu_shift = 1 + __ilog2(mpic->isu_size - 1);
> mpic->isu_mask = (1 << mpic->isu_shift) - 1;
>
> - mpic->irqhost = irq_alloc_host(mpic->node, IRQ_HOST_MAP_LINEAR,
> - mpic->isu_size, &mpic_host_ops,
> - intvec_top + 1);
> + mpic->irqhost = irq_domain_add_linear(mpic->node,
> - isu_size ? isu_size : mpic->num_sources,
> - &mpic_host_ops, mpic);
> ++ mpic->isu_size, &mpic_host_ops, mpic);
>
> /*
> * FIXME: The code leaks the MPIC object and mappings here; this
[-- Attachment #2: Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* Re: linux-next: manual merge of the irqdomain tree with the powerpc tree
From: Grant Likely @ 2012-02-24 6:07 UTC (permalink / raw)
To: Stephen Rothwell
Cc: linux-kernel, linux-next, Paul Mackerras, Kyle Moffett,
linuxppc-dev
In-Reply-To: <20120224163042.4cc2633945c9799b997ff4e7@canb.auug.org.au>
On Thu, Feb 23, 2012 at 10:30 PM, Stephen Rothwell <sfr@canb.auug.org.au> w=
rote:
> [Just adding the PPC guys]
>
> On Fri, 24 Feb 2012 16:25:04 +1100 Stephen Rothwell <sfr@canb.auug.org.au=
> wrote:
>>
>> Hi Grant,
>>
>> Today's linux-next merge of the irqdomain tree got a conflict in
>> arch/powerpc/sysdev/mpic.c between commits 3a7a7176e840 ("powerpc/mpic:
>> Fix use of "flags" variable in mpic_alloc()") and c1b8d45db4db
>> ("powerpc/mpic: Add "last-interrupt-source" property to override
>> hardware") from the powerpc tree and commit a8db8cf0d894 ("irq_domain:
>> Replace irq_alloc_host() with revmap-specific initializers") from the
>> irqdomain tree.
>>
>> I fixed it up (see below) and can carry the fix as necessary.
Thanks Stephen.
g.
>> --
>> Cheers,
>> Stephen Rothwell =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0sfr@canb.auug.or=
g.au
>>
>> diff --cc arch/powerpc/sysdev/mpic.c
>> index b9b989d,c83a512..0000000
>> --- a/arch/powerpc/sysdev/mpic.c
>> +++ b/arch/powerpc/sysdev/mpic.c
>> @@@ -1351,9 -1345,9 +1351,8 @@@ struct mpic * __init mpic_alloc(struct
>> =A0 =A0 =A0 mpic->isu_shift =3D 1 + __ilog2(mpic->isu_size - 1);
>> =A0 =A0 =A0 mpic->isu_mask =3D (1 << mpic->isu_shift) - 1;
>>
>> - =A0 =A0 mpic->irqhost =3D irq_alloc_host(mpic->node, IRQ_HOST_MAP_LINE=
AR,
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0mpic->isu_size, &mpic_host_ops,
>> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0intvec_top + 1);
>> + =A0 =A0 mpic->irqhost =3D irq_domain_add_linear(mpic->node,
>> =A0- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
isu_size ? isu_size : mpic->num_sources,
>> =A0- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
&mpic_host_ops, mpic);
>> ++ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 m=
pic->isu_size, &mpic_host_ops, mpic);
>>
>> =A0 =A0 =A0 /*
>> =A0 =A0 =A0 =A0* FIXME: The code leaks the MPIC object and mappings here=
; this
--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
^ permalink raw reply
* [PATCH v4 00/21] EEH reorganization
From: Gavin Shan @ 2012-02-24 9:37 UTC (permalink / raw)
To: linuxppc-dev; +Cc: kernel.crashing.org, shangw
This series of patches is going to reorganize EEH so that it could support
multiple platforms in future. The requirements were raised from the aspects.
* The original EEH implementation only support pSeries platform, which
would be regarded as guest system. Platform powernv is coming and EEH
needs to be supported on powernv as well.
* Different platforms might be running based on variable firmware.Further
more, the firmware would supply different EEH interfaces to kernel.
Therefore, we have to do necessary abstraction on current EEH implementation.
In order to accomodate the requirements, the series of patches have reorganized
current EEH implementation.
* The original implementation looks not clean enough. Necessary cleanup
will be done in some of the patches.
* struct eeh_ops has been introduced so that EEH core components and platform
dependent implementation could be split up. That make it possible for EEH
to be supported on multiple platforms.
* struct eeh_dev has been introduced to replace struct pci_dn so that EEH module
works independently as much as possible.
* EEH global statistics will be maintained in a collective fashion.
v1 -> v2:
* If possible, to add "eeh_" prefix for function names.
* The format of leading function comments won't be changed in order not to
break kernel document automatic generation (e.g. by "make pdfdocs").
* The name of local variables won't be changed if there're no explicit reasons.
* Represent the PE's state in bitmap fasion.
* Some function names have been adjusted so that they look shorter and
meaningful.
* Platform operation name has been changed to "pseries".
* Merge those patches for cleanup if possible.
* The line length is kept as appropriately short if possible.
* Fixup on alignment & spacing issues.
v2 -> v3:
* Split cleanup patch into 2: one for comment cleanup and another one for
renaming function names.
* Try to use pr_warning/pr_info/pr_debug instead of printk() function call.
* Function names are adjusted a little bit so that they looks more meaningful
according to comments from Michael/Ben.
* Useful comment has been kept according to Michael's comments.
* struct eeh_ops::set_eeh has been changed to eeh_ops::set_option.
* struct eeh_ops::name has been changed to "char *".
* Remove file name from the source file.
* Copyright (C) format has been changed since "(C)" isn't encouraged to use.
* The header files included in the source file have been sorted alphabetically.
* eeh_platform_init() has been replaced by eeh_pseries_init() to avoid duplicate
functions when kernel supports multiple platforms.
* "F/W" has been changed to "Firmware".
* The maximal wait time to retrieve PE's state has been covered by macro.
* It also include changes according to the minor comments from Michael.
v3 -> v4:
* Fix some typo included in the commit messages.
* Reduce code nesting according to Ram's suggestions.
* Addtinal pr_warning on failure of configuring bridges.
The series of patches (v4) has been verified on Firebird-L machine. In order to carry out
the test, you have to install IBM Power Tools from IBM internal yum source. Following
command is used to force EEH check on ethernet interface, which could be recovered eventually
by EEH and device driver successfully. You could keep pinging to the blade before issuing
the following command to force EEH. You should see the network interface can't be reached for
a moment and everything will be recovered couple of seconds after the forced EEH error. At the
same time, you should see EEH error log out of system console.
* errinjct eeh -v -f 0 -p U78AE.001.WZS00M9-P1-C18-L1-T2 -a 0x0 -m 0x0
-------------
arch/powerpc/include/asm/device.h | 3 -
arch/powerpc/include/asm/eeh.h | 143 +---
arch/powerpc/include/asm/eeh_event.h | 33 +-
arch/powerpc/include/asm/ppc-pci.h | 89 ++-
arch/powerpc/kernel/of_platform.c | 3 -
arch/powerpc/kernel/rtas_pci.c | 3 -
arch/powerpc/platforms/pseries/Makefile | 3 +-
arch/powerpc/platforms/pseries/eeh.c | 1016 +++++++++++++++-----------
arch/powerpc/platforms/pseries/eeh_cache.c | 44 +-
arch/powerpc/platforms/pseries/eeh_driver.c | 213 +++---
arch/powerpc/platforms/pseries/eeh_event.c | 55 +-
arch/powerpc/platforms/pseries/eeh_pseries.c | 565 --------------
arch/powerpc/platforms/pseries/eeh_sysfs.c | 25 +-
arch/powerpc/platforms/pseries/msi.c | 2 +-
arch/powerpc/platforms/pseries/pci_dlpar.c | 3 -
arch/powerpc/platforms/pseries/setup.c | 7 +-
include/linux/of.h | 3 -
17 files changed, 861 insertions(+), 1349 deletions(-)
Thanks,
Gavin
^ permalink raw reply
* [PATCH 08/21] pSeries platform EEH wait PE state
From: Gavin Shan @ 2012-02-24 9:38 UTC (permalink / raw)
To: linuxppc-dev; +Cc: kernel.crashing.org, shangw
In-Reply-To: <1330076298-7006-1-git-send-email-shangw@linux.vnet.ibm.com>
On pSeries platform, the PE state might be temporarily unavailable.
In that case, the firmware will return the corresponding wait time.
That means the kernel has to wait for appropriate time in order to
get the PE state.
The patch does the implementation for that. Besides, the function
has been abstracted through struct eeh_ops::wait_state so that EEH core
components could support multiple platforms in future.
Signed-off-by: Gavin Shan <shangw@linux.vnet.ibm.com>
---
arch/powerpc/include/asm/ppc-pci.h | 1 -
arch/powerpc/platforms/pseries/eeh.c | 46 +------------------------
arch/powerpc/platforms/pseries/eeh_driver.c | 2 +-
arch/powerpc/platforms/pseries/eeh_pseries.c | 47 +++++++++++++++++++++++++-
4 files changed, 49 insertions(+), 47 deletions(-)
diff --git a/arch/powerpc/include/asm/ppc-pci.h b/arch/powerpc/include/asm/ppc-pci.h
index 6150349..1cfb2b0 100644
--- a/arch/powerpc/include/asm/ppc-pci.h
+++ b/arch/powerpc/include/asm/ppc-pci.h
@@ -58,7 +58,6 @@ struct pci_dev *pci_get_device_by_addr(unsigned long addr);
void eeh_slot_error_detail (struct pci_dn *pdn, int severity);
int eeh_pci_enable(struct pci_dn *pdn, int function);
int eeh_reset_pe(struct pci_dn *);
-int eeh_wait_for_slot_status(struct pci_dn *pdn, int max_wait_msecs);
void eeh_restore_bars(struct pci_dn *);
void eeh_configure_bridge(struct pci_dn *);
int rtas_write_config(struct pci_dn *, int where, int size, u32 val);
diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c
index 8d11f1f..b5b03d4 100644
--- a/arch/powerpc/platforms/pseries/eeh.c
+++ b/arch/powerpc/platforms/pseries/eeh.c
@@ -287,48 +287,6 @@ void eeh_slot_error_detail(struct pci_dn *pdn, int severity)
}
/**
- * eeh_wait_for_slot_status - Returns error status of slot
- * @pdn: pci device node
- * @max_wait_msecs: maximum number to millisecs to wait
- *
- * Return negative value if a permanent error, else return
- * Partition Endpoint (PE) status value.
- *
- * If @max_wait_msecs is positive, then this routine will
- * sleep until a valid status can be obtained, or until
- * the max allowed wait time is exceeded, in which case
- * a -2 is returned.
- */
-int eeh_wait_for_slot_status(struct pci_dn *pdn, int max_wait_msecs)
-{
- int rc;
- int mwait;
-
- while (1) {
- rc = eeh_ops->get_state(pdn->node, &mwait);
- if (rc != EEH_STATE_UNAVAILABLE)
- return rc;
-
- if (max_wait_msecs <= 0) break;
-
- if (mwait <= 0) {
- printk(KERN_WARNING "EEH: Firmware returned bad wait value=%d\n",
- mwait);
- mwait = 1000;
- } else if (mwait > 300*1000) {
- printk(KERN_WARNING "EEH: Firmware is taking too long, time=%d\n",
- mwait);
- mwait = 300*1000;
- }
- max_wait_msecs -= mwait;
- msleep(mwait);
- }
-
- printk(KERN_WARNING "EEH: Timed out waiting for slot status\n");
- return -2;
-}
-
-/**
* eeh_token_to_phys - Convert EEH address token to phys address
* @token: I/O token, should be address in the form 0xA....
*
@@ -640,7 +598,7 @@ int eeh_pci_enable(struct pci_dn *pdn, int function)
printk(KERN_WARNING "EEH: Unexpected state change %d, err=%d dn=%s\n",
function, rc, pdn->node->full_name);
- rc = eeh_wait_for_slot_status(pdn, PCI_BUS_RESET_WAIT_MSEC);
+ rc = eeh_ops->wait_state(pdn->node, PCI_BUS_RESET_WAIT_MSEC);
if (rc > 0 && (rc & EEH_STATE_MMIO_ENABLED) &&
(function == EEH_OPT_THAW_MMIO))
return 0;
@@ -838,7 +796,7 @@ int eeh_reset_pe(struct pci_dn *pdn)
for (i=0; i<3; i++) {
eeh_reset_pe_once(pdn);
- rc = eeh_wait_for_slot_status(pdn, PCI_BUS_RESET_WAIT_MSEC);
+ rc = eeh_ops->wait_state(pdn->node, PCI_BUS_RESET_WAIT_MSEC);
if (rc == (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE))
return 0;
diff --git a/arch/powerpc/platforms/pseries/eeh_driver.c b/arch/powerpc/platforms/pseries/eeh_driver.c
index 4c6e0c1c..584defe 100644
--- a/arch/powerpc/platforms/pseries/eeh_driver.c
+++ b/arch/powerpc/platforms/pseries/eeh_driver.c
@@ -396,7 +396,7 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event)
/* Get the current PCI slot state. This can take a long time,
* sometimes over 3 seconds for certain systems. */
- rc = eeh_wait_for_slot_status (frozen_pdn, MAX_WAIT_FOR_RECOVERY*1000);
+ rc = eeh_ops->wait_state(frozen_pdn->node, MAX_WAIT_FOR_RECOVERY*1000);
if (rc < 0 || rc == EEH_STATE_NOT_SUPPORT) {
printk(KERN_WARNING "EEH: Permanent failure\n");
goto hard_fail;
diff --git a/arch/powerpc/platforms/pseries/eeh_pseries.c b/arch/powerpc/platforms/pseries/eeh_pseries.c
index 39567b2..7b60131 100644
--- a/arch/powerpc/platforms/pseries/eeh_pseries.c
+++ b/arch/powerpc/platforms/pseries/eeh_pseries.c
@@ -331,7 +331,52 @@ static int pseries_eeh_reset(struct device_node *dn, int option)
*/
static int pseries_eeh_wait_state(struct device_node *dn, int max_wait)
{
- return 0;
+ int ret;
+ int mwait;
+
+ /*
+ * According to PAPR, the state of PE might be temporarily
+ * unavailable. Under the circumstance, we have to wait
+ * for indicated time determined by firmware. The maximal
+ * wait time is 5 minutes, which is acquired from the original
+ * EEH implementation. Also, the original implementation
+ * also defined the minimal wait time as 1 second.
+ */
+#define EEH_STATE_MIN_WAIT_TIME (1000)
+#define EEH_STATE_MAX_WAIT_TIME (300 * 1000)
+
+ while (1) {
+ ret = pseries_eeh_get_state(dn, &mwait);
+
+ /*
+ * If the PE's state is temporarily unavailable,
+ * we have to wait for the specified time. Otherwise,
+ * the PE's state will be returned immediately.
+ */
+ if (ret != EEH_STATE_UNAVAILABLE)
+ return ret;
+
+ if (max_wait <= 0) {
+ pr_warning("%s: Timeout when getting PE's state (%d)\n",
+ __func__, max_wait);
+ return EEH_STATE_NOT_SUPPORT;
+ }
+
+ if (mwait <= 0) {
+ pr_warning("%s: Firmware returned bad wait value %d\n",
+ __func__, mwait);
+ mwait = EEH_STATE_MIN_WAIT_TIME;
+ } else if (mwait > EEH_STATE_MAX_WAIT_TIME) {
+ pr_warning("%s: Firmware returned too long wait value %d\n",
+ __func__, mwait);
+ mwait = EEH_STATE_MAX_WAIT_TIME;
+ }
+
+ max_wait -= mwait;
+ msleep(mwait);
+ }
+
+ return EEH_STATE_NOT_SUPPORT;
}
/**
--
1.7.5.4
^ permalink raw reply related
* [PATCH 21/21] pSeries platform config space access in EEH
From: Gavin Shan @ 2012-02-24 9:38 UTC (permalink / raw)
To: linuxppc-dev; +Cc: kernel.crashing.org, shangw
In-Reply-To: <1330076298-7006-1-git-send-email-shangw@linux.vnet.ibm.com>
With the original EEH implementation, the access to config space of
the corresponding PCI device is done by RTAS sensitive function. That
depends on pci_dn heavily. That would limit EEH extension to other
platforms like powernv because other platforms might have different
ways to access PCI config space.
The patch splits those functions used to access PCI config space
and implement them in platform related EEH component. It would be
helpful to support EEH on multiple platforms simutaneously in future.
Signed-off-by: Gavin Shan <shangw@linux.vnet.ibm.com>
---
arch/powerpc/include/asm/eeh.h | 2 +
arch/powerpc/platforms/pseries/eeh.c | 32 ++++++++++----------
arch/powerpc/platforms/pseries/eeh_pseries.c | 40 +++++++++++++++++++++++++-
3 files changed, 57 insertions(+), 17 deletions(-)
diff --git a/arch/powerpc/include/asm/eeh.h b/arch/powerpc/include/asm/eeh.h
index 226c9a5..121fa54 100644
--- a/arch/powerpc/include/asm/eeh.h
+++ b/arch/powerpc/include/asm/eeh.h
@@ -96,6 +96,8 @@ struct eeh_ops {
int (*wait_state)(struct device_node *dn, int max_wait);
int (*get_log)(struct device_node *dn, int severity, char *drv_log, unsigned long len);
int (*configure_bridge)(struct device_node *dn);
+ int (*read_config)(struct device_node *dn, int where, int size, u32 *val);
+ int (*write_config)(struct device_node *dn, int where, int size, u32 val);
};
/*
diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c
index a8a8c27..899df26 100644
--- a/arch/powerpc/platforms/pseries/eeh.c
+++ b/arch/powerpc/platforms/pseries/eeh.c
@@ -127,11 +127,11 @@ static size_t eeh_gather_pci_data(struct eeh_dev *edev, char * buf, size_t len)
n += scnprintf(buf+n, len-n, "%s\n", dn->full_name);
printk(KERN_WARNING "EEH: of node=%s\n", dn->full_name);
- rtas_read_config(PCI_DN(dn), PCI_VENDOR_ID, 4, &cfg);
+ eeh_ops->read_config(dn, PCI_VENDOR_ID, 4, &cfg);
n += scnprintf(buf+n, len-n, "dev/vend:%08x\n", cfg);
printk(KERN_WARNING "EEH: PCI device/vendor: %08x\n", cfg);
- rtas_read_config(PCI_DN(dn), PCI_COMMAND, 4, &cfg);
+ eeh_ops->read_config(dn, PCI_COMMAND, 4, &cfg);
n += scnprintf(buf+n, len-n, "cmd/stat:%x\n", cfg);
printk(KERN_WARNING "EEH: PCI cmd/status register: %08x\n", cfg);
@@ -142,11 +142,11 @@ static size_t eeh_gather_pci_data(struct eeh_dev *edev, char * buf, size_t len)
/* Gather bridge-specific registers */
if (dev->class >> 16 == PCI_BASE_CLASS_BRIDGE) {
- rtas_read_config(PCI_DN(dn), PCI_SEC_STATUS, 2, &cfg);
+ eeh_ops->read_config(dn, PCI_SEC_STATUS, 2, &cfg);
n += scnprintf(buf+n, len-n, "sec stat:%x\n", cfg);
printk(KERN_WARNING "EEH: Bridge secondary status: %04x\n", cfg);
- rtas_read_config(PCI_DN(dn), PCI_BRIDGE_CONTROL, 2, &cfg);
+ eeh_ops->read_config(dn, PCI_BRIDGE_CONTROL, 2, &cfg);
n += scnprintf(buf+n, len-n, "brdg ctl:%x\n", cfg);
printk(KERN_WARNING "EEH: Bridge control: %04x\n", cfg);
}
@@ -154,11 +154,11 @@ static size_t eeh_gather_pci_data(struct eeh_dev *edev, char * buf, size_t len)
/* Dump out the PCI-X command and status regs */
cap = pci_find_capability(dev, PCI_CAP_ID_PCIX);
if (cap) {
- rtas_read_config(PCI_DN(dn), cap, 4, &cfg);
+ eeh_ops->read_config(dn, cap, 4, &cfg);
n += scnprintf(buf+n, len-n, "pcix-cmd:%x\n", cfg);
printk(KERN_WARNING "EEH: PCI-X cmd: %08x\n", cfg);
- rtas_read_config(PCI_DN(dn), cap+4, 4, &cfg);
+ eeh_ops->read_config(dn, cap+4, 4, &cfg);
n += scnprintf(buf+n, len-n, "pcix-stat:%x\n", cfg);
printk(KERN_WARNING "EEH: PCI-X status: %08x\n", cfg);
}
@@ -171,7 +171,7 @@ static size_t eeh_gather_pci_data(struct eeh_dev *edev, char * buf, size_t len)
"EEH: PCI-E capabilities and status follow:\n");
for (i=0; i<=8; i++) {
- rtas_read_config(PCI_DN(dn), cap+4*i, 4, &cfg);
+ eeh_ops->read_config(dn, cap+4*i, 4, &cfg);
n += scnprintf(buf+n, len-n, "%02x:%x\n", 4*i, cfg);
printk(KERN_WARNING "EEH: PCI-E %02x: %08x\n", i, cfg);
}
@@ -183,7 +183,7 @@ static size_t eeh_gather_pci_data(struct eeh_dev *edev, char * buf, size_t len)
"EEH: PCI-E AER capability register set follows:\n");
for (i=0; i<14; i++) {
- rtas_read_config(PCI_DN(dn), cap+4*i, 4, &cfg);
+ eeh_ops->read_config(dn, cap+4*i, 4, &cfg);
n += scnprintf(buf+n, len-n, "%02x:%x\n", 4*i, cfg);
printk(KERN_WARNING "EEH: PCI-E AER %02x: %08x\n", i, cfg);
}
@@ -732,28 +732,28 @@ static inline void eeh_restore_one_device_bars(struct eeh_dev *edev)
return;
for (i=4; i<10; i++) {
- rtas_write_config(PCI_DN(dn), i*4, 4, edev->config_space[i]);
+ eeh_ops->write_config(dn, i*4, 4, edev->config_space[i]);
}
/* 12 == Expansion ROM Address */
- rtas_write_config(PCI_DN(dn), 12*4, 4, edev->config_space[12]);
+ eeh_ops->write_config(dn, 12*4, 4, edev->config_space[12]);
#define BYTE_SWAP(OFF) (8*((OFF)/4)+3-(OFF))
#define SAVED_BYTE(OFF) (((u8 *)(edev->config_space))[BYTE_SWAP(OFF)])
- rtas_write_config(PCI_DN(dn), PCI_CACHE_LINE_SIZE, 1,
+ eeh_ops->write_config(dn, PCI_CACHE_LINE_SIZE, 1,
SAVED_BYTE(PCI_CACHE_LINE_SIZE));
- rtas_write_config(PCI_DN(dn), PCI_LATENCY_TIMER, 1,
+ eeh_ops->write_config(dn, PCI_LATENCY_TIMER, 1,
SAVED_BYTE(PCI_LATENCY_TIMER));
/* max latency, min grant, interrupt pin and line */
- rtas_write_config(PCI_DN(dn), 15*4, 4, edev->config_space[15]);
+ eeh_ops->write_config(dn, 15*4, 4, edev->config_space[15]);
/* Restore PERR & SERR bits, some devices require it,
* don't touch the other command bits
*/
- rtas_read_config(PCI_DN(dn), PCI_COMMAND, 4, &cmd);
+ eeh_ops->read_config(dn, PCI_COMMAND, 4, &cmd);
if (edev->config_space[1] & PCI_COMMAND_PARITY)
cmd |= PCI_COMMAND_PARITY;
else
@@ -762,7 +762,7 @@ static inline void eeh_restore_one_device_bars(struct eeh_dev *edev)
cmd |= PCI_COMMAND_SERR;
else
cmd &= ~PCI_COMMAND_SERR;
- rtas_write_config(PCI_DN(dn), PCI_COMMAND, 4, cmd);
+ eeh_ops->write_config(dn, PCI_COMMAND, 4, cmd);
}
/**
@@ -804,7 +804,7 @@ static void eeh_save_bars(struct eeh_dev *edev)
dn = EEH_DEV_TO_OF_NODE(edev);
for (i = 0; i < 16; i++)
- rtas_read_config(PCI_DN(dn), i * 4, 4, &edev->config_space[i]);
+ eeh_ops->read_config(dn, i * 4, 4, &edev->config_space[i]);
}
/**
diff --git a/arch/powerpc/platforms/pseries/eeh_pseries.c b/arch/powerpc/platforms/pseries/eeh_pseries.c
index a3345c2..841738e 100644
--- a/arch/powerpc/platforms/pseries/eeh_pseries.c
+++ b/arch/powerpc/platforms/pseries/eeh_pseries.c
@@ -503,6 +503,42 @@ static int pseries_eeh_configure_bridge(struct device_node *dn)
return ret;
}
+/**
+ * pseries_eeh_read_config - Read PCI config space
+ * @dn: device node
+ * @where: PCI address
+ * @size: size to read
+ * @val: return value
+ *
+ * Read config space from the speicifed device
+ */
+static int pseries_eeh_read_config(struct device_node *dn, int where, int size, u32 *val)
+{
+ struct pci_dn *pdn;
+
+ pdn = PCI_DN(dn);
+
+ return rtas_read_config(pdn, where, size, val);
+}
+
+/**
+ * pseries_eeh_write_config - Write PCI config space
+ * @dn: device node
+ * @where: PCI address
+ * @size: size to write
+ * @val: value to be written
+ *
+ * Write config space to the specified device
+ */
+static int pseries_eeh_write_config(struct device_node *dn, int where, int size, u32 val)
+{
+ struct pci_dn *pdn;
+
+ pdn = PCI_DN(dn);
+
+ return rtas_write_config(pdn, where, size, val);
+}
+
static struct eeh_ops pseries_eeh_ops = {
.name = "pseries",
.init = pseries_eeh_init,
@@ -512,7 +548,9 @@ static struct eeh_ops pseries_eeh_ops = {
.reset = pseries_eeh_reset,
.wait_state = pseries_eeh_wait_state,
.get_log = pseries_eeh_get_log,
- .configure_bridge = pseries_eeh_configure_bridge
+ .configure_bridge = pseries_eeh_configure_bridge,
+ .read_config = pseries_eeh_read_config,
+ .write_config = pseries_eeh_write_config
};
/**
--
1.7.5.4
^ permalink raw reply related
* [PATCH 10/21] pSeries platform EEH error log retrieval
From: Gavin Shan @ 2012-02-24 9:38 UTC (permalink / raw)
To: linuxppc-dev; +Cc: kernel.crashing.org, shangw
In-Reply-To: <1330076298-7006-1-git-send-email-shangw@linux.vnet.ibm.com>
On RTAS compliant pSeries platform, one dedicated RTAS call has
been introduced to retrieve EEH temporary or permanent error log.
The patch implements the function of retriving EEH error log through
RTAS call. Besides, it has been abstracted by struct eeh_ops::get_log
so that EEH core components could support multiple platforms in future.
Signed-off-by: Gavin Shan <shangw@linux.vnet.ibm.com>
---
arch/powerpc/include/asm/eeh.h | 2 +
arch/powerpc/include/asm/ppc-pci.h | 2 -
arch/powerpc/platforms/pseries/eeh.c | 63 +-------------------------
arch/powerpc/platforms/pseries/eeh_driver.c | 4 +-
arch/powerpc/platforms/pseries/eeh_pseries.c | 47 +++++++++++++++++++-
5 files changed, 51 insertions(+), 67 deletions(-)
diff --git a/arch/powerpc/include/asm/eeh.h b/arch/powerpc/include/asm/eeh.h
index 894ea6c..ad8f318 100644
--- a/arch/powerpc/include/asm/eeh.h
+++ b/arch/powerpc/include/asm/eeh.h
@@ -52,6 +52,8 @@ struct device_node;
#define EEH_RESET_DEACTIVATE 0 /* Deactivate the PE reset */
#define EEH_RESET_HOT 1 /* Hot reset */
#define EEH_RESET_FUNDAMENTAL 3 /* Fundamental reset */
+#define EEH_LOG_TEMP 1 /* EEH temporary error log */
+#define EEH_LOG_PERM 2 /* EEH permanent error log */
struct eeh_ops {
char *name;
diff --git a/arch/powerpc/include/asm/ppc-pci.h b/arch/powerpc/include/asm/ppc-pci.h
index 1cfb2b0..bd1a84f 100644
--- a/arch/powerpc/include/asm/ppc-pci.h
+++ b/arch/powerpc/include/asm/ppc-pci.h
@@ -53,8 +53,6 @@ void pci_addr_cache_insert_device(struct pci_dev *dev);
void pci_addr_cache_remove_device(struct pci_dev *dev);
void pci_addr_cache_build(void);
struct pci_dev *pci_get_device_by_addr(unsigned long addr);
-#define EEH_LOG_TEMP_FAILURE 1
-#define EEH_LOG_PERM_FAILURE 2
void eeh_slot_error_detail (struct pci_dn *pdn, int severity);
int eeh_pci_enable(struct pci_dn *pdn, int function);
int eeh_reset_pe(struct pci_dn *);
diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c
index 4f329f5..39fcecb 100644
--- a/arch/powerpc/platforms/pseries/eeh.c
+++ b/arch/powerpc/platforms/pseries/eeh.c
@@ -87,7 +87,6 @@
#define PCI_BUS_RESET_WAIT_MSEC (60*1000)
/* RTAS tokens */
-static int ibm_slot_error_detail;
static int ibm_configure_bridge;
static int ibm_configure_pe;
@@ -100,14 +99,6 @@ EXPORT_SYMBOL(eeh_subsystem_enabled);
/* Lock to avoid races due to multiple reports of an error */
static DEFINE_RAW_SPINLOCK(confirm_error_lock);
-/* Buffer for reporting slot-error-detail rtas calls. Its here
- * in BSS, and not dynamically alloced, so that it ends up in
- * RMO where RTAS can access it.
- */
-static unsigned char slot_errbuf[RTAS_ERROR_LOG_MAX];
-static DEFINE_SPINLOCK(slot_errbuf_lock);
-static int eeh_error_buf_size;
-
/* Buffer for reporting pci register dumps. Its here in BSS, and
* not dynamically alloced, so that it ends up in RMO where RTAS
* can access it.
@@ -127,46 +118,6 @@ static unsigned long slot_resets;
#define IS_BRIDGE(class_code) (((class_code)<<16) == PCI_BASE_CLASS_BRIDGE)
/**
- * eeh_rtas_slot_error_detail - Retrieve error log through RTAS call
- * @pdn: device node
- * @severity: temporary or permanent error log
- * @driver_log: driver log to be combined with the retrieved error log
- * @loglen: length of driver log
- *
- * This routine should be called to retrieve error log through the dedicated
- * RTAS call.
- */
-static void eeh_rtas_slot_error_detail(struct pci_dn *pdn, int severity,
- char *driver_log, size_t loglen)
-{
- int config_addr;
- unsigned long flags;
- int rc;
-
- /* Log the error with the rtas logger */
- spin_lock_irqsave(&slot_errbuf_lock, flags);
- memset(slot_errbuf, 0, eeh_error_buf_size);
-
- /* Use PE configuration address, if present */
- config_addr = pdn->eeh_config_addr;
- if (pdn->eeh_pe_config_addr)
- config_addr = pdn->eeh_pe_config_addr;
-
- rc = rtas_call(ibm_slot_error_detail,
- 8, 1, NULL, config_addr,
- BUID_HI(pdn->phb->buid),
- BUID_LO(pdn->phb->buid),
- virt_to_phys(driver_log), loglen,
- virt_to_phys(slot_errbuf),
- eeh_error_buf_size,
- severity);
-
- if (rc == 0)
- log_error(slot_errbuf, ERR_TYPE_RTAS_LOG, 0);
- spin_unlock_irqrestore(&slot_errbuf_lock, flags);
-}
-
-/**
* eeh_gather_pci_data - Copy assorted PCI config space registers to buff
* @pdn: device to report data for
* @buf: point to buffer in which to log
@@ -282,7 +233,7 @@ void eeh_slot_error_detail(struct pci_dn *pdn, int severity)
eeh_restore_bars(pdn);
loglen = eeh_gather_pci_data(pdn, pci_regs_buf, EEH_PCI_REGS_LOG_LEN);
- eeh_rtas_slot_error_detail(pdn, severity, pci_regs_buf, loglen);
+ eeh_ops->get_log(pdn->node, severity, pci_regs_buf, loglen);
}
/**
@@ -1071,26 +1022,14 @@ void __init eeh_init(void)
}
raw_spin_lock_init(&confirm_error_lock);
- spin_lock_init(&slot_errbuf_lock);
np = of_find_node_by_path("/rtas");
if (np == NULL)
return;
- ibm_slot_error_detail = rtas_token("ibm,slot-error-detail");
ibm_configure_bridge = rtas_token("ibm,configure-bridge");
ibm_configure_pe = rtas_token("ibm,configure-pe");
- eeh_error_buf_size = rtas_token("rtas-error-log-max");
- if (eeh_error_buf_size == RTAS_UNKNOWN_SERVICE) {
- eeh_error_buf_size = 1024;
- }
- if (eeh_error_buf_size > RTAS_ERROR_LOG_MAX) {
- printk(KERN_WARNING "EEH: rtas-error-log-max is bigger than allocated "
- "buffer ! (%d vs %d)", eeh_error_buf_size, RTAS_ERROR_LOG_MAX);
- eeh_error_buf_size = RTAS_ERROR_LOG_MAX;
- }
-
/* Enable EEH for all adapters. Note that eeh requires buid's */
for (phb = of_find_node_by_name(NULL, "pci"); phb;
phb = of_find_node_by_name(phb, "pci")) {
diff --git a/arch/powerpc/platforms/pseries/eeh_driver.c b/arch/powerpc/platforms/pseries/eeh_driver.c
index 584defe..6840357 100644
--- a/arch/powerpc/platforms/pseries/eeh_driver.c
+++ b/arch/powerpc/platforms/pseries/eeh_driver.c
@@ -406,7 +406,7 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event)
* don't post the error log until after all dev drivers
* have been informed.
*/
- eeh_slot_error_detail(frozen_pdn, EEH_LOG_TEMP_FAILURE);
+ eeh_slot_error_detail(frozen_pdn, EEH_LOG_TEMP);
/* If all device drivers were EEH-unaware, then shut
* down all of the device drivers, and hope they
@@ -497,7 +497,7 @@ hard_fail:
location, drv_str, pci_str);
perm_error:
- eeh_slot_error_detail(frozen_pdn, EEH_LOG_PERM_FAILURE);
+ eeh_slot_error_detail(frozen_pdn, EEH_LOG_PERM);
/* Notify all devices that they're about to go down. */
pci_walk_bus(frozen_bus, eeh_report_failure, NULL);
diff --git a/arch/powerpc/platforms/pseries/eeh_pseries.c b/arch/powerpc/platforms/pseries/eeh_pseries.c
index 6643e06..7c8434f 100644
--- a/arch/powerpc/platforms/pseries/eeh_pseries.c
+++ b/arch/powerpc/platforms/pseries/eeh_pseries.c
@@ -56,6 +56,15 @@ static int ibm_get_config_addr_info2;
static int ibm_configure_bridge;
static int ibm_configure_pe;
+/*
+ * Buffer for reporting slot-error-detail rtas calls. Its here
+ * in BSS, and not dynamically alloced, so that it ends up in
+ * RMO where RTAS can access it.
+ */
+static unsigned char slot_errbuf[RTAS_ERROR_LOG_MAX];
+static DEFINE_SPINLOCK(slot_errbuf_lock);
+static int eeh_error_buf_size;
+
/**
* pseries_eeh_init - EEH platform dependent initialization
*
@@ -107,6 +116,19 @@ static int pseries_eeh_init(void)
return -EINVAL;
}
+ /* Initialize error log lock and size */
+ spin_lock_init(&slot_errbuf_lock);
+ eeh_error_buf_size = rtas_token("rtas-error-log-max");
+ if (eeh_error_buf_size == RTAS_UNKNOWN_SERVICE) {
+ pr_warning("%s: unknown EEH error log size\n",
+ __func__);
+ eeh_error_buf_size = 1024;
+ } else if (eeh_error_buf_size > RTAS_ERROR_LOG_MAX) {
+ pr_warning("%s: EEH error log size %d exceeds the maximal %d\n",
+ __func__, eeh_error_buf_size, RTAS_ERROR_LOG_MAX);
+ eeh_error_buf_size = RTAS_ERROR_LOG_MAX;
+ }
+
return 0;
}
@@ -415,7 +437,30 @@ static int pseries_eeh_wait_state(struct device_node *dn, int max_wait)
*/
static int pseries_eeh_get_log(struct device_node *dn, int severity, char *drv_log, unsigned long len)
{
- return 0;
+ struct pci_dn *pdn;
+ int config_addr;
+ unsigned long flags;
+ int ret;
+
+ pdn = PCI_DN(dn);
+ spin_lock_irqsave(&slot_errbuf_lock, flags);
+ memset(slot_errbuf, 0, eeh_error_buf_size);
+
+ /* Figure out the PE address */
+ config_addr = pdn->eeh_config_addr;
+ if (pdn->eeh_pe_config_addr)
+ config_addr = pdn->eeh_pe_config_addr;
+
+ ret = rtas_call(ibm_slot_error_detail, 8, 1, NULL, config_addr,
+ BUID_HI(pdn->phb->buid), BUID_LO(pdn->phb->buid),
+ virt_to_phys(drv_log), len,
+ virt_to_phys(slot_errbuf), eeh_error_buf_size,
+ severity);
+ if (!ret)
+ log_error(slot_errbuf, ERR_TYPE_RTAS_LOG, 0);
+ spin_unlock_irqrestore(&slot_errbuf_lock, flags);
+
+ return ret;
}
/**
--
1.7.5.4
^ permalink raw reply related
* [PATCH 17/21] Replace pci_dn with eeh_dev for EEH core
From: Gavin Shan @ 2012-02-24 9:38 UTC (permalink / raw)
To: linuxppc-dev; +Cc: kernel.crashing.org, shangw
In-Reply-To: <1330076298-7006-1-git-send-email-shangw@linux.vnet.ibm.com>
The original EEH implementation is heavily depending on struct pci_dn.
We have to put EEH related information to pci_dn. Actually, we could
split struct pci_dn so that the EEH sensitive information to form an
individual struct, then EEH looks more independent.
The patch replaces pci_dn with eeh_dev for EEH core.
Signed-off-by: Gavin Shan <shangw@linux.vnet.ibm.com>
---
arch/powerpc/include/asm/ppc-pci.h | 8 +-
arch/powerpc/platforms/pseries/eeh.c | 269 ++++++++++++++++++----------------
2 files changed, 144 insertions(+), 133 deletions(-)
diff --git a/arch/powerpc/include/asm/ppc-pci.h b/arch/powerpc/include/asm/ppc-pci.h
index c02d5a7..8c003eb 100644
--- a/arch/powerpc/include/asm/ppc-pci.h
+++ b/arch/powerpc/include/asm/ppc-pci.h
@@ -53,10 +53,10 @@ void pci_addr_cache_build(void);
void pci_addr_cache_insert_device(struct pci_dev *dev);
void pci_addr_cache_remove_device(struct pci_dev *dev);
struct pci_dev *pci_addr_cache_get_device(unsigned long addr);
-void eeh_slot_error_detail (struct pci_dn *pdn, int severity);
-int eeh_pci_enable(struct pci_dn *pdn, int function);
-int eeh_reset_pe(struct pci_dn *);
-void eeh_restore_bars(struct pci_dn *);
+void eeh_slot_error_detail(struct eeh_dev *pdn, int severity);
+int eeh_pci_enable(struct eeh_dev *edev, int function);
+int eeh_reset_pe(struct eeh_dev *);
+void eeh_restore_bars(struct eeh_dev *);
int rtas_write_config(struct pci_dn *, int where, int size, u32 val);
int rtas_read_config(struct pci_dn *, int where, int size, u32 *val);
void eeh_mark_slot(struct device_node *dn, int mode_flag);
diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c
index 646b520..84a8a0c 100644
--- a/arch/powerpc/platforms/pseries/eeh.c
+++ b/arch/powerpc/platforms/pseries/eeh.c
@@ -115,28 +115,29 @@ static unsigned long slot_resets;
/**
* eeh_gather_pci_data - Copy assorted PCI config space registers to buff
- * @pdn: device to report data for
+ * @edev: device to report data for
* @buf: point to buffer in which to log
* @len: amount of room in buffer
*
* This routine captures assorted PCI configuration space data,
* and puts them into a buffer for RTAS error logging.
*/
-static size_t eeh_gather_pci_data(struct pci_dn *pdn, char * buf, size_t len)
+static size_t eeh_gather_pci_data(struct eeh_dev *edev, char * buf, size_t len)
{
- struct pci_dev *dev = pdn->pcidev;
+ struct device_node *dn = EEH_DEV_TO_OF_NODE(edev);
+ struct pci_dev *dev = EEH_DEV_TO_PCI_DEV(edev);
u32 cfg;
int cap, i;
int n = 0;
- n += scnprintf(buf+n, len-n, "%s\n", pdn->node->full_name);
- printk(KERN_WARNING "EEH: of node=%s\n", pdn->node->full_name);
+ n += scnprintf(buf+n, len-n, "%s\n", dn->full_name);
+ printk(KERN_WARNING "EEH: of node=%s\n", dn->full_name);
- rtas_read_config(pdn, PCI_VENDOR_ID, 4, &cfg);
+ rtas_read_config(PCI_DN(dn), PCI_VENDOR_ID, 4, &cfg);
n += scnprintf(buf+n, len-n, "dev/vend:%08x\n", cfg);
printk(KERN_WARNING "EEH: PCI device/vendor: %08x\n", cfg);
- rtas_read_config(pdn, PCI_COMMAND, 4, &cfg);
+ rtas_read_config(PCI_DN(dn), PCI_COMMAND, 4, &cfg);
n += scnprintf(buf+n, len-n, "cmd/stat:%x\n", cfg);
printk(KERN_WARNING "EEH: PCI cmd/status register: %08x\n", cfg);
@@ -147,11 +148,11 @@ static size_t eeh_gather_pci_data(struct pci_dn *pdn, char * buf, size_t len)
/* Gather bridge-specific registers */
if (dev->class >> 16 == PCI_BASE_CLASS_BRIDGE) {
- rtas_read_config(pdn, PCI_SEC_STATUS, 2, &cfg);
+ rtas_read_config(PCI_DN(dn), PCI_SEC_STATUS, 2, &cfg);
n += scnprintf(buf+n, len-n, "sec stat:%x\n", cfg);
printk(KERN_WARNING "EEH: Bridge secondary status: %04x\n", cfg);
- rtas_read_config(pdn, PCI_BRIDGE_CONTROL, 2, &cfg);
+ rtas_read_config(PCI_DN(dn), PCI_BRIDGE_CONTROL, 2, &cfg);
n += scnprintf(buf+n, len-n, "brdg ctl:%x\n", cfg);
printk(KERN_WARNING "EEH: Bridge control: %04x\n", cfg);
}
@@ -159,11 +160,11 @@ static size_t eeh_gather_pci_data(struct pci_dn *pdn, char * buf, size_t len)
/* Dump out the PCI-X command and status regs */
cap = pci_find_capability(dev, PCI_CAP_ID_PCIX);
if (cap) {
- rtas_read_config(pdn, cap, 4, &cfg);
+ rtas_read_config(PCI_DN(dn), cap, 4, &cfg);
n += scnprintf(buf+n, len-n, "pcix-cmd:%x\n", cfg);
printk(KERN_WARNING "EEH: PCI-X cmd: %08x\n", cfg);
- rtas_read_config(pdn, cap+4, 4, &cfg);
+ rtas_read_config(PCI_DN(dn), cap+4, 4, &cfg);
n += scnprintf(buf+n, len-n, "pcix-stat:%x\n", cfg);
printk(KERN_WARNING "EEH: PCI-X status: %08x\n", cfg);
}
@@ -176,7 +177,7 @@ static size_t eeh_gather_pci_data(struct pci_dn *pdn, char * buf, size_t len)
"EEH: PCI-E capabilities and status follow:\n");
for (i=0; i<=8; i++) {
- rtas_read_config(pdn, cap+4*i, 4, &cfg);
+ rtas_read_config(PCI_DN(dn), cap+4*i, 4, &cfg);
n += scnprintf(buf+n, len-n, "%02x:%x\n", 4*i, cfg);
printk(KERN_WARNING "EEH: PCI-E %02x: %08x\n", i, cfg);
}
@@ -188,7 +189,7 @@ static size_t eeh_gather_pci_data(struct pci_dn *pdn, char * buf, size_t len)
"EEH: PCI-E AER capability register set follows:\n");
for (i=0; i<14; i++) {
- rtas_read_config(pdn, cap+4*i, 4, &cfg);
+ rtas_read_config(PCI_DN(dn), cap+4*i, 4, &cfg);
n += scnprintf(buf+n, len-n, "%02x:%x\n", 4*i, cfg);
printk(KERN_WARNING "EEH: PCI-E AER %02x: %08x\n", i, cfg);
}
@@ -197,12 +198,11 @@ static size_t eeh_gather_pci_data(struct pci_dn *pdn, char * buf, size_t len)
/* Gather status on devices under the bridge */
if (dev->class >> 16 == PCI_BASE_CLASS_BRIDGE) {
- struct device_node *dn;
+ struct device_node *child;
- for_each_child_of_node(pdn->node, dn) {
- pdn = PCI_DN(dn);
- if (pdn)
- n += eeh_gather_pci_data(pdn, buf+n, len-n);
+ for_each_child_of_node(dn, child) {
+ if (OF_NODE_TO_EEH_DEV(child))
+ n += eeh_gather_pci_data(OF_NODE_TO_EEH_DEV(child), buf+n, len-n);
}
}
@@ -211,7 +211,7 @@ static size_t eeh_gather_pci_data(struct pci_dn *pdn, char * buf, size_t len)
/**
* eeh_slot_error_detail - Generate combined log including driver log and error log
- * @pdn: device node
+ * @edev: device to report error log for
* @severity: temporary or permanent error log
*
* This routine should be called to generate the combined log, which
@@ -219,17 +219,17 @@ static size_t eeh_gather_pci_data(struct pci_dn *pdn, char * buf, size_t len)
* out from the config space of the corresponding PCI device, while
* the error log is fetched through platform dependent function call.
*/
-void eeh_slot_error_detail(struct pci_dn *pdn, int severity)
+void eeh_slot_error_detail(struct eeh_dev *edev, int severity)
{
size_t loglen = 0;
pci_regs_buf[0] = 0;
- eeh_pci_enable(pdn, EEH_OPT_THAW_MMIO);
- eeh_ops->configure_bridge(pdn->node);
- eeh_restore_bars(pdn);
- loglen = eeh_gather_pci_data(pdn, pci_regs_buf, EEH_PCI_REGS_LOG_LEN);
+ eeh_pci_enable(edev, EEH_OPT_THAW_MMIO);
+ eeh_ops->configure_bridge(EEH_DEV_TO_OF_NODE(edev));
+ eeh_restore_bars(edev);
+ loglen = eeh_gather_pci_data(edev, pci_regs_buf, EEH_PCI_REGS_LOG_LEN);
- eeh_ops->get_log(pdn->node, severity, pci_regs_buf, loglen);
+ eeh_ops->get_log(EEH_DEV_TO_OF_NODE(edev), severity, pci_regs_buf, loglen);
}
/**
@@ -260,8 +260,8 @@ static inline unsigned long eeh_token_to_phys(unsigned long token)
*/
struct device_node *eeh_find_device_pe(struct device_node *dn)
{
- while ((dn->parent) && PCI_DN(dn->parent) &&
- (PCI_DN(dn->parent)->eeh_mode & EEH_MODE_SUPPORTED)) {
+ while (dn->parent && OF_NODE_TO_EEH_DEV(dn->parent) &&
+ (OF_NODE_TO_EEH_DEV(dn->parent)->mode & EEH_MODE_SUPPORTED)) {
dn = dn->parent;
}
return dn;
@@ -284,11 +284,11 @@ static void __eeh_mark_slot(struct device_node *parent, int mode_flag)
struct device_node *dn;
for_each_child_of_node(parent, dn) {
- if (PCI_DN(dn)) {
+ if (OF_NODE_TO_EEH_DEV(dn)) {
/* Mark the pci device driver too */
- struct pci_dev *dev = PCI_DN(dn)->pcidev;
+ struct pci_dev *dev = OF_NODE_TO_EEH_DEV(dn)->pdev;
- PCI_DN(dn)->eeh_mode |= mode_flag;
+ OF_NODE_TO_EEH_DEV(dn)->mode |= mode_flag;
if (dev && dev->driver)
dev->error_state = pci_channel_io_frozen;
@@ -312,13 +312,13 @@ void eeh_mark_slot(struct device_node *dn, int mode_flag)
dn = eeh_find_device_pe(dn);
/* Back up one, since config addrs might be shared */
- if (!pcibios_find_pci_bus(dn) && PCI_DN(dn->parent))
+ if (!pcibios_find_pci_bus(dn) && OF_NODE_TO_EEH_DEV(dn->parent))
dn = dn->parent;
- PCI_DN(dn)->eeh_mode |= mode_flag;
+ OF_NODE_TO_EEH_DEV(dn)->mode |= mode_flag;
/* Mark the pci device too */
- dev = PCI_DN(dn)->pcidev;
+ dev = OF_NODE_TO_EEH_DEV(dn)->pdev;
if (dev)
dev->error_state = pci_channel_io_frozen;
@@ -337,9 +337,9 @@ static void __eeh_clear_slot(struct device_node *parent, int mode_flag)
struct device_node *dn;
for_each_child_of_node(parent, dn) {
- if (PCI_DN(dn)) {
- PCI_DN(dn)->eeh_mode &= ~mode_flag;
- PCI_DN(dn)->eeh_check_count = 0;
+ if (OF_NODE_TO_EEH_DEV(dn)) {
+ OF_NODE_TO_EEH_DEV(dn)->mode &= ~mode_flag;
+ OF_NODE_TO_EEH_DEV(dn)->check_count = 0;
__eeh_clear_slot(dn, mode_flag);
}
}
@@ -360,11 +360,11 @@ void eeh_clear_slot(struct device_node *dn, int mode_flag)
dn = eeh_find_device_pe(dn);
/* Back up one, since config addrs might be shared */
- if (!pcibios_find_pci_bus(dn) && PCI_DN(dn->parent))
+ if (!pcibios_find_pci_bus(dn) && OF_NODE_TO_EEH_DEV(dn->parent))
dn = dn->parent;
- PCI_DN(dn)->eeh_mode &= ~mode_flag;
- PCI_DN(dn)->eeh_check_count = 0;
+ OF_NODE_TO_EEH_DEV(dn)->mode &= ~mode_flag;
+ OF_NODE_TO_EEH_DEV(dn)->check_count = 0;
__eeh_clear_slot(dn, mode_flag);
raw_spin_unlock_irqrestore(&confirm_error_lock, flags);
}
@@ -388,7 +388,7 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev)
{
int ret;
unsigned long flags;
- struct pci_dn *pdn;
+ struct eeh_dev *edev;
int rc = 0;
const char *location;
@@ -402,18 +402,18 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev)
return 0;
}
dn = eeh_find_device_pe(dn);
- pdn = PCI_DN(dn);
+ edev = OF_NODE_TO_EEH_DEV(dn);
/* Access to IO BARs might get this far and still not want checking. */
- if (!(pdn->eeh_mode & EEH_MODE_SUPPORTED) ||
- pdn->eeh_mode & EEH_MODE_NOCHECK) {
+ if (!(edev->mode & EEH_MODE_SUPPORTED) ||
+ edev->mode & EEH_MODE_NOCHECK) {
ignored_check++;
pr_debug("EEH: Ignored check (%x) for %s %s\n",
- pdn->eeh_mode, eeh_pci_name(dev), dn->full_name);
+ edev->mode, eeh_pci_name(dev), dn->full_name);
return 0;
}
- if (!pdn->eeh_config_addr && !pdn->eeh_pe_config_addr) {
+ if (!edev->config_addr && !edev->pe_config_addr) {
no_cfg_addr++;
return 0;
}
@@ -426,13 +426,13 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev)
*/
raw_spin_lock_irqsave(&confirm_error_lock, flags);
rc = 1;
- if (pdn->eeh_mode & EEH_MODE_ISOLATED) {
- pdn->eeh_check_count ++;
- if (pdn->eeh_check_count % EEH_MAX_FAILS == 0) {
+ if (edev->mode & EEH_MODE_ISOLATED) {
+ edev->check_count++;
+ if (edev->check_count % EEH_MAX_FAILS == 0) {
location = of_get_property(dn, "ibm,loc-code", NULL);
printk(KERN_ERR "EEH: %d reads ignored for recovering device at "
"location=%s driver=%s pci addr=%s\n",
- pdn->eeh_check_count, location,
+ edev->check_count, location,
eeh_driver_name(dev), eeh_pci_name(dev));
printk(KERN_ERR "EEH: Might be infinite loop in %s driver\n",
eeh_driver_name(dev));
@@ -448,7 +448,7 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev)
* function zero of a multi-function device.
* In any case they must share a common PHB.
*/
- ret = eeh_ops->get_state(pdn->node, NULL);
+ ret = eeh_ops->get_state(dn, NULL);
/* Note that config-io to empty slots may fail;
* they are empty when they don't have children.
@@ -461,7 +461,7 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev)
(ret & (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE)) ==
(EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE)) {
false_positives++;
- pdn->eeh_false_positives ++;
+ edev->false_positives ++;
rc = 0;
goto dn_unlock;
}
@@ -475,7 +475,7 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev)
eeh_mark_slot(dn, EEH_MODE_ISOLATED);
raw_spin_unlock_irqrestore(&confirm_error_lock, flags);
- eeh_send_failure_event(dn, dev);
+ eeh_send_failure_event(edev->dn, edev->pdev);
/* Most EEH events are due to device driver bugs. Having
* a stack trace will help the device-driver authors figure
@@ -529,22 +529,23 @@ EXPORT_SYMBOL(eeh_check_failure);
/**
* eeh_pci_enable - Enable MMIO or DMA transfers for this slot
- * @pdn pci device node
+ * @edev: pci device node
*
* This routine should be called to reenable frozen MMIO or DMA
* so that it would work correctly again. It's useful while doing
* recovery or log collection on the indicated device.
*/
-int eeh_pci_enable(struct pci_dn *pdn, int function)
+int eeh_pci_enable(struct eeh_dev *edev, int function)
{
int rc;
+ struct device_node *dn = EEH_DEV_TO_OF_NODE(edev);
- rc = eeh_ops->set_option(pdn->node, function);
+ rc = eeh_ops->set_option(dn, function);
if (rc)
printk(KERN_WARNING "EEH: Unexpected state change %d, err=%d dn=%s\n",
- function, rc, pdn->node->full_name);
+ function, rc, dn->full_name);
- rc = eeh_ops->wait_state(pdn->node, PCI_BUS_RESET_WAIT_MSEC);
+ rc = eeh_ops->wait_state(dn, PCI_BUS_RESET_WAIT_MSEC);
if (rc > 0 && (rc & EEH_STATE_MMIO_ENABLED) &&
(function == EEH_OPT_THAW_MMIO))
return 0;
@@ -595,8 +596,8 @@ void __eeh_set_pe_freset(struct device_node *parent, unsigned int *freset)
struct device_node *dn;
for_each_child_of_node(parent, dn) {
- if (PCI_DN(dn)) {
- struct pci_dev *dev = PCI_DN(dn)->pcidev;
+ if (OF_NODE_TO_EEH_DEV(dn)) {
+ struct pci_dev *dev = OF_NODE_TO_EEH_DEV(dn)->pdev;
if (dev && dev->driver)
*freset |= dev->needs_freset;
@@ -622,10 +623,10 @@ void eeh_set_pe_freset(struct device_node *dn, unsigned int *freset)
dn = eeh_find_device_pe(dn);
/* Back up one, since config addrs might be shared */
- if (!pcibios_find_pci_bus(dn) && PCI_DN(dn->parent))
+ if (!pcibios_find_pci_bus(dn) && OF_NODE_TO_EEH_DEV(dn->parent))
dn = dn->parent;
- dev = PCI_DN(dn)->pcidev;
+ dev = OF_NODE_TO_EEH_DEV(dn)->pdev;
if (dev)
*freset |= dev->needs_freset;
@@ -634,13 +635,14 @@ void eeh_set_pe_freset(struct device_node *dn, unsigned int *freset)
/**
* eeh_reset_pe_once - Assert the pci #RST line for 1/4 second
- * @pdn: pci device node to be reset.
+ * @edev: pci device node to be reset.
*
* Assert the PCI #RST line for 1/4 second.
*/
-static void eeh_reset_pe_once(struct pci_dn *pdn)
+static void eeh_reset_pe_once(struct eeh_dev *edev)
{
unsigned int freset = 0;
+ struct device_node *dn = EEH_DEV_TO_OF_NODE(edev);
/* Determine type of EEH reset required for
* Partitionable Endpoint, a hot-reset (1)
@@ -648,12 +650,12 @@ static void eeh_reset_pe_once(struct pci_dn *pdn)
* A fundamental reset required by any device under
* Partitionable Endpoint trumps hot-reset.
*/
- eeh_set_pe_freset(pdn->node, &freset);
+ eeh_set_pe_freset(dn, &freset);
if (freset)
- eeh_ops->reset(pdn->node, EEH_RESET_FUNDAMENTAL);
+ eeh_ops->reset(dn, EEH_RESET_FUNDAMENTAL);
else
- eeh_ops->reset(pdn->node, EEH_RESET_HOT);
+ eeh_ops->reset(dn, EEH_RESET_HOT);
/* The PCI bus requires that the reset be held high for at least
* a 100 milliseconds. We wait a bit longer 'just in case'.
@@ -665,9 +667,9 @@ static void eeh_reset_pe_once(struct pci_dn *pdn)
* pci slot reset line is dropped. Make sure we don't miss
* these, and clear the flag now.
*/
- eeh_clear_slot(pdn->node, EEH_MODE_ISOLATED);
+ eeh_clear_slot(dn, EEH_MODE_ISOLATED);
- eeh_ops->reset(pdn->node, EEH_RESET_DEACTIVATE);
+ eeh_ops->reset(dn, EEH_RESET_DEACTIVATE);
/* After a PCI slot has been reset, the PCI Express spec requires
* a 1.5 second idle time for the bus to stabilize, before starting
@@ -679,31 +681,32 @@ static void eeh_reset_pe_once(struct pci_dn *pdn)
/**
* eeh_reset_pe - Reset the indicated PE
- * @pdn: PCI device node
+ * @edev: PCI device associated EEH device
*
* This routine should be called to reset indicated device, including
* PE. A PE might include multiple PCI devices and sometimes PCI bridges
* might be involved as well.
*/
-int eeh_reset_pe(struct pci_dn *pdn)
+int eeh_reset_pe(struct eeh_dev *edev)
{
int i, rc;
+ struct device_node *dn = EEH_DEV_TO_OF_NODE(edev);
/* Take three shots at resetting the bus */
for (i=0; i<3; i++) {
- eeh_reset_pe_once(pdn);
+ eeh_reset_pe_once(edev);
- rc = eeh_ops->wait_state(pdn->node, PCI_BUS_RESET_WAIT_MSEC);
+ rc = eeh_ops->wait_state(dn, PCI_BUS_RESET_WAIT_MSEC);
if (rc == (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE))
return 0;
if (rc < 0) {
printk(KERN_ERR "EEH: unrecoverable slot failure %s\n",
- pdn->node->full_name);
+ dn->full_name);
return -1;
}
printk(KERN_ERR "EEH: bus reset %d failed on slot %s, rc=%d\n",
- i+1, pdn->node->full_name, rc);
+ i+1, dn->full_name, rc);
}
return -1;
@@ -719,90 +722,95 @@ int eeh_reset_pe(struct pci_dn *pdn)
/**
* eeh_restore_one_device_bars - Restore the Base Address Registers for one device
- * @pdn: pci device node
+ * @edev: PCI device associated EEH device
*
* Loads the PCI configuration space base address registers,
* the expansion ROM base address, the latency timer, and etc.
* from the saved values in the device node.
*/
-static inline void eeh_restore_one_device_bars(struct pci_dn *pdn)
+static inline void eeh_restore_one_device_bars(struct eeh_dev *edev)
{
int i;
u32 cmd;
+ struct device_node *dn = EEH_DEV_TO_OF_NODE(edev);
+
+ if (!edev->phb)
+ return;
- if (NULL==pdn->phb) return;
for (i=4; i<10; i++) {
- rtas_write_config(pdn, i*4, 4, pdn->config_space[i]);
+ rtas_write_config(PCI_DN(dn), i*4, 4, edev->config_space[i]);
}
/* 12 == Expansion ROM Address */
- rtas_write_config(pdn, 12*4, 4, pdn->config_space[12]);
+ rtas_write_config(PCI_DN(dn), 12*4, 4, edev->config_space[12]);
#define BYTE_SWAP(OFF) (8*((OFF)/4)+3-(OFF))
-#define SAVED_BYTE(OFF) (((u8 *)(pdn->config_space))[BYTE_SWAP(OFF)])
+#define SAVED_BYTE(OFF) (((u8 *)(edev->config_space))[BYTE_SWAP(OFF)])
- rtas_write_config(pdn, PCI_CACHE_LINE_SIZE, 1,
+ rtas_write_config(PCI_DN(dn), PCI_CACHE_LINE_SIZE, 1,
SAVED_BYTE(PCI_CACHE_LINE_SIZE));
- rtas_write_config(pdn, PCI_LATENCY_TIMER, 1,
+ rtas_write_config(PCI_DN(dn), PCI_LATENCY_TIMER, 1,
SAVED_BYTE(PCI_LATENCY_TIMER));
/* max latency, min grant, interrupt pin and line */
- rtas_write_config(pdn, 15*4, 4, pdn->config_space[15]);
+ rtas_write_config(PCI_DN(dn), 15*4, 4, edev->config_space[15]);
/* Restore PERR & SERR bits, some devices require it,
* don't touch the other command bits
*/
- rtas_read_config(pdn, PCI_COMMAND, 4, &cmd);
- if (pdn->config_space[1] & PCI_COMMAND_PARITY)
+ rtas_read_config(PCI_DN(dn), PCI_COMMAND, 4, &cmd);
+ if (edev->config_space[1] & PCI_COMMAND_PARITY)
cmd |= PCI_COMMAND_PARITY;
else
cmd &= ~PCI_COMMAND_PARITY;
- if (pdn->config_space[1] & PCI_COMMAND_SERR)
+ if (edev->config_space[1] & PCI_COMMAND_SERR)
cmd |= PCI_COMMAND_SERR;
else
cmd &= ~PCI_COMMAND_SERR;
- rtas_write_config(pdn, PCI_COMMAND, 4, cmd);
+ rtas_write_config(PCI_DN(dn), PCI_COMMAND, 4, cmd);
}
/**
* eeh_restore_bars - Restore the PCI config space info
- * @pdn: PCI device node
+ * @edev: EEH device
*
* This routine performs a recursive walk to the children
* of this device as well.
*/
-void eeh_restore_bars(struct pci_dn *pdn)
+void eeh_restore_bars(struct eeh_dev *edev)
{
struct device_node *dn;
- if (!pdn)
+ if (!edev)
return;
- if ((pdn->eeh_mode & EEH_MODE_SUPPORTED) && !IS_BRIDGE(pdn->class_code))
- eeh_restore_one_device_bars(pdn);
+ if ((edev->mode & EEH_MODE_SUPPORTED) && !IS_BRIDGE(edev->class_code))
+ eeh_restore_one_device_bars(edev);
- for_each_child_of_node(pdn->node, dn)
- eeh_restore_bars(PCI_DN(dn));
+ for_each_child_of_node(EEH_DEV_TO_OF_NODE(edev), dn)
+ eeh_restore_bars(OF_NODE_TO_EEH_DEV(dn));
}
/**
* eeh_save_bars - Save device bars
- * @pdn: PCI device node
+ * @edev: PCI device associated EEH device
*
* Save the values of the device bars. Unlike the restore
* routine, this routine is *not* recursive. This is because
* PCI devices are added individually; but, for the restore,
* an entire slot is reset at a time.
*/
-static void eeh_save_bars(struct pci_dn *pdn)
+static void eeh_save_bars(struct eeh_dev *edev)
{
int i;
+ struct device_node *dn;
- if (!pdn )
+ if (!edev)
return;
+ dn = EEH_DEV_TO_OF_NODE(edev);
for (i = 0; i < 16; i++)
- rtas_read_config(pdn, i * 4, 4, &pdn->config_space[i]);
+ rtas_read_config(PCI_DN(dn), i * 4, 4, &edev->config_space[i]);
}
/**
@@ -822,13 +830,13 @@ static void *eeh_early_enable(struct device_node *dn, void *data)
const u32 *device_id = of_get_property(dn, "device-id", NULL);
const u32 *regs;
int enable;
- struct pci_dn *pdn = PCI_DN(dn);
+ struct eeh_dev *edev = OF_NODE_TO_EEH_DEV(dn);
- pdn->class_code = 0;
- pdn->eeh_mode = 0;
- pdn->eeh_check_count = 0;
- pdn->eeh_freeze_count = 0;
- pdn->eeh_false_positives = 0;
+ edev->class_code = 0;
+ edev->mode = 0;
+ edev->check_count = 0;
+ edev->freeze_count = 0;
+ edev->false_positives = 0;
if (!of_device_is_available(dn))
return NULL;
@@ -839,10 +847,10 @@ static void *eeh_early_enable(struct device_node *dn, void *data)
/* There is nothing to check on PCI to ISA bridges */
if (dn->type && !strcmp(dn->type, "isa")) {
- pdn->eeh_mode |= EEH_MODE_NOCHECK;
+ edev->mode |= EEH_MODE_NOCHECK;
return NULL;
}
- pdn->class_code = *class_code;
+ edev->class_code = *class_code;
/* Ok... see if this device supports EEH. Some do, some don't,
* and the only way to find out is to check each and every one.
@@ -855,40 +863,40 @@ static void *eeh_early_enable(struct device_node *dn, void *data)
enable = 0;
if (ret == 0) {
- pdn->eeh_config_addr = regs[0];
+ edev->config_addr = regs[0];
/* If the newer, better, ibm,get-config-addr-info is supported,
* then use that instead.
*/
- pdn->eeh_pe_config_addr = eeh_ops->get_pe_addr(dn);
+ edev->pe_config_addr = eeh_ops->get_pe_addr(dn);
/* Some older systems (Power4) allow the
* ibm,set-eeh-option call to succeed even on nodes
* where EEH is not supported. Verify support
* explicitly.
*/
- ret = eeh_ops->get_state(pdn->node, NULL);
+ ret = eeh_ops->get_state(dn, NULL);
if (ret > 0 && ret != EEH_STATE_NOT_SUPPORT)
enable = 1;
}
if (enable) {
eeh_subsystem_enabled = 1;
- pdn->eeh_mode |= EEH_MODE_SUPPORTED;
+ edev->mode |= EEH_MODE_SUPPORTED;
pr_debug("EEH: %s: eeh enabled, config=%x pe_config=%x\n",
- dn->full_name, pdn->eeh_config_addr,
- pdn->eeh_pe_config_addr);
+ dn->full_name, edev->config_addr,
+ edev->pe_config_addr);
} else {
/* This device doesn't support EEH, but it may have an
* EEH parent, in which case we mark it as supported.
*/
- if (dn->parent && PCI_DN(dn->parent)
- && (PCI_DN(dn->parent)->eeh_mode & EEH_MODE_SUPPORTED)) {
+ if (dn->parent && OF_NODE_TO_EEH_DEV(dn->parent) &&
+ (OF_NODE_TO_EEH_DEV(dn->parent)->mode & EEH_MODE_SUPPORTED)) {
/* Parent supports EEH. */
- pdn->eeh_mode |= EEH_MODE_SUPPORTED;
- pdn->eeh_config_addr = PCI_DN(dn->parent)->eeh_config_addr;
+ edev->mode |= EEH_MODE_SUPPORTED;
+ edev->config_addr = OF_NODE_TO_EEH_DEV(dn->parent)->config_addr;
return NULL;
}
}
@@ -897,7 +905,7 @@ static void *eeh_early_enable(struct device_node *dn, void *data)
dn->full_name);
}
- eeh_save_bars(pdn);
+ eeh_save_bars(edev);
return NULL;
}
@@ -994,7 +1002,7 @@ void __init eeh_init(void)
unsigned long buid;
buid = get_phb_buid(phb);
- if (buid == 0 || PCI_DN(phb) == NULL)
+ if (buid == 0 || !OF_NODE_TO_EEH_DEV(phb))
continue;
traverse_pci_devices(phb, eeh_early_enable, NULL);
@@ -1022,9 +1030,9 @@ static void eeh_add_device_early(struct device_node *dn)
{
struct pci_controller *phb;
- if (!dn || !PCI_DN(dn))
+ if (!dn || !OF_NODE_TO_EEH_DEV(dn))
return;
- phb = PCI_DN(dn)->phb;
+ phb = OF_NODE_TO_EEH_DEV(dn)->phb;
/* USB Bus children of PCI devices will not have BUID's */
if (NULL == phb || 0 == phb->buid)
@@ -1061,7 +1069,7 @@ EXPORT_SYMBOL_GPL(eeh_add_device_tree_early);
static void eeh_add_device_late(struct pci_dev *dev)
{
struct device_node *dn;
- struct pci_dn *pdn;
+ struct eeh_dev *edev;
if (!dev || !eeh_subsystem_enabled)
return;
@@ -1069,15 +1077,16 @@ static void eeh_add_device_late(struct pci_dev *dev)
pr_debug("EEH: Adding device %s\n", pci_name(dev));
dn = pci_device_to_OF_node(dev);
- pdn = PCI_DN(dn);
- if (pdn->pcidev == dev) {
+ edev = PCI_DEV_TO_EEH_DEV(dev);
+ if (edev->pdev == dev) {
pr_debug("EEH: Already referenced !\n");
return;
}
- WARN_ON(pdn->pcidev);
+ WARN_ON(edev->pdev);
pci_dev_get(dev);
- pdn->pcidev = dev;
+ edev->pdev = dev;
+ dev->dev.archdata.edev = edev;
pci_addr_cache_insert_device(dev);
eeh_sysfs_add_device(dev);
@@ -1118,19 +1127,21 @@ EXPORT_SYMBOL_GPL(eeh_add_device_tree_late);
*/
static void eeh_remove_device(struct pci_dev *dev)
{
- struct device_node *dn;
+ struct eeh_dev *edev;
+
if (!dev || !eeh_subsystem_enabled)
return;
+ edev = PCI_DEV_TO_EEH_DEV(dev);
/* Unregister the device with the EEH/PCI address search system */
pr_debug("EEH: Removing device %s\n", pci_name(dev));
- dn = pci_device_to_OF_node(dev);
- if (PCI_DN(dn)->pcidev == NULL) {
+ if (!edev || !edev->pdev) {
pr_debug("EEH: Not referenced !\n");
return;
}
- PCI_DN(dn)->pcidev = NULL;
+ edev->pdev = NULL;
+ dev->dev.archdata.edev = NULL;
pci_dev_put(dev);
pci_addr_cache_remove_device(dev);
--
1.7.5.4
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox