* Re: Pegasos OHCI bug (was Re: PROBLEM: memory corrupting bug,
From: Segher Boessenkool @ 2010-10-27 22:05 UTC (permalink / raw)
To: pacman; +Cc: Olaf Hering, linuxppc-dev, linux-kernel
In-Reply-To: <20101027210457.23673.qmail@kosh.dhis.org>
>> > |1. How do I locate all usb nodes in the device tree?
>> > |
>> > |2. How do I know if a particular usb node is OHCI?
You look for compatible "usb-ohci".
But this doesn't help you. You do not know yet if the
problem happens for all usb-ohci; for example, it could be
that you have the console output device on usb; or as another
example, it could be that this firmware leaves all pci devices
in some active state.
So as I see it you have only two options:
1) Figure out what exactly is going on;
or 2) make the kernel shut down all pci devices early (either
in actual kernel code, or in an OF boot script).
> The big question that I'm still stumbling over is how to access the device
> registers. The "reg" property looks like this:
You should look at "assigned-addresses", not "reg". Well,
you first need to look at "reg" to figure out what entry
in "assigned-addresses" to use.
Segher
^ permalink raw reply
* Re: Pegasos OHCI bug (was Re: PROBLEM: memory corrupting bug,
From: pacman @ 2010-10-27 21:04 UTC (permalink / raw)
To: Olaf Hering; +Cc: linuxppc-dev, linux-kernel
In-Reply-To: <20101027101351.GA28218@aepfle.de>
Olaf Hering writes:
>
> On Wed, Oct 27, pacman@kosh.dhis.org wrote:
>
> > |1. How do I locate all usb nodes in the device tree?
> > |
> > |2. How do I know if a particular usb node is OHCI?
>
> In the installed system, run 'lspci | grep -i usb', this gives the pci
> bus numbers. Then run 'find /sys -name devspec', and look or the bus
Once the system is running, I have no problem figuring it out. What I meant
was how do I write some code to identify OHCI devices correctly, from within
the limited environment of the Forth interpreter, which will work in the
general case.
I already know that /pci@80000000/usb@5 and /pci@80000000/usb@5,1 are the
problem nodes on my machine. And I've learned enough about OF to do a full
recursive device tree search to find the USB nodes, so the first question is
answered.
But the UHCI and OHCI nodes look very much alike in the OF properties. "name"
is just "usb" and there's no "compatible".
The big question that I'm still stumbling over is how to access the device
registers. The "reg" property looks like this:
phys size
-------------------------- -----------------
00002800 00000000 00000000 00000000 00000000
02002810 00000000 00000000 00000000 00001000
so I take the second group of 5 words, which should be the device registers,
and try to map it to a virtual address. The members are unpacked on the stack
like this:
00000000 00000000 02002810 00000000 00001000
which looks like this stack diagram from OF spec:
map-in ( phys.lo ... phys.hi size -- virt )
and the method call goes like this:
" map-in" $call-parent
The result: "invalid pointer". But I notice it only popped 4 items. I think
maybe the "size" for map-in is not the same as the "size" found in the reg
property. Maybe #size-cells applies in one place but not the other. Thanks
for not documenting that! Try again:
00000000 00000000 02002810 00001000 " map-in" $call-parent
This one doesn't complain, but leaves me a 0 on the stack as its answer. The
OHCI registers have been mapped to virtual address 0? Doesn't seem likely.
--
Alan Curry
^ permalink raw reply
* Re: [PATCH] drivers/char/hvc_console.c: reduce max idle timeout
From: Chris Metcalf @ 2010-10-27 19:46 UTC (permalink / raw)
To: Alan Cox; +Cc: linuxppc-dev, linux-kernel
In-Reply-To: <20101027202101.226085c1@lxorguk.ukuu.org.uk>
On 10/27/2010 3:21 PM, Alan Cox wrote:
> On Wed, 27 Oct 2010 12:54:27 -0400 Chris Metcalf <cmetcalf@tilera.com> wrote:
>> The tile architecture uses this framework for our serial console,
> That may be a mistake unless your console is genuinely only capable of
> polled input.
The console is in fact interrupt-driven within the hypervisor, and data is
buffered there. However, the current hypervisor console API is only
"write" and "read". We have a bugzilla to add console interrupts to the
hypervisor API and use them from Linux, but we haven't done it yet.
--
Chris Metcalf, Tilera Corp.
http://www.tilera.com
^ permalink raw reply
* Re: [PATCH] drivers/char/hvc_console.c: reduce max idle timeout
From: Alan Cox @ 2010-10-27 19:21 UTC (permalink / raw)
To: Chris Metcalf; +Cc: linuxppc-dev, linux-kernel
In-Reply-To: <201010271659.o9RGxrMc009847@farm-0002.internal.tilera.com>
On Wed, 27 Oct 2010 12:54:27 -0400
Chris Metcalf <cmetcalf@tilera.com> wrote:
> The tile architecture uses this framework for our serial console,
That may be a mistake unless your console is genuinely only capable of
polled input.
Alan
^ permalink raw reply
* [PATCH] drivers/char/hvc_console.c: reduce max idle timeout
From: Chris Metcalf @ 2010-10-27 16:54 UTC (permalink / raw)
To: linux-kernel, linuxppc-dev
The tile architecture uses this framework for our serial console,
and our users complain that the delay of up to two seconds feels like
the machine has gone non-responsive and is disturbing. By contrast,
a delay of up to half a second feels like just the normal sort of
delay caused by swapping, network lag, etc. and is not noticeable.
The overhead is obviously not much greater.
Signed-off-by: Chris Metcalf <cmetcalf@tilera.com>
---
I'm happy to push this via the tile tree if the linuxppc-dev folks
want to give me an acked-by, or you can take it into your tree. Thanks!
drivers/char/hvc_console.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c
index 3afd62e..1df5431 100644
--- a/drivers/char/hvc_console.c
+++ b/drivers/char/hvc_console.c
@@ -565,11 +565,11 @@ static int hvc_chars_in_buffer(struct tty_struct *tty)
* and during console activity we will use a default MIN_TIMEOUT of 10. When
* the console is idle, we increase the timeout value on each pass through
* msleep until we reach the max. This may be noticeable as a brief (average
- * one second) delay on the console before the console responds to input when
+ * 0.25 second) delay on the console before the console responds to input when
* there has been no input for some time.
*/
#define MIN_TIMEOUT (10)
-#define MAX_TIMEOUT (2000)
+#define MAX_TIMEOUT (500)
static u32 timeout = MIN_TIMEOUT;
#define HVC_POLL_READ 0x00000001
--
1.6.5.2
^ permalink raw reply related
* Re: [PATCH] powerpc/5121: pdm360ng: fix touch irq if 8xxx gpio driver is enabled
From: Grant Likely @ 2010-10-27 13:40 UTC (permalink / raw)
To: Anatolij Gustschin; +Cc: linuxppc-dev
In-Reply-To: <20100925222244.2fad5ff6@wker>
On Sat, Sep 25, 2010 at 10:22:44PM +0200, Anatolij Gustschin wrote:
> On Wed, 15 Sep 2010 20:38:23 -0600
> Grant Likely <grant.likely@secretlab.ca> wrote:
>
> > On Wed, Sep 15, 2010 at 10:12:57PM +0200, Anatolij Gustschin wrote:
> > > Enabling the MPC8xxx GPIO driver with MPC512x GPIO extension
> > > breaks touch screen support on this board since the GPIO
> > > interrupt will be mapped to 8xxx GPIO irq host resulting in
> > > a not requestable interrupt in the touch screen driver. Fix
> > > it by mapping the touch interrupt on 8xxx GPIO irq host.
> >
> > This looks wrong to me. The touchscreen code should not go mucking
> > about in the GPIO controller registers; that is the job of the gpio
> > driver.
>
> But if there is no GPIO driver (as it was the case before adding
> mpc512x support in the 8xxx gpio driver) or if the driver is not
> enabled in the kernel configuration? Then the platform specific
> callback (called from touchscreen driver) returns the pin state
> and acknowlegdes the interrupt.
So, basically the touchscreen device node has an interrupts property
which does not use the gpio controller as the interrupt controller,
but instead points directly and the interrupt controller that the gpio
controller is cascaded from.
Really it sounds like the device tree data is broken. The preferred
solution is be to fix the device tree to declare the gpio node as
an interrupt controller.
>
> > What is the reason that the touch interrupt isn't
> > requestable?
>
> The 8xxx gpio driver sets up gpio irq host and installs
> the chained irq handler for GPIO interrupt 78 using
> set_irq_chained_handler() which sets the status field of
> the irq_desc structure to IRQ_NOREQUEST | IRQ_NOPROBE.
> Other drivers can't request this GPIO interrupt any more,
> request_threaded_irq() checks the IRQ_NOREQUEST status
> flag and returns -EINVAL if it is set. The gpio interrupts
> for each gpio pin are now handled by the
> mpc8xxx_gpio_irq_cascade() handler as they should.
>
> > It looks like the 8xxx gpio driver is designed to hand
> > out a separate virq number for each gpio pin (I've not had time to dig
> > into details, so you'll need to educate me on the problem details)
>
> Yes, exactly. This patch adds code to request the
> board's pen_down gpio pin and to use it's virq number in
> the touchscreen driver. The touchscreen driver can
> request this virq interrupt and it is now properly handled
> by the chained handler in the gpio driver.
...but it does so by hard coding the irq number (via the GPIO number)
into the board code; a situation which I've tried very hard to avoid.
This is what I'm not okay with.
Another solution is to modify the 8xxx gpio driver to cascade off the
normal request_irq() path instead of via set_irq_chained_handler(),
but that *might* have unacceptable performance impact for other users.
Unfortunately, I've been slow on this patch, so I cannot get anything
into 2.6.37 (sorry). However, I've not asked Linus to pull the 8xxx
gpio driver changes either so nothing in mainline will get broken.
g.
^ permalink raw reply
* Re: Pegasos OHCI bug (was Re: PROBLEM: memory corrupting bug, bisected to 6dda9d55)
From: Benjamin Herrenschmidt @ 2010-10-27 13:27 UTC (permalink / raw)
To: pacman; +Cc: linuxppc-dev, linux-kernel
In-Reply-To: <20101027085738.1837.qmail@kosh.dhis.org>
> Since then, the silence has been deafening.
>
> My assumption now is that this is not ever getting fixed. I'm certainly not
> able to fix it. I'm not a even kernel programmer! I got far enough to
> diagnose the cause just with the "add more printk's and boot it again"
> technique. Hundreds of reboots trying to figure it out. I was a conscientious
> bug-reporter, I thought.
I'm happy to help you fix it but I'm travelling at the moment and won't
have much time for a couple of weeks.
Cheers,
Ben.
> I could pull the PCI card and be done with it. I never used those USB ports
> anyway. But after all the suffering I went through to find this bug... the
> crashing e2fsck's and consequent filesystem corruption... I hate the idea of
> surrendering to it. There are possibly other affected users who I'd be
> abandoning to suffer similarly in the future.
>
> For the last week I've studied OpenFirmware as hard as I can. I read the spec
> cover to cover. And the USB annex, and the PCI annex. But I'm still lost in
> all the different address formats.
>
> I took my best guess on how to handle this problem, and ran with it, ending
> up with a 97-line Forth script, and that was just to get a virtual address,
> not to actually do anything with it, and it used a hardcoded device path. But
> it didn't work, all I got was an "invalid pointer" error. I made another
> guess at something that wasn't documented anywhere (the fact that this stuff
> is insufficiently documented is the one thing I can state with complete
> confidence!) and out came a successful translation to a virtual address: 0.
>
> If I'm the only one fighting this bug, the bug wins.
>
^ permalink raw reply
* RE: Freescale P2020/ 85xx PCIe: DMA low throughtput
From: Jenkins, Clive @ 2010-10-27 11:28 UTC (permalink / raw)
To: Natalie Shapira; +Cc: linuxppc-dev, zw
In-Reply-To: <4CC7EFFC.10405@extricom.com>
> Hi,=20
> =09
> I'm working on bring up for a new board based on
Freescales p2020.
> I have a programmable FPGA as a PCIe device with a
buffer I can
> write to and from.
> I want to test performence for the PCIe bus.=20
> I encountered a problem while doing a DMA between the
FPGA & DDR.=20
> The whole buffer moves to and from the device with
out
> mismatches but with low throughtput.=20
> The thing is that the buffer divided to many
transactions of byte
> size instead of transferring it in a burst.=20
> I must mention that even a buffer of word size, divided
in to byte
> transactions by the DMA (the core can read a word so it
seems like
> the DMA fault.
> I tried to change the latency timer, max latency, min
latency and
> cache line in the configuration space of both sides of
the pcie
> bus. It didn't help.
> Do you have an idea what can it be?=20
> =09
> Thanks,
> Natalie.=20
> =20
>
>=09
> Assuming the P2020 has the usual 85xx-style DMA engine, you may
have
> the Band Width Control cleared to 0. This 4-bit field (BWC)
restricts
> the transfer size to 2^BWC bytes, for BWC=3D0,1,..0xa. 0xb-0xe are
> reserved. 0xf disables bandwidth sharing to allow uninterrupted
> transfers from each channel, so if you are using several
channels
> one channel can completely lock out other channels. BWC=3D0x8 at
reset
> (2^8 =3D 256 bytes). See the P2020 manual for more details.
>=09
> BWC is the field with mask 0x0f000000 in the MR (Master Reset)
> register for the channel (0, 1, 2, 3), at offset 0x100, 0x180,
0x200,
> 0x280 relative to the base of the DMA controller.
>=09
> Clive
>=09
>=09
> =20
>
> Hi, Thanks.
> I changed the BWC but the transactions are still in a byte size
instead
> of burst. Do you have another idea?
>
> Natalie.
Sorry, no.
Are you sure you have modified the FSL-DMA driver in the kernel so it
does not
write zero to BWC?
Clive
^ permalink raw reply
* Re: Pegasos OHCI bug (was Re: PROBLEM: memory corrupting bug, bisected to 6dda9d55)
From: Olaf Hering @ 2010-10-27 10:13 UTC (permalink / raw)
To: pacman; +Cc: linuxppc-dev, linux-kernel
In-Reply-To: <20101027085738.1837.qmail@kosh.dhis.org>
On Wed, Oct 27, pacman@kosh.dhis.org wrote:
> |1. How do I locate all usb nodes in the device tree?
> |
> |2. How do I know if a particular usb node is OHCI?
In the installed system, run 'lspci | grep -i usb', this gives the pci
bus numbers. Then run 'find /sys -name devspec', and look or the bus
numbers from the lspci output. Each devspec file contains the firmware
path. The ohci node may have subdirectories. Run 'words' in each of
them at the firmware prompt. Perhaps there is one to shutdown the
controller?
I just noticed older firmware did not have a node for ohci, newer ones
my have a /pci@80000000/usb@5 node.
Good luck.
Olaf
^ permalink raw reply
* Re: Freescale P2020/ 85xx PCIe: DMA low throughtput
From: Natalie Shapira @ 2010-10-27 9:25 UTC (permalink / raw)
To: Jenkins, Clive; +Cc: linuxppc-dev, zw
In-Reply-To: <929D3CED81F34E43887A393170D66FB90355C3CA@GBRSUN01MS002.eu.xerox.net>
[-- Attachment #1: Type: text/plain, Size: 1743 bytes --]
Jenkins, Clive wrote:
>> Hi,
>>
>> I'm working on bring up for a new board based on Freescales p2020.
>> I have a programmable FPGA as a PCIe device with a buffer I can
>> write to and from.
>> I want to test performence for the PCIe bus.
>> I encountered a problem while doing a DMA between the FPGA & DDR.
>> The whole buffer moves to and from the device with out
>> mismatches but with low throughtput.
>> The thing is that the buffer divided to many transactions of byte
>> size instead of transferring it in a burst.
>> I must mention that even a buffer of word size, divided in to byte
>> transactions by the DMA (the core can read a word so it seems like
>> the DMA fault.
>> I tried to change the latency timer, max latency, min latency and
>> cache line in the configuration space of both sides of the pcie
>> bus. It didn't help.
>> Do you have an idea what can it be?
>>
>> Thanks,
>> Natalie.
>>
>
> Assuming the P2020 has the usual 85xx-style DMA engine, you may have
> the Band Width Control cleared to 0. This 4-bit field (BWC) restricts
> the transfer size to 2^BWC bytes, for BWC=0,1,..0xa. 0xb-0xe are
> reserved. 0xf disables bandwidth sharing to allow uninterrupted
> transfers from each channel, so if you are using several channels
> one channel can completely lock out other channels. BWC=0x8 at reset
> (2^8 = 256 bytes). See the P2020 manual for more details.
>
> BWC is the field with mask 0x0f000000 in the MR (Master Reset)
> register for the channel (0, 1, 2, 3), at offset 0x100, 0x180, 0x200,
> 0x280 relative to the base of the DMA controller.
>
> Clive
>
>
>
Hi, Thanks.
I changed the BWC but the transactions are still in a byte size instead
of burst.
Do you have another idea?
Natalie.
[-- Attachment #2: Type: text/html, Size: 2126 bytes --]
^ permalink raw reply
* Pegasos OHCI bug (was Re: PROBLEM: memory corrupting bug, bisected to 6dda9d55)
From: pacman @ 2010-10-27 8:57 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: linuxppc-dev, linux-kernel
In-Reply-To: <1287608215.2198.23.camel@pasglop>
Benjamin Herrenschmidt writes:
>
> Ok so you'll have to make up a "workaround" in prom_init that looks for
> OHCI's in the device-tree and disable them.
>
> Check if the OHCI node has some existing f-code words you can use for
> that with "dev /path-to-ohci words" in OF for example. If not, you may
> need to use the low level register accessors. Use OF client interface
> "interpret" to run forth code from C.
I responded with a long list of reasons that I'm not qualified to do that
work myself:
|Here are the major problems:
|
|1. How do I locate all usb nodes in the device tree?
|
|2. How do I know if a particular usb node is OHCI?
|
|3. Knowing that a node is OHCI, how do I know where its control registers
|are? I'm sure this is calculated from the "reg" property but I don't see how.
|
|4. Knowing where the control registers are, how do I access them? Do I need
|to request a virt-to-phys mapping or can I assume that it's already mapped,
|or that the "rl!" command will do the right thing with a physical address?
|
|5. Which control register should I use to tell the OHCI to be quiet? Just do
|a general reset, or is there something that specifically turns off the
|counter that's been causing the trouble?
Since then, the silence has been deafening.
My assumption now is that this is not ever getting fixed. I'm certainly not
able to fix it. I'm not a even kernel programmer! I got far enough to
diagnose the cause just with the "add more printk's and boot it again"
technique. Hundreds of reboots trying to figure it out. I was a conscientious
bug-reporter, I thought.
I could pull the PCI card and be done with it. I never used those USB ports
anyway. But after all the suffering I went through to find this bug... the
crashing e2fsck's and consequent filesystem corruption... I hate the idea of
surrendering to it. There are possibly other affected users who I'd be
abandoning to suffer similarly in the future.
For the last week I've studied OpenFirmware as hard as I can. I read the spec
cover to cover. And the USB annex, and the PCI annex. But I'm still lost in
all the different address formats.
I took my best guess on how to handle this problem, and ran with it, ending
up with a 97-line Forth script, and that was just to get a virtual address,
not to actually do anything with it, and it used a hardcoded device path. But
it didn't work, all I got was an "invalid pointer" error. I made another
guess at something that wasn't documented anywhere (the fact that this stuff
is insufficiently documented is the one thing I can state with complete
confidence!) and out came a successful translation to a virtual address: 0.
If I'm the only one fighting this bug, the bug wins.
--
Alan Curry
^ permalink raw reply
* Re: [REPOST] [PATCH 0/6] fixes and MPC8308 support for the mpc512x_dma driver
From: Piotr Zięcik @ 2010-10-27 7:24 UTC (permalink / raw)
To: Ilya Yanok; +Cc: vlad, linuxppc-dev, wd, dzu
In-Reply-To: <1288137180-3220-1-git-send-email-yanok@emcraft.com>
On Wednesday 27 October 2010 01:52:54 Ilya Yanok wrote:
> Hello everybody,
>
> meanwhile I've fixed one more issue in mpc512x_dma driver.
>
> Any comments? Anybody interrested in this driver? Piotr?
>
> Still unsure how to deal with bitfield structures in IO space...
>
Currently I am not able to deal with this as I am much involved in other development.
--
Best Regards,
Piotr Zięcik.
^ permalink raw reply
* [RFC PATCH 7/7 v2] ppc: add dynamic dma window support
From: Nishanth Aravamudan @ 2010-10-27 3:35 UTC (permalink / raw)
To: nacc; +Cc: sonnyrao, miltonm, Paul Mackerras, Anton Blanchard, linuxppc-dev
In-Reply-To: <1288150518-4026-1-git-send-email-nacc@us.ibm.com>
If firmware allows us to map all of a partition's memory for DMA on a
particular bridge, create a 1:1 mapping of that memory. Add hooks for
dealing with hotplug events. Dyanmic DMA windows can use larger than the
default page size, and we use the largest one possible.
Not-yet-signed-off-by: Nishanth Aravamudan <nacc@us.ibm.com>
---
I've tested this briefly on a machine with suitable firmware/hardware.
Things seem to work well, but I want to do more exhaustive I/O testing
before asking for upstream merging. I would really appreciate any
feedback on the updated approach.
Specific questions:
Ben, did I hook into the dma_set_mask() platform callback as you
expected? Anything I can do better or which perhaps might lead to
gotchas later?
I've added a disable_ddw option, but perhaps it would be better to
just disable the feature if iommu=force?
---
arch/powerpc/platforms/pseries/iommu.c | 577 +++++++++++++++++++++++++++++++-
1 files changed, 575 insertions(+), 2 deletions(-)
diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c
index 45c6865..8090b6b 100644
--- a/arch/powerpc/platforms/pseries/iommu.c
+++ b/arch/powerpc/platforms/pseries/iommu.c
@@ -33,6 +33,7 @@
#include <linux/pci.h>
#include <linux/dma-mapping.h>
#include <linux/crash_dump.h>
+#include <linux/memory.h>
#include <asm/io.h>
#include <asm/prom.h>
#include <asm/rtas.h>
@@ -45,6 +46,7 @@
#include <asm/tce.h>
#include <asm/ppc-pci.h>
#include <asm/udbg.h>
+#include <asm/mmzone.h>
#include "plpar_wrappers.h"
@@ -270,6 +272,139 @@ static unsigned long tce_get_pSeriesLP(struct iommu_table *tbl, long tcenum)
return tce_ret;
}
+/* this is compatable with cells for the device tree property */
+struct dynamic_dma_window_prop {
+ __be32 liobn; /* tce table number */
+ __be64 dma_base; /* address hi,lo */
+ __be32 tce_shift; /* ilog2(tce_page_size) */
+ __be32 window_shift; /* ilog2(tce_window_size) */
+};
+
+struct direct_window {
+ struct device_node *device;
+ const struct dynamic_dma_window_prop *prop;
+ struct list_head list;
+};
+static LIST_HEAD(direct_window_list);
+/* prevents races between memory on/offline and window creation */
+static DEFINE_SPINLOCK(direct_window_list_lock);
+/* protects initializing window twice for same device */
+static DEFINE_MUTEX(direct_window_init_mutex);
+#define DIRECT64_PROPNAME "linux,direct64-ddr-window-info"
+
+static int tce_clearrange_multi_pSeriesLP(unsigned long start_pfn,
+ unsigned long num_pfn, const void *arg)
+{
+ const struct dynamic_dma_window_prop *maprange = arg;
+ int rc;
+ u64 tce_size, num_tce, dma_offset, next;
+ u32 tce_shift;
+ long limit;
+
+ tce_shift = be32_to_cpu(maprange->tce_shift);
+ tce_size = 1ULL << tce_shift;
+ next = start_pfn << PAGE_SHIFT;
+ num_tce = num_pfn << PAGE_SHIFT;
+
+ /* round back to the beginning of the tce page size */
+ num_tce += next & (tce_size - 1);
+ next &= ~(tce_size - 1);
+
+ /* covert to number of tces */
+ num_tce |= tce_size - 1;
+ num_tce >>= tce_shift;
+
+ do {
+ /*
+ * Set up the page with TCE data, looping through and setting
+ * the values.
+ */
+ limit = min_t(long, num_tce, 512);
+ dma_offset = next + be64_to_cpu(maprange->dma_base);
+
+ rc = plpar_tce_stuff(be64_to_cpu(maprange->liobn),
+ (u64)dma_offset,
+ 0, limit);
+ num_tce -= limit;
+ } while (num_tce > 0 && !rc);
+
+ return rc;
+}
+
+static int tce_setrange_multi_pSeriesLP(unsigned long start_pfn,
+ unsigned long num_pfn, const void *arg)
+{
+ const struct dynamic_dma_window_prop *maprange = arg;
+ u64 *tcep, tce_size, num_tce, dma_offset, next, proto_tce, liobn;
+ u32 tce_shift;
+ u64 rc = 0;
+ long l, limit;
+
+ local_irq_disable(); /* to protect tcep and the page behind it */
+ tcep = __get_cpu_var(tce_page);
+
+ if (!tcep) {
+ tcep = (u64 *)__get_free_page(GFP_ATOMIC);
+ if (!tcep) {
+ local_irq_enable();
+ return -ENOMEM;
+ }
+ __get_cpu_var(tce_page) = tcep;
+ }
+
+ proto_tce = TCE_PCI_READ | TCE_PCI_WRITE;
+
+ liobn = (u64)be32_to_cpu(maprange->liobn);
+ tce_shift = be32_to_cpu(maprange->tce_shift);
+ tce_size = 1ULL << tce_shift;
+ next = start_pfn << PAGE_SHIFT;
+ num_tce = num_pfn << PAGE_SHIFT;
+
+ /* round back to the beginning of the tce page size */
+ num_tce += next & (tce_size - 1);
+ next &= ~(tce_size - 1);
+
+ /* covert to number of tces */
+ num_tce |= tce_size - 1;
+ num_tce >>= tce_shift;
+
+ /* We can map max one pageful of TCEs at a time */
+ do {
+ /*
+ * Set up the page with TCE data, looping through and setting
+ * the values.
+ */
+ limit = min_t(long, num_tce, 4096/TCE_ENTRY_SIZE);
+ dma_offset = next + be64_to_cpu(maprange->dma_base);
+
+ for (l = 0; l < limit; l++) {
+ tcep[l] = proto_tce | next;
+ next += tce_size;
+ }
+
+ rc = plpar_tce_put_indirect(liobn,
+ (u64)dma_offset,
+ (u64)virt_to_abs(tcep),
+ limit);
+
+ num_tce -= limit;
+ } while (num_tce > 0 && !rc);
+ printk("plpar_tce_put_indirect for offset 0x%llx and tcep[0] 0x%llx returned %llu\n",
+ (u64)dma_offset, tcep[0], rc);
+
+ /* error cleanup: caller will clear whole range */
+
+ local_irq_enable();
+ return rc;
+}
+
+static int tce_setrange_multi_pSeriesLP_walk(unsigned long start_pfn,
+ unsigned long num_pfn, void *arg)
+{
+ return tce_setrange_multi_pSeriesLP(start_pfn, num_pfn, arg);
+}
+
+
#ifdef CONFIG_PCI
static void iommu_table_setparms(struct pci_controller *phb,
struct device_node *dn,
@@ -449,8 +584,7 @@ static void pci_dma_bus_setup_pSeriesLP(struct pci_bus *bus)
if (!ppci->iommu_table) {
tbl = kzalloc_node(sizeof(struct iommu_table), GFP_KERNEL,
ppci->phb->node);
- iommu_table_setparms_lpar(ppci->phb, pdn, tbl, dma_window,
- bus->number);
+ iommu_table_setparms_lpar(ppci->phb, pdn, tbl, dma_window);
ppci->iommu_table = iommu_init_table(tbl, ppci->phb->node);
pr_debug(" created table: %p\n", ppci->iommu_table);
}
@@ -496,6 +630,338 @@ static void pci_dma_dev_setup_pSeries(struct pci_dev *dev)
pci_name(dev));
}
+static int __read_mostly disable_ddw;
+
+static int __init disable_ddw_setup(char *str)
+{
+ disable_ddw = 1;
+ printk(KERN_INFO "ppc iommu: disabling ddw.\n");
+
+ return 0;
+}
+
+early_param("disable_ddw", disable_ddw_setup);
+
+static void remove_ddw(struct device_node *np)
+{
+ struct dynamic_dma_window_prop *dwp;
+ struct property *win64;
+ const u32 *ddr_avail;
+ u64 liobn;
+ int len, ret;
+
+ ddr_avail = of_get_property(np, "ibm,ddw-applicable", &len);
+ win64 = of_find_property(np, DIRECT64_PROPNAME, NULL);
+ if (!win64 || !ddr_avail || len < 3 * sizeof(u32))
+ return;
+
+ dwp = win64->value;
+ liobn = (u64)be32_to_cpu(dwp->liobn);
+
+ /* clear the whole window, note the arg is in kernel pages */
+ ret = tce_clearrange_multi_pSeriesLP(0,
+ 1ULL << (be32_to_cpu(dwp->window_shift) - PAGE_SHIFT), dwp);
+ if (ret)
+ pr_warning("%s failed to clear tces in window.\n",
+ np->full_name);
+ else
+ pr_warning("%s successfully cleared tces in window.\n",
+ np->full_name);
+
+ ret = rtas_call(ddr_avail[2], 1, 1, NULL, liobn);
+ if (ret)
+ pr_warning("%s: failed to remove direct window: rtas returned "
+ "%d to ibm,remove-pe-dma-window(%x) %llx\n",
+ np->full_name, ret, ddr_avail[2], liobn);
+ else
+ pr_warning("%s: successfully removed direct window: rtas returned "
+ "%d to ibm,remove-pe-dma-window(%x) %llx\n",
+ np->full_name, ret, ddr_avail[2], liobn);
+
+ ret = prom_remove_property(np, win64);
+ if (ret)
+ pr_warning("%s: failed to remove direct window property (%i)\n",
+ np->full_name, ret);
+ else
+ pr_warning("%s: successfully removed direct window property (%i)\n",
+ np->full_name, ret);
+}
+
+
+static int dupe_ddw_if_already_created(struct pci_dev *dev, struct device_node *pdn)
+{
+ struct device_node *dn;
+ struct pci_dn *pcidn;
+ struct direct_window *window;
+ const struct dynamic_dma_window_prop *direct64;
+ u64 dma_addr;
+
+ dn = pci_device_to_OF_node(dev);
+ pcidn = PCI_DN(dn);
+ spin_lock(&direct_window_list_lock);
+ /* check if we already created a window and dupe that config if so */
+ list_for_each_entry(window, &direct_window_list, list) {
+ if (window->device == pdn) {
+ direct64 = window->prop;
+ dma_addr = direct64->dma_base;
+ break;
+ }
+ }
+ spin_unlock(&direct_window_list_lock);
+
+ return dma_addr;
+}
+
+static u64 dupe_ddw_if_kexec(struct pci_dev *dev, struct device_node *pdn)
+{
+ struct device_node *dn;
+ struct pci_dn *pcidn;
+ int len;
+ struct direct_window *window;
+ const struct dynamic_dma_window_prop *direct64;
+ u64 dma_addr;
+
+ dn = pci_device_to_OF_node(dev);
+ pcidn = PCI_DN(dn);
+ direct64 = of_get_property(pdn, DIRECT64_PROPNAME, &len);
+ if (direct64) {
+ window = kzalloc(sizeof(*window), GFP_KERNEL);
+ if (!window) {
+ remove_ddw(pdn);
+ } else {
+ window->device = pdn;
+ window->prop = direct64;
+ spin_lock(&direct_window_list_lock);
+ list_add(&window->list, &direct_window_list);
+ spin_unlock(&direct_window_list_lock);
+ dma_addr = direct64->dma_base;
+ }
+ }
+
+ return dma_addr;
+}
+
+static int query_ddw(struct pci_dev *dev, const u32 *ddr_avail, u32 *query)
+{
+ struct device_node *dn;
+ struct pci_dn *pcidn;
+ u32 cfg_addr;
+ u64 buid;
+ int ret;
+
+ /*
+ * Get the config address and phb build of the PE window.
+ * Rely on eeh to retrieve this for us.
+ * Retrieve them from the pci device, not the node with the
+ * dma-window property
+ */
+ dn = pci_device_to_OF_node(dev);
+ pcidn = PCI_DN(dn);
+ cfg_addr = pcidn->eeh_config_addr;
+ if (pcidn->eeh_pe_config_addr)
+ cfg_addr = pcidn->eeh_pe_config_addr;
+ buid = pcidn->phb->buid;
+ ret = rtas_call(ddr_avail[0], 3, 5, query,
+ cfg_addr, BUID_HI(buid), BUID_LO(buid));
+ dev_info(&dev->dev, "ibm,query-pe-dma-windows(%x) %x %x %x"
+ " returned %d\n", ddr_avail[0], cfg_addr, BUID_HI(buid),
+ BUID_LO(buid), ret);
+ return ret;
+}
+
+static int create_ddw(struct pci_dev *dev, const u32 *ddr_avail, u32 *create, int page_shift, int window_shift)
+{
+ struct device_node *dn;
+ struct pci_dn *pcidn;
+ u32 cfg_addr;
+ u64 buid;
+ int ret;
+
+ /*
+ * Get the config address and phb build of the PE window.
+ * Rely on eeh to retrieve this for us.
+ * Retrieve them from the pci device, not the node with the
+ * dma-window property
+ */
+ dn = pci_device_to_OF_node(dev);
+ pcidn = PCI_DN(dn);
+ cfg_addr = pcidn->eeh_config_addr;
+ if (pcidn->eeh_pe_config_addr)
+ cfg_addr = pcidn->eeh_pe_config_addr;
+ buid = pcidn->phb->buid;
+
+ do {
+ /* extra outputs are LIOBN and dma-addr (hi, lo) */
+ ret = rtas_call(ddr_avail[1], 5, 4, &create[0], cfg_addr,
+ BUID_HI(buid), BUID_LO(buid), page_shift, window_shift);
+ } while(rtas_busy_delay(ret));
+ dev_info(&dev->dev,
+ "ibm,create-pe-dma-window(%x) %x %x %x %x %x returned %d "
+ "(liobn = 0x%x starting addr = %x %x\n", ddr_avail[1],
+ cfg_addr, BUID_HI(buid), BUID_LO(buid), page_shift,
+ window_shift, ret, create[0], create[1], create[2]);
+
+ return ret;
+}
+
+/*
+ * If the PE supports dynamic dma windows, and there is space for a table
+ * that can map all pages in a linear offset, then setup such a table,
+ * and record the dma-offset in the struct device.
+ *
+ * dev: the pci device we are checking
+ * pdn: the parent pe node with the ibm,dma_window property
+ * Future: also check if we can remap the base window for our base page size
+ *
+ * returns the dma offset for use by dma_set_mask
+ */
+static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn)
+{
+ int len, ret;
+ u32 query[4], create[3];
+ int page_shift;
+ u64 dma_addr, max_addr;
+ struct device_node *dn;
+ const u32 *uninitialized_var(ddr_avail);
+ struct direct_window *window;
+ struct property *uninitialized_var(win64);
+ struct dynamic_dma_window_prop *ddwprop;
+ const struct dynamic_dma_window_prop *direct64;
+
+ mutex_lock(&direct_window_init_mutex);
+
+ dma_addr = dupe_ddw_if_already_created(dev, pdn);
+ if (dma_addr != 0)
+ goto out_unlock;
+
+ dma_addr = dupe_ddw_if_kexec(dev, pdn);
+ if (dma_addr != 0)
+ goto out_unlock;
+
+ /*
+ * the ibm,ddw-applicable property holds the tokens for:
+ * ibm,query-pe-dma-window
+ * ibm,create-pe-dma-window
+ * ibm,remove-pe-dma-window
+ * for the given node in that order.
+ * the property is actually in the parent, not the PE
+ */
+ ddr_avail = of_get_property(pdn, "ibm,ddw-applicable", &len);
+ if (!ddr_avail || len < 3 * sizeof(u32))
+ goto out_unlock;
+
+ /*
+ * Query if there is a second window of size to map the
+ * whole partition. Query returns number of windows, largest
+ * block assigned to PE (partition endpoint), and two bitmasks
+ * of page sizes: supported and supported for migrate-dma.
+ */
+ dn = pci_device_to_OF_node(dev);
+ ret = query_ddw(dev, ddr_avail, &query[0]);
+ if (ret != 0)
+ goto out_unlock;
+
+ if (!query[0]) {
+ /*
+ * no additional windows are available for this device.
+ * We might be able to reallocate the existing window,
+ * trading in for a larger page size.
+ */
+ dev_dbg(&dev->dev, "no free dynamic windows");
+ goto out_unlock;
+ }
+ if (query[2] & 4) {
+ page_shift = 24; /* 16MB */
+ } else if (query[2] & 2) {
+ page_shift = 16; /* 64kB */
+ } else if (query[2] & 1) {
+ page_shift = 12; /* 4kB */
+ } else {
+ dev_dbg(&dev->dev, "no supported direct page size in mask %x",
+ query[2]);
+ goto out_unlock;
+ }
+ /* verify the window * number of ptes will map the partition */
+ /* check largest block * page size > max memory hotplug addr */
+ max_addr = memory_hotplug_max();
+ if (query[1] < (max_addr >> page_shift)) {
+ dev_dbg(&dev->dev, "can't map partiton max 0x%llx with %u "
+ "%llu-sized pages\n", max_addr, query[1],
+ 1ULL << page_shift);
+ goto out_unlock;
+ }
+ len = order_base_2(max_addr);
+ win64 = kzalloc(sizeof(struct property), GFP_KERNEL);
+ if (!win64) {
+ dev_info(&dev->dev,
+ "couldn't allocate property for 64bit dma window\n");
+ goto out_unlock;
+ }
+ win64->name = kstrdup(DIRECT64_PROPNAME, GFP_KERNEL);
+ win64->value = ddwprop = kmalloc(sizeof(*ddwprop), GFP_KERNEL);
+ if (!win64->name || !win64->value) {
+ dev_info(&dev->dev,
+ "couldn't allocate property name and value\n");
+ goto out_free_prop;
+ }
+
+ ret = create_ddw(dev, ddr_avail, &create[0], page_shift, len);
+ if (ret != 0)
+ goto out_free_prop;
+
+ *ddwprop = (struct dynamic_dma_window_prop) {
+ .liobn = cpu_to_be32(create[0]),
+ .dma_base = cpu_to_be64(((u64)create[1] << 32) + (u64)create[2]),
+ .tce_shift = cpu_to_be32(page_shift),
+ .window_shift = cpu_to_be32(len)
+ };
+
+ dev_dbg(&dev->dev, "created tce table LIOBN 0x%x for %s\n",
+ create[0], dn->full_name);
+
+ ret = walk_system_ram_range(0, memblock_end_of_DRAM() >> PAGE_SHIFT,
+ win64->value, tce_setrange_multi_pSeriesLP_walk);
+ if (ret) {
+ dev_info(&dev->dev, "failed to map direct window for %s: %d\n",
+ dn->full_name, ret);
+ goto out_clear_window;
+ }
+
+ ret = prom_add_property(pdn, win64);
+ if (ret) {
+ dev_err(&dev->dev, "unable to add dma window property for %s: %d",
+ pdn->full_name, ret);
+ goto out_clear_window;
+ }
+
+ direct64 = ddwprop;
+
+ window = kzalloc(sizeof(*window), GFP_KERNEL);
+ if (!window)
+ goto out_clear_window;
+ window->device = pdn;
+ window->prop = direct64;
+ spin_lock(&direct_window_list_lock);
+ list_add(&window->list, &direct_window_list);
+ spin_unlock(&direct_window_list_lock);
+
+ dma_addr = of_read_number(&create[1], 2);
+ set_dma_offset(&dev->dev, dma_addr);
+ goto out_unlock;
+
+out_clear_window:
+ remove_ddw(pdn);
+
+out_free_prop:
+ kfree(win64->name);
+ kfree(win64->value);
+ kfree(win64);
+
+out_unlock:
+ mutex_unlock(&direct_window_init_mutex);
+ return dma_addr;
+}
+
static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev)
{
struct device_node *pdn, *dn;
@@ -542,23 +1008,128 @@ static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev)
set_iommu_table_base(&dev->dev, pci->iommu_table);
}
+
+static int dma_set_mask_pSeriesLP(struct device *dev, u64 dma_mask)
+{
+ bool ddw_enabled = false;
+ struct device_node *pdn, *dn;
+ struct pci_dev *pdev;
+ const void *dma_window = NULL;
+ u64 dma_offset;
+
+ if (!dev->dma_mask || !dma_supported(dev, dma_mask))
+ return -EIO;
+
+ /* only attempt to use a new window if 64-bit DMA is requested */
+ if (!disable_ddw && dma_mask == DMA_BIT_MASK(64)) {
+ pdev = to_pci_dev(dev);
+
+ dn = pci_device_to_OF_node(pdev);
+ dev_dbg(dev, "node is %s\n", dn->full_name);
+
+ /*
+ * the device tree might contain the dma-window properties
+ * per-device and not neccesarily for the bus. So we need to
+ * search upwards in the tree until we either hit a dma-window
+ * property, OR find a parent with a table already allocated.
+ */
+ for (pdn = dn; pdn && PCI_DN(pdn) && !PCI_DN(pdn)->iommu_table;
+ pdn = pdn->parent) {
+ dma_window = of_get_property(pdn, "ibm,dma-window", NULL);
+ if (dma_window)
+ break;
+ }
+ if (pdn && PCI_DN(pdn)) {
+ dma_offset = enable_ddw(pdev, pdn);
+ if (dma_offset != 0) {
+ dev_info(dev, "Using 64-bit direct DMA at offset %llx\n", dma_offset);
+ set_dma_offset(dev, dma_offset);
+ set_dma_ops(dev, &dma_direct_ops);
+ ddw_enabled = true;
+ }
+ }
+ }
+
+ /* fall-through to iommu ops */
+ if (!ddw_enabled) {
+ dev_info(dev, "Using 32-bit DMA via iommu\n");
+ set_dma_ops(dev, &dma_iommu_ops);
+ }
+
+ *dev->dma_mask = dma_mask;
+ return 0;
+}
+
#else /* CONFIG_PCI */
#define pci_dma_bus_setup_pSeries NULL
#define pci_dma_dev_setup_pSeries NULL
#define pci_dma_bus_setup_pSeriesLP NULL
#define pci_dma_dev_setup_pSeriesLP NULL
+#define dma_set_mask_pSeriesLP NULL
#endif /* !CONFIG_PCI */
+static int iommu_mem_notifier(struct notifier_block *nb, unsigned long action,
+ void *data)
+{
+ struct direct_window *window;
+ struct memory_notify *arg = data;
+ int ret = 0;
+
+ switch (action) {
+ case MEM_GOING_ONLINE:
+ spin_lock(&direct_window_list_lock);
+ list_for_each_entry(window, &direct_window_list, list) {
+ ret |= tce_setrange_multi_pSeriesLP(arg->start_pfn,
+ arg->nr_pages, window->prop);
+ /* XXX log error */
+ }
+ spin_unlock(&direct_window_list_lock);
+ break;
+ case MEM_CANCEL_ONLINE:
+ case MEM_OFFLINE:
+ spin_lock(&direct_window_list_lock);
+ list_for_each_entry(window, &direct_window_list, list) {
+ ret |= tce_clearrange_multi_pSeriesLP(arg->start_pfn,
+ arg->nr_pages, window->prop);
+ /* XXX log error */
+ }
+ spin_unlock(&direct_window_list_lock);
+ break;
+ default:
+ break;
+ }
+ if (ret && action != MEM_CANCEL_ONLINE)
+ return NOTIFY_BAD;
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block iommu_mem_nb = {
+ .notifier_call = iommu_mem_notifier,
+};
+
static int iommu_reconfig_notifier(struct notifier_block *nb, unsigned long action, void *node)
{
int err = NOTIFY_OK;
struct device_node *np = node;
struct pci_dn *pci = PCI_DN(np);
+ struct direct_window *window;
switch (action) {
case PSERIES_RECONFIG_REMOVE:
if (pci && pci->iommu_table)
iommu_free_table(pci->iommu_table, np->full_name);
+
+ spin_lock(&direct_window_list_lock);
+ list_for_each_entry(window, &direct_window_list, list) {
+ if (window->device == np) {
+ list_del(&window->list);
+ break;
+ }
+ }
+ spin_unlock(&direct_window_list_lock);
+
+ remove_ddw(np);
break;
default:
err = NOTIFY_DONE;
@@ -588,6 +1159,7 @@ void iommu_init_early_pSeries(void)
ppc_md.tce_get = tce_get_pSeriesLP;
ppc_md.pci_dma_bus_setup = pci_dma_bus_setup_pSeriesLP;
ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_pSeriesLP;
+ ppc_md.dma_set_mask = dma_set_mask_pSeriesLP;
} else {
ppc_md.tce_build = tce_build_pSeries;
ppc_md.tce_free = tce_free_pSeries;
@@ -598,6 +1170,7 @@ void iommu_init_early_pSeries(void)
pSeries_reconfig_notifier_register(&iommu_reconfig_nb);
+ register_memory_notifier(&iommu_mem_nb);
set_pci_dma_ops(&dma_iommu_ops);
}
--
1.7.1
^ permalink raw reply related
* [RFC PATCH 6/7 v2] ppc/iommu: pass phb only to iommu_table_setparms_lpar
From: Nishanth Aravamudan @ 2010-10-27 3:35 UTC (permalink / raw)
To: nacc; +Cc: sonnyrao, miltonm, Paul Mackerras, Anton Blanchard, linuxppc-dev
In-Reply-To: <1288150518-4026-1-git-send-email-nacc@us.ibm.com>
iommu_table_setparms_lpar needs either the phb or the subbusnumber
(not both), pass the phb to make it similar to iommu_table_setparms.
Note: In cases where a caller was passing bus->number previously to
iommu_table_setparms_lpar() rather than phb->bus->number, this can lead
to a different value in tbl->it_busno. The only example of this was the
removed pci_dma_dev_setup_pSeriesLP(), removed in "ppc/iommu: remove
unneeded pci_dma_dev_setup_pSeriesLP".
Signed-off-by: Milton Miller <miltonm@bga.com>
Signed-off-by: Nishanth Aravamudan <nacc@us.ibm.com>
---
arch/powerpc/platforms/pseries/iommu.c | 8 +++-----
1 files changed, 3 insertions(+), 5 deletions(-)
diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c
index 9d564b9..45c6865 100644
--- a/arch/powerpc/platforms/pseries/iommu.c
+++ b/arch/powerpc/platforms/pseries/iommu.c
@@ -323,14 +323,13 @@ static void iommu_table_setparms(struct pci_controller *phb,
static void iommu_table_setparms_lpar(struct pci_controller *phb,
struct device_node *dn,
struct iommu_table *tbl,
- const void *dma_window,
- int bussubno)
+ const void *dma_window)
{
unsigned long offset, size;
- tbl->it_busno = bussubno;
of_parse_dma_window(dn, dma_window, &tbl->it_index, &offset, &size);
+ tbl->it_busno = phb->bus->number;
tbl->it_base = 0;
tbl->it_blocksize = 16;
tbl->it_type = TCE_PCI;
@@ -534,8 +533,7 @@ static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev)
if (!pci->iommu_table) {
tbl = kzalloc_node(sizeof(struct iommu_table), GFP_KERNEL,
pci->phb->node);
- iommu_table_setparms_lpar(pci->phb, pdn, tbl, dma_window,
- pci->phb->bus->number);
+ iommu_table_setparms_lpar(pci->phb, pdn, tbl, dma_window);
pci->iommu_table = iommu_init_table(tbl, pci->phb->node);
pr_debug(" created table: %p\n", pci->iommu_table);
} else {
--
1.7.1
^ permalink raw reply related
* [RFC PATCH 4/7 v2] ppc: checking for pdn->parent is redundant
From: Nishanth Aravamudan @ 2010-10-27 3:35 UTC (permalink / raw)
To: nacc; +Cc: sonnyrao, miltonm, Paul Mackerras, Anton Blanchard, linuxppc-dev
In-Reply-To: <1288150518-4026-1-git-send-email-nacc@us.ibm.com>
The device tree root is never a pci bus, and will not have a
PCI_DN(pdn), so the check for PCI_DN added in
650f7b3b2f0ead0673e90452cf3dedde97c537ba makes the check for pdn->parent
redundant and it can be removed.
Signed-off-by: Milton Miller <miltonm@bga.com>
Signed-off-by: Nishanth Aravamudan <nacc@us.ibm.com>
---
arch/powerpc/platforms/pseries/iommu.c | 5 +----
1 files changed, 1 insertions(+), 4 deletions(-)
diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c
index 8ab32da..0ae5a60 100644
--- a/arch/powerpc/platforms/pseries/iommu.c
+++ b/arch/powerpc/platforms/pseries/iommu.c
@@ -530,10 +530,7 @@ static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev)
}
pr_debug(" parent is %s\n", pdn->full_name);
- /* Check for parent == NULL so we don't try to setup the empty EADS
- * slots on POWER4 machines.
- */
- if (dma_window == NULL || pdn->parent == NULL) {
+ if (dma_window == NULL) {
pr_debug(" no dma window for device, linking to parent\n");
set_iommu_table_base(&dev->dev, PCI_DN(pdn)->iommu_table);
return;
--
1.7.1
^ permalink raw reply related
* [RFC PATCH 5/7 v2] ppc/iommu: do not need to check for dma_window == NULL
From: Nishanth Aravamudan @ 2010-10-27 3:35 UTC (permalink / raw)
To: nacc; +Cc: sonnyrao, miltonm, Paul Mackerras, Anton Blanchard, linuxppc-dev
In-Reply-To: <1288150518-4026-1-git-send-email-nacc@us.ibm.com>
The block in pci_dma_dev_setup_pSeriesLP for dma_window == NULL can be
removed because we will only teminate the loop if we had already allocated
a iommu table for that node or we found a window. While there may be
no window for the device, the intresting part is if we are reusing a
table or creating it for the first device under it.
Signed-off-by: Milton Miller <miltonm@bga.com>
Signed-off-by: Nishanth Aravamudan <nacc@us.ibm.com>
---
arch/powerpc/platforms/pseries/iommu.c | 6 ------
1 files changed, 0 insertions(+), 6 deletions(-)
diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c
index 0ae5a60..9d564b9 100644
--- a/arch/powerpc/platforms/pseries/iommu.c
+++ b/arch/powerpc/platforms/pseries/iommu.c
@@ -530,12 +530,6 @@ static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev)
}
pr_debug(" parent is %s\n", pdn->full_name);
- if (dma_window == NULL) {
- pr_debug(" no dma window for device, linking to parent\n");
- set_iommu_table_base(&dev->dev, PCI_DN(pdn)->iommu_table);
- return;
- }
-
pci = PCI_DN(pdn);
if (!pci->iommu_table) {
tbl = kzalloc_node(sizeof(struct iommu_table), GFP_KERNEL,
--
1.7.1
^ permalink raw reply related
* [RFC PATCH 2/7 v2] ppc: add memory_hotplug_max
From: Nishanth Aravamudan @ 2010-10-27 3:35 UTC (permalink / raw)
To: nacc
Cc: sonnyrao, linuxppc-dev, miltonm, H Hartley Sweeten,
Paul Mackerras, Anton Blanchard, H. Peter Anvin, Yinghai Lu
In-Reply-To: <1288150518-4026-1-git-send-email-nacc@us.ibm.com>
Add a function to get the maximum address that can be hotplug added.
This is needed to calculate the size of the tce table needed to cover
all memory in 1:1 mode.
Signed-off-by: Milton Miller <miltonm@bga.com>
Signed-off-by: Nishanth Aravamudan <nacc@us.ibm.com>
---
Comments on where to export?
---
arch/powerpc/include/asm/mmzone.h | 5 +++++
arch/powerpc/mm/numa.c | 26 ++++++++++++++++++++++++++
2 files changed, 31 insertions(+), 0 deletions(-)
diff --git a/arch/powerpc/include/asm/mmzone.h b/arch/powerpc/include/asm/mmzone.h
index aac87cb..fd3fd58 100644
--- a/arch/powerpc/include/asm/mmzone.h
+++ b/arch/powerpc/include/asm/mmzone.h
@@ -33,6 +33,9 @@ extern int numa_cpu_lookup_table[];
extern cpumask_var_t node_to_cpumask_map[];
#ifdef CONFIG_MEMORY_HOTPLUG
extern unsigned long max_pfn;
+u64 memory_hotplug_max(void);
+#else
+#define memory_hotplug_max() memblock_end_of_DRAM()
#endif
/*
@@ -42,6 +45,8 @@ extern unsigned long max_pfn;
#define node_start_pfn(nid) (NODE_DATA(nid)->node_start_pfn)
#define node_end_pfn(nid) (NODE_DATA(nid)->node_end_pfn)
+#else
+#define memory_hotplug_max() memblock_end_of_DRAM()
#endif /* CONFIG_NEED_MULTIPLE_NODES */
#endif /* __KERNEL__ */
diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c
index 74505b2..8c0944c 100644
--- a/arch/powerpc/mm/numa.c
+++ b/arch/powerpc/mm/numa.c
@@ -1247,4 +1247,30 @@ int hot_add_scn_to_nid(unsigned long scn_addr)
return nid;
}
+static u64 hot_add_drconf_memory_max(void)
+{
+ struct device_node *memory = NULL;
+ unsigned int drconf_cell_cnt = 0;
+ u64 lmb_size = 0;
+ const u32 *dm = 0;
+
+ memory = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory");
+ if (memory) {
+ drconf_cell_cnt = of_get_drconf_memory(memory, &dm);
+ lmb_size = of_get_lmb_size(memory);
+ of_node_put(memory);
+ }
+ return lmb_size * drconf_cell_cnt;
+}
+
+/*
+ * memory_hotplug_max - return max address of memory that may be added
+ *
+ * This is currently only used on systems that support drconfig memory
+ * hotplug.
+ */
+u64 memory_hotplug_max(void)
+{
+ return max(hot_add_drconf_memory_max(), memblock_end_of_DRAM());
+}
#endif /* CONFIG_MEMORY_HOTPLUG */
--
1.7.1
^ permalink raw reply related
* [RFC PATCH 1/7 v2] macio: ensure all dma routines get copied over
From: Nishanth Aravamudan @ 2010-10-27 3:35 UTC (permalink / raw)
To: nacc; +Cc: sonnyrao, miltonm, Paul Mackerras, linuxppc-dev
In-Reply-To: <1288150518-4026-1-git-send-email-nacc@us.ibm.com>
Also add a comment to dev_archdata, indicating that changes there need
to be verified against the driver code.
Signed-off-by: Milton Miller <miltonm@bga.com>
Signed-off-by: Nishanth Aravamudan <nacc@us.ibm.com>
---
arch/powerpc/include/asm/device.h | 6 ++++++
drivers/macintosh/macio_asic.c | 7 +++----
2 files changed, 9 insertions(+), 4 deletions(-)
diff --git a/arch/powerpc/include/asm/device.h b/arch/powerpc/include/asm/device.h
index a3954e4..16d25c0 100644
--- a/arch/powerpc/include/asm/device.h
+++ b/arch/powerpc/include/asm/device.h
@@ -9,6 +9,12 @@
struct dma_map_ops;
struct device_node;
+/*
+ * Arch extensions to struct device.
+ *
+ * When adding fields, consider macio_add_one_device in
+ * drivers/macintosh/macio_asic.c
+ */
struct dev_archdata {
/* DMA operations on that device */
struct dma_map_ops *dma_ops;
diff --git a/drivers/macintosh/macio_asic.c b/drivers/macintosh/macio_asic.c
index b6e7ddc..4daf9e5 100644
--- a/drivers/macintosh/macio_asic.c
+++ b/drivers/macintosh/macio_asic.c
@@ -387,11 +387,10 @@ static struct macio_dev * macio_add_one_device(struct macio_chip *chip,
/* Set the DMA ops to the ones from the PCI device, this could be
* fishy if we didn't know that on PowerMac it's always direct ops
* or iommu ops that will work fine
+ *
+ * To get all the fields, copy all archdata
*/
- dev->ofdev.dev.archdata.dma_ops =
- chip->lbus.pdev->dev.archdata.dma_ops;
- dev->ofdev.dev.archdata.dma_data =
- chip->lbus.pdev->dev.archdata.dma_data;
+ dev->ofdev.dev.archdata = chip->lbus.pdev->dev.archdata;
#endif /* CONFIG_PCI */
#ifdef DEBUG
--
1.7.1
^ permalink raw reply related
* [RFC PATCH 3/7 v2] ppc: do not search for dma-window property on dlpar remove
From: Nishanth Aravamudan @ 2010-10-27 3:35 UTC (permalink / raw)
To: nacc; +Cc: sonnyrao, miltonm, Paul Mackerras, Anton Blanchard, linuxppc-dev
In-Reply-To: <1288150518-4026-1-git-send-email-nacc@us.ibm.com>
The iommu_table pointer in the pci auxiliary struct of device_node has
not been used by the iommu ops since the dma refactor of
12d04eef927bf61328af2c7cbe756c96f98ac3bf, however this code still uses
it to find tables for dlpar. By only setting the PCI_DN iommu_table
pointer on nodes with dma window properties, we will be able to quickly
find the node for later checks, and can remove the table without looking
for the the dma window property on dlpar remove.
Signed-off-by: Milton Miller <miltonm@bga.com>
Signed-off-by: Nishanth Aravamudan <nacc@us.ibm.com>
---
arch/powerpc/platforms/pseries/iommu.c | 6 +-----
1 files changed, 1 insertions(+), 5 deletions(-)
diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c
index 9184db3..8ab32da 100644
--- a/arch/powerpc/platforms/pseries/iommu.c
+++ b/arch/powerpc/platforms/pseries/iommu.c
@@ -455,9 +455,6 @@ static void pci_dma_bus_setup_pSeriesLP(struct pci_bus *bus)
ppci->iommu_table = iommu_init_table(tbl, ppci->phb->node);
pr_debug(" created table: %p\n", ppci->iommu_table);
}
-
- if (pdn != dn)
- PCI_DN(dn)->iommu_table = ppci->iommu_table;
}
@@ -571,8 +568,7 @@ static int iommu_reconfig_notifier(struct notifier_block *nb, unsigned long acti
switch (action) {
case PSERIES_RECONFIG_REMOVE:
- if (pci && pci->iommu_table &&
- of_get_property(np, "ibm,dma-window", NULL))
+ if (pci && pci->iommu_table)
iommu_free_table(pci->iommu_table, np->full_name);
break;
default:
--
1.7.1
^ permalink raw reply related
* [RFC PATCH 0/7 v2] ppc: enable dynamic dma window support
From: Nishanth Aravamudan @ 2010-10-27 3:35 UTC (permalink / raw)
To: nacc; +Cc: sonnyrao, miltonm, Paul Mackerras, linuxppc-dev
The following series, which builds upon the series of cleanups I posted
on 9/15 and 10/18 as "ppc iommu cleanups", enables the pseries firmware
feature dynamic dma windows. This feature will allow future devices to
have a 64-bit DMA mapping covering all memory, coexisting with a smaller
IOMMU window in 32-bit PCI space
Changes from v1 to v2:
Fixed numerous bugs/issues found in testing.
Reworked to be based off platform hook dma_set_mask().
Nishanth Aravamudan (7):
macio: ensure all dma routines get copied over
ppc: add memory_hotplug_max
ppc: do not search for dma-window property on dlpar remove
ppc: checking for pdn->parent is redundant
ppc/iommu: do not need to check for dma_window == NULL
ppc/iommu: pass phb only to iommu_table_setparms_lpar
ppc: add dynamic dma window support
arch/powerpc/include/asm/device.h | 6 +
arch/powerpc/include/asm/mmzone.h | 5 +
arch/powerpc/mm/numa.c | 26 ++
arch/powerpc/platforms/pseries/iommu.c | 600 ++++++++++++++++++++++++++++++--
drivers/macintosh/macio_asic.c | 7 +-
5 files changed, 619 insertions(+), 25 deletions(-)
^ permalink raw reply
* Re: [linux-2.6.36-git7: Power7] LTP Memory CGROUP Controller functional test creates Backtrace, OOMKill & rcu_sched_state detected stall jiffies
From: KAMEZAWA Hiroyuki @ 2010-10-27 0:45 UTC (permalink / raw)
To: subrata; +Cc: Linuxppc-dev, Kamalesh Babulal, Li Zefan, linux-kernel, ltp-list
In-Reply-To: <1288089237.5010.9.camel@subratamodak.linux.ibm.com>
On Tue, 26 Oct 2010 16:03:56 +0530
Subrata Modak <subrata@linux.vnet.ibm.com> wrote:
> If you run LTP Memory CGROUP Controller functional test on
> linux-2.6.36-git7, the following Backtrace, OOMKill & rcu_sched_state
> detected stall jiffies are created. The machine is not reachable
> thereafter. Ways to reproduce this problem:
>
> 1) Build and boot kernel 2.6.36-git7 on Power7 machine with attached
> config file,
> 2) Fetch, build and install LTP:
> git clone git://ltp.git.sourceforge.net/gitroot/ltp/ltp
> cd ltp
> ./configure
> make
> make install
> 3) Create a LTP runtest file /opt/ltp/runtest/memcg_function_test with
> the following entry:
> memcg_function memcg_function_test.sh
> <<EOF>>
> cd /opt/ltp
> ./runltp -f memcg_function_test
>
IIUC, memcg test includes intentional OOM-Kill test by setting the limit to 0.
And it has another test to set the limit to PAGE_SIZE.
In your environemnt, I think page size is 64kb...right ?
About rcu_sched_state()....I have no idea at this stage. I reviewed memcontrol.c
and oom_kill.c again and coundn't found anything in quick review.
Could you try again after -rc1 shipped ?
I think Andrew Morton sent some amount of updates for oom_kill and memcg, vmscan
to Linus, today.
Thanks,
-Kame
^ permalink raw reply
* [REPOST][PATCH] mpc8308: fix USB DR controller initialization
From: Ilya Yanok @ 2010-10-27 0:02 UTC (permalink / raw)
To: linuxppc-dev, galak, kim.phillips, wd, dzu, vlad; +Cc: Ilya Yanok
In-Reply-To: <1282906641-25351-1-git-send-email-yanok@emcraft.com>
MPC8308 has ULPI pin muxing settings in SICRH register, bits 17-18
which is different from both MPC8313 and MPC8315.
Also MPC8308 doesn't have REFSEL, UTMI_PHY_EN and OTG_PORT fields
in the USB DR controller CONTROL register.
Signed-off-by: Ilya Yanok <yanok@emcraft.com>
---
Kim, Kumar,
Please consider including this patch. Without it USB initialization code
writes to the wrong bits on the MPC8308RDB.
Regards, Ilya.
arch/powerpc/boot/dts/mpc8308rdb.dts | 2 +-
arch/powerpc/platforms/83xx/mpc83xx.h | 2 ++
arch/powerpc/platforms/83xx/usb.c | 21 ++++++++++++++++-----
3 files changed, 19 insertions(+), 6 deletions(-)
diff --git a/arch/powerpc/boot/dts/mpc8308rdb.dts b/arch/powerpc/boot/dts/mpc8308rdb.dts
index a97eb2d..1e2b888 100644
--- a/arch/powerpc/boot/dts/mpc8308rdb.dts
+++ b/arch/powerpc/boot/dts/mpc8308rdb.dts
@@ -109,7 +109,7 @@
#address-cells = <1>;
#size-cells = <1>;
device_type = "soc";
- compatible = "fsl,mpc8315-immr", "simple-bus";
+ compatible = "fsl,mpc8308-immr", "simple-bus";
ranges = <0 0xe0000000 0x00100000>;
reg = <0xe0000000 0x00000200>;
bus-frequency = <0>;
diff --git a/arch/powerpc/platforms/83xx/mpc83xx.h b/arch/powerpc/platforms/83xx/mpc83xx.h
index 0fea881..82a4345 100644
--- a/arch/powerpc/platforms/83xx/mpc83xx.h
+++ b/arch/powerpc/platforms/83xx/mpc83xx.h
@@ -35,6 +35,8 @@
/* system i/o configuration register high */
#define MPC83XX_SICRH_OFFS 0x118
+#define MPC8308_SICRH_USB_MASK 0x000c0000
+#define MPC8308_SICRH_USB_ULPI 0x00040000
#define MPC834X_SICRH_USB_UTMI 0x00020000
#define MPC831X_SICRH_USB_MASK 0x000000e0
#define MPC831X_SICRH_USB_ULPI 0x000000a0
diff --git a/arch/powerpc/platforms/83xx/usb.c b/arch/powerpc/platforms/83xx/usb.c
index 3ba4bb7..2c64164 100644
--- a/arch/powerpc/platforms/83xx/usb.c
+++ b/arch/powerpc/platforms/83xx/usb.c
@@ -127,7 +127,8 @@ int mpc831x_usb_cfg(void)
/* Configure clock */
immr_node = of_get_parent(np);
- if (immr_node && of_device_is_compatible(immr_node, "fsl,mpc8315-immr"))
+ if (immr_node && (of_device_is_compatible(immr_node, "fsl,mpc8315-immr") ||
+ of_device_is_compatible(immr_node, "fsl,mpc8308-immr")))
clrsetbits_be32(immap + MPC83XX_SCCR_OFFS,
MPC8315_SCCR_USB_MASK,
MPC8315_SCCR_USB_DRCM_01);
@@ -138,7 +139,11 @@ int mpc831x_usb_cfg(void)
/* Configure pin mux for ULPI. There is no pin mux for UTMI */
if (prop && !strcmp(prop, "ulpi")) {
- if (of_device_is_compatible(immr_node, "fsl,mpc8315-immr")) {
+ if (of_device_is_compatible(immr_node, "fsl,mpc8308-immr")) {
+ clrsetbits_be32(immap + MPC83XX_SICRH_OFFS,
+ MPC8308_SICRH_USB_MASK,
+ MPC8308_SICRH_USB_ULPI);
+ } else if (of_device_is_compatible(immr_node, "fsl,mpc8315-immr")) {
clrsetbits_be32(immap + MPC83XX_SICRL_OFFS,
MPC8315_SICRL_USB_MASK,
MPC8315_SICRL_USB_ULPI);
@@ -173,6 +178,9 @@ int mpc831x_usb_cfg(void)
!strcmp(prop, "utmi"))) {
u32 refsel;
+ if (of_device_is_compatible(immr_node, "fsl,mpc8308-immr"))
+ goto out;
+
if (of_device_is_compatible(immr_node, "fsl,mpc8315-immr"))
refsel = CONTROL_REFSEL_24MHZ;
else
@@ -186,9 +194,11 @@ int mpc831x_usb_cfg(void)
temp = CONTROL_PHY_CLK_SEL_ULPI;
#ifdef CONFIG_USB_OTG
/* Set OTG_PORT */
- dr_mode = of_get_property(np, "dr_mode", NULL);
- if (dr_mode && !strcmp(dr_mode, "otg"))
- temp |= CONTROL_OTG_PORT;
+ if (!of_device_is_compatible(immr_node, "fsl,mpc8308-immr")) {
+ dr_mode = of_get_property(np, "dr_mode", NULL);
+ if (dr_mode && !strcmp(dr_mode, "otg"))
+ temp |= CONTROL_OTG_PORT;
+ }
#endif /* CONFIG_USB_OTG */
out_be32(usb_regs + FSL_USB2_CONTROL_OFFS, temp);
} else {
@@ -196,6 +206,7 @@ int mpc831x_usb_cfg(void)
ret = -EINVAL;
}
+out:
iounmap(usb_regs);
of_node_put(np);
return ret;
--
1.7.2.3
^ permalink raw reply related
* [PATCH 4/6] mpc512x_dma: try to free descriptors in case of allocation failure
From: Ilya Yanok @ 2010-10-26 23:52 UTC (permalink / raw)
To: linuxppc-dev, wd, dzu, vlad; +Cc: Piotr Ziecik, Ilya Yanok
In-Reply-To: <1285676696-5358-1-git-send-email-yanok@emcraft.com>
Currently completed descriptors are processed in the tasklet. This can
lead to dead lock in case of CONFIG_NET_DMA enabled (new requests are
submitted from softirq context and dma_memcpy_to_iovec() busy loops until
the requests is submitted). To prevent this we should process completed
descriptors from the allocation failure path in prepare_memcpy too.
Signed-off-by: Ilya Yanok <yanok@emcraft.com>
Cc: Piotr Ziecik <kosmo@semihalf.com>
---
drivers/dma/mpc512x_dma.c | 79 +++++++++++++++++++++++++-------------------
1 files changed, 45 insertions(+), 34 deletions(-)
diff --git a/drivers/dma/mpc512x_dma.c b/drivers/dma/mpc512x_dma.c
index 97b92ec..59c2701 100644
--- a/drivers/dma/mpc512x_dma.c
+++ b/drivers/dma/mpc512x_dma.c
@@ -328,19 +328,55 @@ static irqreturn_t mpc_dma_irq(int irq, void *data)
return IRQ_HANDLED;
}
-/* DMA Tasklet */
-static void mpc_dma_tasklet(unsigned long data)
+/* proccess completed descriptors */
+static void mpc_dma_process_completed(struct mpc_dma *mdma)
{
- struct mpc_dma *mdma = (void *)data;
dma_cookie_t last_cookie = 0;
struct mpc_dma_chan *mchan;
struct mpc_dma_desc *mdesc;
struct dma_async_tx_descriptor *desc;
unsigned long flags;
LIST_HEAD(list);
- uint es;
int i;
+ for (i = 0; i < mdma->dma.chancnt; i++) {
+ mchan = &mdma->channels[i];
+
+ /* Get all completed descriptors */
+ spin_lock_irqsave(&mchan->lock, flags);
+ if (!list_empty(&mchan->completed))
+ list_splice_tail_init(&mchan->completed, &list);
+ spin_unlock_irqrestore(&mchan->lock, flags);
+
+ if (list_empty(&list))
+ continue;
+
+ /* Execute callbacks and run dependencies */
+ list_for_each_entry(mdesc, &list, node) {
+ desc = &mdesc->desc;
+
+ if (desc->callback)
+ desc->callback(desc->callback_param);
+
+ last_cookie = desc->cookie;
+ dma_run_dependencies(desc);
+ }
+
+ /* Free descriptors */
+ spin_lock_irqsave(&mchan->lock, flags);
+ list_splice_tail_init(&list, &mchan->free);
+ mchan->completed_cookie = last_cookie;
+ spin_unlock_irqrestore(&mchan->lock, flags);
+ }
+}
+
+/* DMA Tasklet */
+static void mpc_dma_tasklet(unsigned long data)
+{
+ struct mpc_dma *mdma = (void *)data;
+ unsigned long flags;
+ uint es;
+
spin_lock_irqsave(&mdma->error_status_lock, flags);
es = mdma->error_status;
mdma->error_status = 0;
@@ -379,35 +415,7 @@ static void mpc_dma_tasklet(unsigned long data)
dev_err(mdma->dma.dev, "- Destination Bus Error\n");
}
- for (i = 0; i < mdma->dma.chancnt; i++) {
- mchan = &mdma->channels[i];
-
- /* Get all completed descriptors */
- spin_lock_irqsave(&mchan->lock, flags);
- if (!list_empty(&mchan->completed))
- list_splice_tail_init(&mchan->completed, &list);
- spin_unlock_irqrestore(&mchan->lock, flags);
-
- if (list_empty(&list))
- continue;
-
- /* Execute callbacks and run dependencies */
- list_for_each_entry(mdesc, &list, node) {
- desc = &mdesc->desc;
-
- if (desc->callback)
- desc->callback(desc->callback_param);
-
- last_cookie = desc->cookie;
- dma_run_dependencies(desc);
- }
-
- /* Free descriptors */
- spin_lock_irqsave(&mchan->lock, flags);
- list_splice_tail_init(&list, &mchan->free);
- mchan->completed_cookie = last_cookie;
- spin_unlock_irqrestore(&mchan->lock, flags);
- }
+ mpc_dma_process_completed(mdma);
}
/* Submit descriptor to hardware */
@@ -587,8 +595,11 @@ mpc_dma_prep_memcpy(struct dma_chan *chan, dma_addr_t dst, dma_addr_t src,
}
spin_unlock_irqrestore(&mchan->lock, iflags);
- if (!mdesc)
+ if (!mdesc) {
+ /* try to free completed descriptors */
+ mpc_dma_process_completed(mdma);
return NULL;
+ }
mdesc->error = 0;
tcd = mdesc->tcd;
--
1.7.2.3
^ permalink raw reply related
* [PATCH 2/6] mpc512x_dma: fix the hanged transfer issue
From: Ilya Yanok @ 2010-10-26 23:52 UTC (permalink / raw)
To: linuxppc-dev, wd, dzu, vlad; +Cc: Piotr Ziecik, Ilya Yanok
In-Reply-To: <1285676696-5358-1-git-send-email-yanok@emcraft.com>
Current code clears interrupt active status _after_ submiting new
transfers. This leaves a possibility of clearing the interrupt for this
new transfer (if it is triggered fast enough) and thus lose this
interrupt. We want to clear interrupt active status _before_ new
transfers is submited and for current channel only.
Signed-off-by: Ilya Yanok <yanok@emcraft.com>
Cc: Piotr Ziecik <kosmo@semihalf.com>
---
drivers/dma/mpc512x_dma.c | 9 +++------
1 files changed, 3 insertions(+), 6 deletions(-)
diff --git a/drivers/dma/mpc512x_dma.c b/drivers/dma/mpc512x_dma.c
index 1bc04aa..0717527 100644
--- a/drivers/dma/mpc512x_dma.c
+++ b/drivers/dma/mpc512x_dma.c
@@ -276,6 +276,9 @@ static void mpc_dma_irq_process(struct mpc_dma *mdma, u32 is, u32 es, int off)
spin_lock(&mchan->lock);
+ out_8(&mdma->regs->dmacint, ch + off);
+ out_8(&mdma->regs->dmacerr, ch + off);
+
/* Check error status */
if (es & (1 << ch))
list_for_each_entry(mdesc, &mchan->active, node)
@@ -309,12 +312,6 @@ static irqreturn_t mpc_dma_irq(int irq, void *data)
mpc_dma_irq_process(mdma, in_be32(&mdma->regs->dmaintl),
in_be32(&mdma->regs->dmaerrl), 0);
- /* Ack interrupt on all channels */
- out_be32(&mdma->regs->dmainth, 0xFFFFFFFF);
- out_be32(&mdma->regs->dmaintl, 0xFFFFFFFF);
- out_be32(&mdma->regs->dmaerrh, 0xFFFFFFFF);
- out_be32(&mdma->regs->dmaerrl, 0xFFFFFFFF);
-
/* Schedule tasklet */
tasklet_schedule(&mdma->tasklet);
--
1.7.2.3
^ permalink raw reply related
* [REPOST] [PATCH 0/6] fixes and MPC8308 support for the mpc512x_dma driver
From: Ilya Yanok @ 2010-10-26 23:52 UTC (permalink / raw)
To: linuxppc-dev, wd, dzu, vlad; +Cc: Piotr Ziecik, Ilya Yanok
In-Reply-To: <1285676696-5358-1-git-send-email-yanok@emcraft.com>
Hello everybody,
meanwhile I've fixed one more issue in mpc512x_dma driver.
Any comments? Anybody interrested in this driver? Piotr?
Still unsure how to deal with bitfield structures in IO space...
Regards, Ilya.
Signed-off-by: Ilya Yanok <yanok@emcraft.com>
Cc: Piotr Ziecik <kosmo@semihalf.com>
^ permalink raw reply
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