* Re: [PATCH][RFC] fsldma: fix performance degradation by optimizing spinlock use.
From: Ira W. Snyder @ 2011-12-02 17:13 UTC (permalink / raw)
To: Shi Xuelin-B29237
Cc: vinod.koul@intel.com, dan.j.williams@intel.com,
linuxppc-dev@lists.ozlabs.org, linux-kernel@vger.kernel.org,
Li Yang-R58472
In-Reply-To: <DBB740589CE8814680DECFE34BE197AB14BCBC@039-SN1MPN1-006.039d.mgd.msft.net>
On Fri, Dec 02, 2011 at 03:47:27AM +0000, Shi Xuelin-B29237 wrote:
> Hi Iris,
>
> >I'm convinced that "smp_rmb()" is needed when removing the spinlock. As noted, Documentation/memory-barriers.txt says that stores on one CPU can be
> >observed by another CPU in a different order.
> >Previously, there was an UNLOCK (in fsl_dma_tx_submit) followed by a LOCK (in fsl_tx_status). This provided a "full barrier", forcing the operations to
> >complete correctly when viewed by the second CPU.
>
> I do not agree this smp_rmb() works here. Because when this smp_rmb() executed and begin to read chan->common.cookie, you still cannot avoid the order issue. Something like one is reading old value, but another CPU is updating the new value.
>
> My point is here the order is not important for the DMA decision.
> Completed DMA tx is decided as not complete is not a big deal, because next time it will be OK.
>
> I believe there is no case that could cause uncompleted DMA tx is decided as completed, because the fsl_tx_status is called after fsl_dma_tx_submit for a specific cookie. If you can give me an example here, I will agree with you.
>
According to memory-barriers.txt, writes to main memory may be observed in
any order if memory barriers are not used. This means that writes can
appear to happen in a different order than they were issued by the CPU.
Citing from the text:
> There are certain things that the Linux kernel memory barriers do not guarantee:
>
> (*) There is no guarantee that any of the memory accesses specified before a
> memory barrier will be _complete_ by the completion of a memory barrier
> instruction; the barrier can be considered to draw a line in that CPU's
> access queue that accesses of the appropriate type may not cross.
Also:
> Without intervention, CPU 2 may perceive the events on CPU 1 in some
> effectively random order, despite the write barrier issued by CPU 1:
Also:
> When dealing with CPU-CPU interactions, certain types of memory barrier should
> always be paired. A lack of appropriate pairing is almost certainly an error.
>
> A write barrier should always be paired with a data dependency barrier or read
> barrier, though a general barrier would also be viable.
Therefore, in an SMP system, the following situation can happen.
descriptor->cookie = 2
chan->common.cookie = 1
chan->completed_cookie = 1
This occurs when CPU-A calls fsl_dma_tx_submit() and then CPU-B calls
dma_async_is_complete() ***after*** CPU-B has observed the write to
descriptor->cookie, and ***before*** before CPU-B has observed the write to
chan->common.cookie.
Remember, without barriers, CPU-B can observe CPU-A's memory accesses in
*any possible order*. Memory accesses are not guaranteed to be *complete*
by the time fsl_dma_tx_submit() returns!
With the above values, dma_async_is_complete() returns DMA_COMPLETE. This
is incorrect: the DMA is still in progress. The required invariant
chan->common.cookie >= descriptor->cookie has not been met.
By adding an smp_rmb(), I force CPU-B to stall until *both* stores in
fsl_dma_tx_submit() (descriptor->cookie and chan->common.cookie) actually
hit main memory. This avoids the above situation: all CPU's observe
descriptor->cookie and chan->common.cookie to update in sync with each
other.
Is this unclear in any way?
Please run your test with the smp_rmb() and measure the performance
impact.
Ira
^ permalink raw reply
* Re: [PATCH 3/3] 8250: add workaround for MPC8[356]xx UART break IRQ storm
From: Scott Wood @ 2011-12-02 17:27 UTC (permalink / raw)
To: Paul Gortmaker
Cc: gregkh, linux-kernel, linux-serial, linuxppc-dev, Alan Cox, alan
In-Reply-To: <4ED8FE14.7020007@windriver.com>
On 12/02/2011 10:34 AM, Paul Gortmaker wrote:
> On 11-12-02 06:30 AM, Alan Cox wrote:
>>>> OK, I'll simply change the above to CONFIG_PPC then.
>>>
>>> It does, the bug is in the uart IP which I don't think we ever plan on fixing, so 32 or 64-bit parts will have it for ever and ever ;)
>>
>> It should be runtime selected, there should be no ifdefs here.
>
> The ifdef wasn't strictly required; it just made it so gcc would
> toss the errata code out of the irq handler for !PPC. Anyway it
> will be a moot point if I can somehow hide all the mess by snooping
> serial_inp() traffic and deploying the errata fix from there....
Eww.
If it's not to be allowed in the main 8250 code (even for ppc builds
only), a custom handle_port sounds like a saner option.
-Scott
^ permalink raw reply
* Re: [PATCH 2/8] 44x/pci: Add a want_sdr flag into ppc4xx_pciex_hwops
From: Benjamin Herrenschmidt @ 2011-12-02 20:57 UTC (permalink / raw)
To: Tony Breeds; +Cc: LinuxPPC-dev
In-Reply-To: <1322725164-4391-3-git-send-email-tony@bakeyournoodle.com>
On Thu, 2011-12-01 at 18:39 +1100, Tony Breeds wrote:
> + if (ppc4xx_pciex_hwops->want_sdr == true) {
if (ppc4xx_pciex_hwops->want_sdr) {
Please ! This is a boolean after all :-)
Cheers,
Ben.
^ permalink raw reply
* Re: [PATCH 7/8] 44x/476fpe: Add 476fpe SoC code
From: Benjamin Herrenschmidt @ 2011-12-02 20:58 UTC (permalink / raw)
To: Tony Breeds; +Cc: LinuxPPC-dev
In-Reply-To: <1322725164-4391-8-git-send-email-tony@bakeyournoodle.com>
On Thu, 2011-12-01 at 18:39 +1100, Tony Breeds wrote:
> Based on original work by David 'Shaggy' Kliekamp.
Typo in Shaggy's last name :-)
Cheers,
Ben.
^ permalink raw reply
* [PATCH 1/2] powerpc/85xx: fix localbus and PCI addresses in the P1022DS 36-bit device tree
From: Timur Tabi @ 2011-12-02 22:08 UTC (permalink / raw)
To: kumar.gala, linuxppc-dev
Fix the PCI buses in the 36-bit device tree for the P1022DS. It was using
values copy-pasted from another device tree.
Also fix the NAND localbus bus address from ffa00000 to ff800000, which is
what U-boot sets it to.
Signed-off-by: Timur Tabi <timur@freescale.com>
---
arch/powerpc/boot/dts/p1022ds.dts | 8 ++++----
1 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/arch/powerpc/boot/dts/p1022ds.dts b/arch/powerpc/boot/dts/p1022ds.dts
index 3e85d8c..a54dd13 100644
--- a/arch/powerpc/boot/dts/p1022ds.dts
+++ b/arch/powerpc/boot/dts/p1022ds.dts
@@ -21,7 +21,7 @@
reg = <0xf 0xffe05000 0 0x1000>;
ranges = <0x0 0x0 0xf 0xe8000000 0x08000000
0x1 0x0 0xf 0xe0000000 0x08000000
- 0x2 0x0 0xf 0xffa00000 0x00040000
+ 0x2 0x0 0xf 0xff800000 0x00040000
0x3 0x0 0xf 0xffdf0000 0x00008000>;
/*
@@ -222,7 +222,7 @@
pci0: pcie@fffe09000 {
reg = <0xf 0xffe09000 0 0x1000>;
- ranges = <0x2000000 0x0 0xa0000000 0xc 0x20000000 0x0 0x20000000
+ ranges = <0x2000000 0x0 0xe0000000 0xc 0x20000000 0x0 0x20000000
0x1000000 0x0 0x00000000 0xf 0xffc10000 0x0 0x10000>;
pcie@0 {
ranges = <0x2000000 0x0 0xe0000000
@@ -237,7 +237,7 @@
pci1: pcie@fffe0a000 {
reg = <0xf 0xffe0a000 0 0x1000>;
- ranges = <0x2000000 0x0 0xc0000000 0xc 0x40000000 0x0 0x20000000
+ ranges = <0x2000000 0x0 0xe0000000 0xc 0x40000000 0x0 0x20000000
0x1000000 0x0 0x00000000 0xf 0xffc20000 0x0 0x10000>;
pcie@0 {
reg = <0x0 0x0 0x0 0x0 0x0>;
@@ -253,7 +253,7 @@
pci2: pcie@fffe0b000 {
reg = <0xf 0xffe0b000 0 0x1000>;
- ranges = <0x2000000 0x0 0x80000000 0xc 0x00000000 0x0 0x20000000
+ ranges = <0x2000000 0x0 0xe0000000 0xc 0x00000000 0x0 0x20000000
0x1000000 0x0 0x00000000 0xf 0xffc00000 0x0 0x10000>;
pcie@0 {
ranges = <0x2000000 0x0 0xe0000000
--
1.7.3.4
^ permalink raw reply related
* [PATCH 2/2] powerpc/85xx: add a 32-bit P1022DS device tree
From: Timur Tabi @ 2011-12-02 22:08 UTC (permalink / raw)
To: kumar.gala, linuxppc-dev
In-Reply-To: <1322863714-6818-1-git-send-email-timur@freescale.com>
Add a 32-bit version of the device tree for the Freescale P1022DS reference
board.
Signed-off-by: Timur Tabi <timur@freescale.com>
---
arch/powerpc/boot/dts/p1022ds_32b.dts | 270 +++++++++++++++++++++++++++++++++
1 files changed, 270 insertions(+), 0 deletions(-)
create mode 100644 arch/powerpc/boot/dts/p1022ds_32b.dts
diff --git a/arch/powerpc/boot/dts/p1022ds_32b.dts b/arch/powerpc/boot/dts/p1022ds_32b.dts
new file mode 100644
index 0000000..18787d9
--- /dev/null
+++ b/arch/powerpc/boot/dts/p1022ds_32b.dts
@@ -0,0 +1,270 @@
+/*
+ * P1022 DS 32-Bit Physical Address Map Device Tree Source
+ *
+ * Copyright 2011 Freescale Semiconductor, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+/include/ "fsl/p1022si-pre.dtsi"
+/ {
+ model = "fsl,P1022DS";
+ compatible = "fsl,P1022DS";
+
+ memory {
+ device_type = "memory";
+ };
+
+ lbc: localbus@ffe05000 {
+ reg = <0x0 0xffe05000 0 0x1000>;
+ ranges = <0x0 0x0 0x0 0xe8000000 0x08000000
+ 0x1 0x0 0x0 0xe0000000 0x08000000
+ 0x2 0x0 0x0 0xff800000 0x00040000
+ 0x3 0x0 0x0 0xffdf0000 0x00008000>;
+
+ /*
+ * This node is used to access the pixis via "indirect" mode,
+ * which is done by writing the pixis register index to chip
+ * select 0 and the value to/from chip select 1. Indirect
+ * mode is the only way to access the pixis when DIU video
+ * is enabled. Note that this assumes that the first column
+ * of the 'ranges' property above is the chip select number.
+ */
+ board-control@0,0 {
+ compatible = "fsl,p1022ds-indirect-pixis";
+ reg = <0x0 0x0 1 /* CS0 */
+ 0x1 0x0 1>; /* CS1 */
+ };
+
+ nor@0,0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "cfi-flash";
+ reg = <0x0 0x0 0x8000000>;
+ bank-width = <2>;
+ device-width = <1>;
+
+ partition@0 {
+ reg = <0x0 0x03000000>;
+ label = "ramdisk-nor";
+ read-only;
+ };
+
+ partition@3000000 {
+ reg = <0x03000000 0x00e00000>;
+ label = "diagnostic-nor";
+ read-only;
+ };
+
+ partition@3e00000 {
+ reg = <0x03e00000 0x00200000>;
+ label = "dink-nor";
+ read-only;
+ };
+
+ partition@4000000 {
+ reg = <0x04000000 0x00400000>;
+ label = "kernel-nor";
+ read-only;
+ };
+
+ partition@4400000 {
+ reg = <0x04400000 0x03b00000>;
+ label = "jffs2-nor";
+ };
+
+ partition@7f00000 {
+ reg = <0x07f00000 0x00080000>;
+ label = "dtb-nor";
+ read-only;
+ };
+
+ partition@7f80000 {
+ reg = <0x07f80000 0x00080000>;
+ label = "u-boot-nor";
+ read-only;
+ };
+ };
+
+ nand@2,0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "fsl,elbc-fcm-nand";
+ reg = <0x2 0x0 0x40000>;
+
+ partition@0 {
+ reg = <0x0 0x02000000>;
+ label = "u-boot-nand";
+ read-only;
+ };
+
+ partition@2000000 {
+ reg = <0x02000000 0x10000000>;
+ label = "jffs2-nand";
+ };
+
+ partition@12000000 {
+ reg = <0x12000000 0x10000000>;
+ label = "ramdisk-nand";
+ read-only;
+ };
+
+ partition@22000000 {
+ reg = <0x22000000 0x04000000>;
+ label = "kernel-nand";
+ };
+
+ partition@26000000 {
+ reg = <0x26000000 0x01000000>;
+ label = "dtb-nand";
+ read-only;
+ };
+
+ partition@27000000 {
+ reg = <0x27000000 0x19000000>;
+ label = "reserved-nand";
+ };
+ };
+
+ board-control@3,0 {
+ compatible = "fsl,p1022ds-fpga", "fsl,fpga-ngpixis";
+ reg = <3 0 0x30>;
+ interrupt-parent = <&mpic>;
+ /*
+ * IRQ8 is generated if the "EVENT" switch is pressed
+ * and PX_CTL[EVESEL] is set to 00.
+ */
+ interrupts = <8 8 0 0>;
+ };
+ };
+
+ soc: soc@ffe00000 {
+ ranges = <0x0 0x0 0xffe00000 0x100000>;
+
+ i2c@3100 {
+ wm8776:codec@1a {
+ compatible = "wlf,wm8776";
+ reg = <0x1a>;
+ /*
+ * clock-frequency will be set by U-Boot if
+ * the clock is enabled.
+ */
+ };
+ };
+
+ spi@7000 {
+ flash@0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "spansion,s25sl12801";
+ reg = <0>;
+ spi-max-frequency = <40000000>; /* input clock */
+
+ partition@0 {
+ label = "u-boot-spi";
+ reg = <0x00000000 0x00100000>;
+ read-only;
+ };
+ partition@100000 {
+ label = "kernel-spi";
+ reg = <0x00100000 0x00500000>;
+ read-only;
+ };
+ partition@600000 {
+ label = "dtb-spi";
+ reg = <0x00600000 0x00100000>;
+ read-only;
+ };
+ partition@700000 {
+ label = "file system-spi";
+ reg = <0x00700000 0x00900000>;
+ };
+ };
+ };
+
+ ssi@15000 {
+ fsl,mode = "i2s-slave";
+ codec-handle = <&wm8776>;
+ fsl,ssi-asynchronous;
+ };
+
+ usb@22000 {
+ phy_type = "ulpi";
+ };
+
+ usb@23000 {
+ status = "disabled";
+ };
+
+ mdio@24000 {
+ phy0: ethernet-phy@0 {
+ interrupts = <3 1 0 0>;
+ reg = <0x1>;
+ };
+ phy1: ethernet-phy@1 {
+ interrupts = <9 1 0 0>;
+ reg = <0x2>;
+ };
+ };
+
+ ethernet@b0000 {
+ phy-handle = <&phy0>;
+ phy-connection-type = "rgmii-id";
+ };
+
+ ethernet@b1000 {
+ phy-handle = <&phy1>;
+ phy-connection-type = "rgmii-id";
+ };
+ };
+
+ pci0: pcie@ffe09000 {
+ reg = <0x0 0xffe09000 0 0x1000>;
+ ranges = <0x2000000 0x0 0xe0000000 0 0xa0000000 0x0 0x20000000
+ 0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>;
+ pcie@0 {
+ ranges = <0x2000000 0x0 0xe0000000
+ 0x2000000 0x0 0xe0000000
+ 0x0 0x20000000
+
+ 0x1000000 0x0 0x0
+ 0x1000000 0x0 0x0
+ 0x0 0x100000>;
+ };
+ };
+
+ pci1: pcie@ffe0a000 {
+ reg = <0 0xffe0a000 0 0x1000>;
+ ranges = <0x2000000 0x0 0xe0000000 0 0xc0000000 0x0 0x20000000
+ 0x1000000 0x0 0x00000000 0 0xffc20000 0x0 0x10000>;
+ pcie@0 {
+ reg = <0x0 0x0 0x0 0x0 0x0>;
+ ranges = <0x2000000 0x0 0xe0000000
+ 0x2000000 0x0 0xe0000000
+ 0x0 0x20000000
+
+ 0x1000000 0x0 0x0
+ 0x1000000 0x0 0x0
+ 0x0 0x100000>;
+ };
+ };
+
+ pci2: pcie@ffe0b000 {
+ reg = <0 0xffe0b000 0 0x1000>;
+ ranges = <0x2000000 0x0 0xe0000000 0 0x80000000 0x0 0x20000000
+ 0x1000000 0x0 0x00000000 0 0xffc00000 0x0 0x10000>;
+ pcie@0 {
+ ranges = <0x2000000 0x0 0xe0000000
+ 0x2000000 0x0 0xe0000000
+ 0x0 0x20000000
+
+ 0x1000000 0x0 0x0
+ 0x1000000 0x0 0x0
+ 0x0 0x100000>;
+ };
+ };
+};
+
+/include/ "fsl/p1022si-post.dtsi"
--
1.7.3.4
^ permalink raw reply related
* Re: [PATCH 2/2] powerpc/85xx: add a 32-bit P1022DS device tree
From: Scott Wood @ 2011-12-02 22:19 UTC (permalink / raw)
To: Timur Tabi; +Cc: linuxppc-dev, kumar.gala
In-Reply-To: <1322863714-6818-2-git-send-email-timur@freescale.com>
On 12/02/2011 04:08 PM, Timur Tabi wrote:
> + lbc: localbus@ffe05000 {
> + reg = <0x0 0xffe05000 0 0x1000>;
> + ranges = <0x0 0x0 0x0 0xe8000000 0x08000000
> + 0x1 0x0 0x0 0xe0000000 0x08000000
> + 0x2 0x0 0x0 0xff800000 0x00040000
> + 0x3 0x0 0x0 0xffdf0000 0x00008000>;
> +
> + /*
> + * This node is used to access the pixis via "indirect" mode,
> + * which is done by writing the pixis register index to chip
> + * select 0 and the value to/from chip select 1. Indirect
> + * mode is the only way to access the pixis when DIU video
> + * is enabled. Note that this assumes that the first column
> + * of the 'ranges' property above is the chip select number.
> + */
> + board-control@0,0 {
> + compatible = "fsl,p1022ds-indirect-pixis";
> + reg = <0x0 0x0 1 /* CS0 */
> + 0x1 0x0 1>; /* CS1 */
> + };
> +
> + nor@0,0 {
> + #address-cells = <1>;
> + #size-cells = <1>;
> + compatible = "cfi-flash";
> + reg = <0x0 0x0 0x8000000>;
> + bank-width = <2>;
> + device-width = <1>;
[snip]
> + };
> +
> + nand@2,0 {
> + #address-cells = <1>;
> + #size-cells = <1>;
> + compatible = "fsl,elbc-fcm-nand";
> + reg = <0x2 0x0 0x40000>;
[snip]
> + };
> + };
> +
> + board-control@3,0 {
> + compatible = "fsl,p1022ds-fpga", "fsl,fpga-ngpixis";
> + reg = <3 0 0x30>;
> + interrupt-parent = <&mpic>;
> + /*
> + * IRQ8 is generated if the "EVENT" switch is pressed
> + * and PX_CTL[EVESEL] is set to 00.
> + */
> + interrupts = <8 8 0 0>;
> + };
> + };
[snip]
> +/include/ "fsl/p1022si-post.dtsi"
Please add something after post to strip simple-bus off of the localbus
node's compatible. Either you have board-control@0,0, or you have the
other stuff (did you ever find out what the situation with NAND is?) --
not both at the same time. Or do you have U-Boot patching in status
updates now?
I realize this isn't a 32-bit versus 36-bit issue, but this seemed as
good a time as any to repeat this complaint. :-)
-Scott
^ permalink raw reply
* Re: [PATCH 2/2] powerpc/85xx: add a 32-bit P1022DS device tree
From: Timur Tabi @ 2011-12-02 22:24 UTC (permalink / raw)
To: Scott Wood; +Cc: linuxppc-dev, kumar.gala
In-Reply-To: <4ED94EF5.2090406@freescale.com>
Scott Wood wrote:
> Please add something after post to strip simple-bus off of the localbus
> node's compatible. Either you have board-control@0,0, or you have the
> other stuff (did you ever find out what the situation with NAND is?) --
> not both at the same time. Or do you have U-Boot patching in status
> updates now?
I posted a Linux patch that disables the NOR flash node if video needs to be enabled.
http://patchwork.ozlabs.org/patch/126459/
However, I only now notice that Kumar requested some changes.
--
Timur Tabi
Linux kernel developer at Freescale
^ permalink raw reply
* [PATCH 1/1] Punch a hole in /dev/mem for librtas
From: Sukadev Bhattiprolu @ 2011-12-02 22:26 UTC (permalink / raw)
To: benh; +Cc: linuxppc-dev, sbest, paulus, anton
Subject: [PATCH 1/1] Punch a hole in /dev/mem for librtas
With CONFIG_STRICT_DEVMEM=y, user space cannot read any part of /dev/mem.
Since this breaks librtas, punch a hole in /dev/mem to allow access to the
rmo_buffer that librtas needs.
Anton Blanchard reported the problem and helped with the fix.
A quick test for this patch:
# cat /proc/rtas/rmo_buffer
000000000f190000 10000
# python -c "print 0x000000000f190000 / 0x10000"
3865
# dd if=/dev/mem of=/tmp/foo count=1 bs=64k skip=3865
1+0 records in
1+0 records out
65536 bytes (66 kB) copied, 0.000205235 s, 319 MB/s
# dd if=/dev/mem of=/tmp/foo
dd: reading `/dev/mem': Operation not permitted
0+0 records in
0+0 records out
0 bytes (0 B) copied, 0.00022519 s, 0.0 kB/s
Changelog[v3]: [Ben Harrenschmidt]: Incremental patch for the punched hole,
since CONFIG_STRICT_DEVMEM was merged into the -next branch.
[Ben Harrenschmidt]: Rename interface to page_is_rtas_user_buf()
move declaration to a header file and ensure it doesn't break
CONFIG_PPC_RTAS=n.
Signed-off-by: Sukadev Bhattiprolu <sukadev@linux.vnet.ibm.com>
---
arch/powerpc/include/asm/rtas.h | 12 ++++++++++++
arch/powerpc/mm/mem.c | 3 +++
2 files changed, 15 insertions(+), 0 deletions(-)
diff --git a/arch/powerpc/include/asm/rtas.h b/arch/powerpc/include/asm/rtas.h
index 58625d1..c2d3c9f 100644
--- a/arch/powerpc/include/asm/rtas.h
+++ b/arch/powerpc/include/asm/rtas.h
@@ -305,5 +305,17 @@ static inline u32 rtas_config_addr(int busno, int devfn, int reg)
extern void __cpuinit rtas_give_timebase(void);
extern void __cpuinit rtas_take_timebase(void);
+#ifdef CONFIG_PPC_RTAS
+static inline int page_is_rtas_user_buf(unsigned long pfn)
+{
+ unsigned long paddr = (pfn << PAGE_SHIFT);
+ if (paddr >= rtas_rmo_buf && paddr < (rtas_rmo_buf + RTAS_RMOBUF_MAX))
+ return 1;
+ return 0;
+}
+#else
+static inline int page_is_rtas_user_buf(unsigned long pfn) { return 0;}
+#endif
+
#endif /* __KERNEL__ */
#endif /* _POWERPC_RTAS_H */
diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
index 553fb41..05abd49 100644
--- a/arch/powerpc/mm/mem.c
+++ b/arch/powerpc/mm/mem.c
@@ -50,6 +50,7 @@
#include <asm/vdso.h>
#include <asm/fixmap.h>
#include <asm/swiotlb.h>
+#include <asm/rtas.h>
#include "mmu_decl.h"
@@ -564,6 +565,8 @@ int devmem_is_allowed(unsigned long pfn)
return 0;
if (!page_is_ram(pfn))
return 1;
+ if (page_is_rtas_user_buf(pfn))
+ return 1;
return 0;
}
#endif /* CONFIG_STRICT_DEVMEM */
--
1.7.0.4
^ permalink raw reply related
* Re: [PATCH 2/2] powerpc/85xx: add a 32-bit P1022DS device tree
From: Scott Wood @ 2011-12-02 22:34 UTC (permalink / raw)
To: Timur Tabi; +Cc: linuxppc-dev, kumar.gala
In-Reply-To: <4ED95006.9010301@freescale.com>
On 12/02/2011 04:24 PM, Timur Tabi wrote:
> Scott Wood wrote:
>
>> Please add something after post to strip simple-bus off of the localbus
>> node's compatible. Either you have board-control@0,0, or you have the
>> other stuff (did you ever find out what the situation with NAND is?) --
>> not both at the same time. Or do you have U-Boot patching in status
>> updates now?
>
> I posted a Linux patch that disables the NOR flash node if video needs to be enabled.
>
> http://patchwork.ozlabs.org/patch/126459/
>
> However, I only now notice that Kumar requested some changes.
Nothing that happens in Linux excuses handing Linux a device tree that
is wrong. That you need special handling in Linux indicates that this
is not a simple-bus.
-Scott
^ permalink raw reply
* Re: [PATCH 2/2] powerpc/85xx: add a 32-bit P1022DS device tree
From: Kumar Gala @ 2011-12-02 23:03 UTC (permalink / raw)
To: Timur Tabi; +Cc: linuxppc-dev
In-Reply-To: <1322863714-6818-2-git-send-email-timur@freescale.com>
On Dec 2, 2011, at 4:08 PM, Timur Tabi wrote:
> Add a 32-bit version of the device tree for the Freescale P1022DS =
reference
> board.
>=20
> Signed-off-by: Timur Tabi <timur@freescale.com>
> ---
> arch/powerpc/boot/dts/p1022ds_32b.dts | 270 =
+++++++++++++++++++++++++++++++++
> 1 files changed, 270 insertions(+), 0 deletions(-)
> create mode 100644 arch/powerpc/boot/dts/p1022ds_32b.dts
look at how mpc8572ds handles 36b.dts we put common definitions in a =
shared file.
- k=
^ permalink raw reply
* Re: [PATCH 2/2] powerpc/85xx: add a 32-bit P1022DS device tree
From: Timur Tabi @ 2011-12-02 23:41 UTC (permalink / raw)
To: Scott Wood; +Cc: linuxppc-dev, kumar.gala
In-Reply-To: <4ED95287.1010606@freescale.com>
Scott Wood wrote:
> Nothing that happens in Linux excuses handing Linux a device tree that
> is wrong. That you need special handling in Linux indicates that this
> is not a simple-bus.
How about this:
diff --git a/arch/powerpc/boot/dts/fsl/p1022si-post.dtsi b/arch/powerpc/boot/dts
index 16239b1..2a62edd 100644
--- a/arch/powerpc/boot/dts/fsl/p1022si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p1022si-post.dtsi
@@ -35,7 +35,11 @@
&lbc {
#address-cells = <2>;
#size-cells = <1>;
- compatible = "fsl,p1022-elbc", "fsl,elbc", "simple-bus";
+ /*
+ * The localbus on the P1022 is not a simple-bus because of the eLBC
+ * pin muxing when the DIU is enabled.
+ */
+ compatible = "fsl,p1022-elbc", "fsl,elbc";
interrupts = <19 2 0 0>;
};
--
Timur Tabi
Linux kernel developer at Freescale
^ permalink raw reply related
* Re: [PATCH 2/2] powerpc/85xx: add a 32-bit P1022DS device tree
From: Scott Wood @ 2011-12-02 23:50 UTC (permalink / raw)
To: Timur Tabi; +Cc: linuxppc-dev, kumar.gala
In-Reply-To: <4ED96236.9030505@freescale.com>
On 12/02/2011 05:41 PM, Timur Tabi wrote:
> Scott Wood wrote:
>
>> Nothing that happens in Linux excuses handing Linux a device tree that
>> is wrong. That you need special handling in Linux indicates that this
>> is not a simple-bus.
>
> How about this:
>
> diff --git a/arch/powerpc/boot/dts/fsl/p1022si-post.dtsi b/arch/powerpc/boot/dts
> index 16239b1..2a62edd 100644
> --- a/arch/powerpc/boot/dts/fsl/p1022si-post.dtsi
> +++ b/arch/powerpc/boot/dts/fsl/p1022si-post.dtsi
> @@ -35,7 +35,11 @@
> &lbc {
> #address-cells = <2>;
> #size-cells = <1>;
> - compatible = "fsl,p1022-elbc", "fsl,elbc", "simple-bus";
> + /*
> + * The localbus on the P1022 is not a simple-bus because of the eLBC
> + * pin muxing when the DIU is enabled.
> + */
> + compatible = "fsl,p1022-elbc", "fsl,elbc";
> interrupts = <19 2 0 0>;
> };
>
OK.
-Scott
^ permalink raw reply
* Re: [PATCH 1/1] Punch a hole in /dev/mem for librtas
From: Segher Boessenkool @ 2011-12-03 3:22 UTC (permalink / raw)
To: Sukadev Bhattiprolu; +Cc: sbest, paulus, anton, linuxppc-dev
In-Reply-To: <20111202222623.GA31354@us.ibm.com>
> +static inline int page_is_rtas_user_buf(unsigned long pfn)
> +{
> + unsigned long paddr = (pfn << PAGE_SHIFT);
> + if (paddr >= rtas_rmo_buf && paddr < (rtas_rmo_buf +
> RTAS_RMOBUF_MAX))
It probably cannot overflow with actual values of rtas_rmo_buf
and RTAS_RMOBUF_MAX, but otherwise it is an incorrect test;
please write
if (paddr >= rtas_rmo_buf && paddr - rtas_rmo_buf < RTAS_RMOBUF_MAX)
(and, _MAX? Shouldn't it be the actual size here? Or is _MAX
just a confusing name :-) )
Segher
^ permalink raw reply
* Re: [PATCH 7/8] 44x/476fpe: Add 476fpe SoC code
From: Tony Breeds @ 2011-12-03 10:11 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: LinuxPPC-dev
In-Reply-To: <1322859497.11728.13.camel@pasglop>
[-- Attachment #1: Type: text/plain, Size: 392 bytes --]
On Sat, Dec 03, 2011 at 07:58:17AM +1100, Benjamin Herrenschmidt wrote:
> On Thu, 2011-12-01 at 18:39 +1100, Tony Breeds wrote:
> > Based on original work by David 'Shaggy' Kliekamp.
>
> Typo in Shaggy's last name :-)
Rats!
Looks like I stuffed it up once. Do you need me to respin with these
changes or are the minor enough to be done as the patches are applied?
Yours Tony
[-- Attachment #2: Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* Re: [PATCH 7/8] 44x/476fpe: Add 476fpe SoC code
From: Josh Boyer @ 2011-12-03 13:33 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Josh Boyer, LinuxPPC-dev
In-Reply-To: <20111203101116.GA7805@thor.bakeyournoodle.com>
On Sat, Dec 3, 2011 at 5:11 AM, Tony Breeds <tony@bakeyournoodle.com> wrote=
:
> On Sat, Dec 03, 2011 at 07:58:17AM +1100, Benjamin Herrenschmidt wrote:
>> On Thu, 2011-12-01 at 18:39 +1100, Tony Breeds wrote:
>> > Based on original work by David 'Shaggy' Kliekamp.
>>
>> Typo in Shaggy's last name :-)
>
> Rats!
>
> Looks like I stuffed it up once. =A0Do you need me to respin with these
> changes or are the minor enough to be done as the patches are applied?
If the plan is to have them go through my tree, I can fix them up when
I apply them.
josh
^ permalink raw reply
* Re: [PATCH v3 02/10] powerpc: Consolidate mpic_alloc() OF address translation
From: Kumar Gala @ 2011-12-03 15:53 UTC (permalink / raw)
To: Kyle Moffett; +Cc: Paul Mackerras, linuxppc-dev, Michael Ellerman
In-Reply-To: <1322843287-2745-3-git-send-email-Kyle.D.Moffett@boeing.com>
On Dec 2, 2011, at 10:27 AM, Kyle Moffett wrote:
> Instead of using the open-coded "reg" property lookup and address
> translation in mpic_alloc(), directly call of_address_to_resource().
> This includes various workarounds for special cases which the naive
> of_address_translate() does not.
>=20
> Afterwards it is possible to remove the copiously copy-pasted calls to
> of_address_translate() from the 85xx/86xx/powermac platforms.
>=20
> Signed-off-by: Kyle Moffett <Kyle.D.Moffett@boeing.com>
> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> Cc: Paul Mackerras <paulus@samba.org>
> Cc: Grant Likely <grant.likely@secretlab.ca>
> Cc: Kumar Gala <galak@kernel.crashing.org>
> ---
> arch/powerpc/platforms/85xx/corenet_ds.c | 9 +----
> arch/powerpc/platforms/85xx/ksi8560.c | 9 +----
> arch/powerpc/platforms/85xx/mpc8536_ds.c | 9 +----
> arch/powerpc/platforms/85xx/mpc85xx_ads.c | 9 +----
> arch/powerpc/platforms/85xx/mpc85xx_cds.c | 9 +----
> arch/powerpc/platforms/85xx/mpc85xx_ds.c | 11 +----
> arch/powerpc/platforms/85xx/mpc85xx_mds.c | 9 +----
> arch/powerpc/platforms/85xx/mpc85xx_rdb.c | 11 +----
> arch/powerpc/platforms/85xx/p1010rdb.c | 9 +----
> arch/powerpc/platforms/85xx/p1022_ds.c | 9 +----
> arch/powerpc/platforms/85xx/p1023_rds.c | 9 +----
> arch/powerpc/platforms/85xx/sbc8548.c | 9 +----
> arch/powerpc/platforms/85xx/sbc8560.c | 9 +----
> arch/powerpc/platforms/85xx/socrates.c | 9 +----
> arch/powerpc/platforms/85xx/stx_gp3.c | 9 +----
> arch/powerpc/platforms/85xx/tqm85xx.c | 9 +----
> arch/powerpc/platforms/85xx/xes_mpc85xx.c | 9 +----
> arch/powerpc/platforms/86xx/pic.c | 4 +-
> arch/powerpc/platforms/powermac/pic.c | 8 +---
> arch/powerpc/sysdev/mpic.c | 61 =
++++++++++++++++-------------
> 20 files changed, 55 insertions(+), 175 deletions(-)
What about cleaning up:
arch/powerpc/platforms/chrp/setup.c: chrp_mpic =3D mpic_alloc(np, =
opaddr, MPIC_PRIMARY,
arch/powerpc/platforms/embedded6xx/holly.c: mpic =3D =
mpic_alloc(tsi_pic, mpic_paddr,
arch/powerpc/platforms/embedded6xx/linkstation.c: mpic =3D =
mpic_alloc(dnp, paddr, MPIC_PRIMARY | MPIC
arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c: mpic =3D =
mpic_alloc(tsi_pic, mpic_paddr,
arch/powerpc/platforms/embedded6xx/storcenter.c: mpic =3D =
mpic_alloc(dnp, paddr, MPIC_PRIMARY | MPIC
arch/powerpc/platforms/maple/setup.c: mpic =3D mpic_alloc(mpic_node, =
openpic_addr, flags,
arch/powerpc/platforms/pasemi/setup.c: mpic =3D mpic_alloc(mpic_node, =
openpic_addr,
arch/powerpc/platforms/pseries/setup.c: mpic =3D =
mpic_alloc(pSeries_mpic_node, openpic_addr,
Seems like we should be able to remove the 'phys_addr' argument =
altogether.
- k=
^ permalink raw reply
* Re: [PATCH v3 05/10] powerpc/mpic: Search for open-pic device-tree node if NULL
From: Kumar Gala @ 2011-12-03 16:05 UTC (permalink / raw)
To: Benjamin Herrenschmidt
Cc: linuxppc-dev list, Paul Mackerras, Michael Ellerman, Kyle Moffett
In-Reply-To: <1322843287-2745-6-git-send-email-Kyle.D.Moffett@boeing.com>
On Dec 2, 2011, at 10:28 AM, Kyle Moffett wrote:
> Almost all PowerPC platforms use a standard "open-pic" device node so
> the mpic_alloc() function now accepts NULL for the device-node. This
> will cause it to perform a default search with =
of_find_matching_node().
>=20
> Signed-off-by: Kyle Moffett <Kyle.D.Moffett@boeing.com>
> ---
> arch/powerpc/platforms/85xx/corenet_ds.c | 10 +-----
> arch/powerpc/platforms/85xx/ksi8560.c | 14 +--------
> arch/powerpc/platforms/85xx/mpc8536_ds.c | 13 +-------
> arch/powerpc/platforms/85xx/mpc85xx_ads.c | 13 +-------
> arch/powerpc/platforms/85xx/mpc85xx_cds.c | 15 +--------
> arch/powerpc/platforms/85xx/mpc85xx_ds.c | 14 ++-------
> arch/powerpc/platforms/85xx/mpc85xx_mds.c | 10 +-----
> arch/powerpc/platforms/85xx/mpc85xx_rdb.c | 14 +-------
> arch/powerpc/platforms/85xx/p1010rdb.c | 12 +------
> arch/powerpc/platforms/85xx/p1022_ds.c | 14 +--------
> arch/powerpc/platforms/85xx/p1023_rds.c | 11 +------
> arch/powerpc/platforms/85xx/sbc8548.c | 16 +---------
> arch/powerpc/platforms/85xx/sbc8560.c | 13 +-------
> arch/powerpc/platforms/85xx/socrates.c | 11 +------
> arch/powerpc/platforms/85xx/stx_gp3.c | 13 +-------
> arch/powerpc/platforms/85xx/tqm85xx.c | 13 +-------
> arch/powerpc/platforms/85xx/xes_mpc85xx.c | 13 +-------
> arch/powerpc/platforms/86xx/pic.c | 11 +-----
> arch/powerpc/platforms/embedded6xx/holly.c | 10 +-----
> arch/powerpc/platforms/embedded6xx/linkstation.c | 8 +----
> arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c | 10 +-----
> arch/powerpc/platforms/embedded6xx/storcenter.c | 10 +-----
> arch/powerpc/sysdev/mpic.c | 34 =
++++++++++++++++++--
> 23 files changed, 58 insertions(+), 244 deletions(-)
Ben,
What do pseries, cell, & maple really have in there device trees? We =
should be able to move all this into mpic.c
- k=
^ permalink raw reply
* Re: [PATCH] pq3: Add default tbi address
From: Andy Fleming @ 2011-12-03 20:15 UTC (permalink / raw)
To: Kumar Gala; +Cc: linuxppc-dev, Andy Fleming, David Miller, netdev
In-Reply-To: <B84C6222-2359-46D5-BA54-5024E43ECD3F@kernel.crashing.org>
>> arch/powerpc/boot/dts/fsl/pq3-etsec1-0.dtsi | =A0 =A05 +++++
>> arch/powerpc/boot/dts/fsl/pq3-etsec2-0.dtsi | =A0 =A05 +++++
>> 2 files changed, 10 insertions(+), 0 deletions(-)
>
> This doesn't seem correct, meaning this should really be in the board .dt=
s not in the IP.
>
> I think the driver should check and warn if this property doesn't exist.
Hmm... in principle, I agree with you. I suppose I was just being
lazy, and avoiding changing all the device trees again. However, it's
not an unreasonable default. A search through *all* of the device
trees for the tbi node indicates that 0x11 is chosen about 50% of the
time.
However, I'll devise a patch which complains if the node isn't found,
and another patch which modifies all of the offending device trees.
Andy
^ permalink raw reply
* Re: [PATCH 7/8] 44x/476fpe: Add 476fpe SoC code
From: Tony Breeds @ 2011-12-03 21:52 UTC (permalink / raw)
To: Josh Boyer; +Cc: LinuxPPC-dev
In-Reply-To: <CA+5PVA67iOfn2L8zjnjKKGhfQzhEFeU2RN90bF+5xU3=p4SN=A@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 262 bytes --]
On Sat, Dec 03, 2011 at 08:33:40AM -0500, Josh Boyer wrote:
> If the plan is to have them go through my tree, I can fix them up when
> I apply them.
I was expecting them to go through your tree, so it'd be grat if you
didn't mind finxing those up.
Yours Tony
[-- Attachment #2: Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* [PATCH 1/3] mtd/nand : use elbc_fcm_ctrl->oob to set FPAR_MS bit of FPAR
From: shuo.liu @ 2011-12-04 4:31 UTC (permalink / raw)
To: dwmw2, Artem.Bityutskiy, scottwood
Cc: linux-kernel, shuo.liu, linux-mtd, akpm, linuxppc-dev
From: Liu Shuo <b35362@freescale.com>
On both of large-page chip and small-page chip, we always should use
'elbc_fcm_ctrl->oob' to set the FPAR_LP_MS/FPAR_SP_MS bit of FPAR, don't
use a overflowed 'column' to set it.
Signed-off-by: Liu Shuo <b35362@freescale.com>
Signed-off-by: Li Yang <leoli@freescale.com>
---
drivers/mtd/nand/fsl_elbc_nand.c | 18 +++++++++++-------
1 files changed, 11 insertions(+), 7 deletions(-)
diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c
index cc08a11..6fce7da 100644
--- a/drivers/mtd/nand/fsl_elbc_nand.c
+++ b/drivers/mtd/nand/fsl_elbc_nand.c
@@ -414,9 +414,17 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
page_addr, column);
elbc_fcm_ctrl->column = column;
- elbc_fcm_ctrl->oob = 0;
elbc_fcm_ctrl->use_mdr = 1;
+ if (column >= mtd->writesize) {
+ /* OOB area */
+ column -= mtd->writesize;
+ elbc_fcm_ctrl->oob = 1;
+ } else {
+ WARN_ON(column != 0);
+ elbc_fcm_ctrl->oob = 0;
+ }
+
fcr = (NAND_CMD_STATUS << FCR_CMD1_SHIFT) |
(NAND_CMD_SEQIN << FCR_CMD2_SHIFT) |
(NAND_CMD_PAGEPROG << FCR_CMD3_SHIFT);
@@ -441,16 +449,12 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
(FIR_OP_CW1 << FIR_OP6_SHIFT) |
(FIR_OP_RS << FIR_OP7_SHIFT));
- if (column >= mtd->writesize) {
+ if (elbc_fcm_ctrl->oob)
/* OOB area --> READOOB */
- column -= mtd->writesize;
fcr |= NAND_CMD_READOOB << FCR_CMD0_SHIFT;
- elbc_fcm_ctrl->oob = 1;
- } else {
- WARN_ON(column != 0);
+ else
/* First 256 bytes --> READ0 */
fcr |= NAND_CMD_READ0 << FCR_CMD0_SHIFT;
- }
}
out_be32(&lbc->fcr, fcr);
--
1.7.1
^ permalink raw reply related
* [PATCH 2/3] mtd/nand : set correct length to FBCR for a non-full-page write
From: shuo.liu @ 2011-12-04 4:31 UTC (permalink / raw)
To: dwmw2, Artem.Bityutskiy, scottwood
Cc: linux-kernel, shuo.liu, linux-mtd, akpm, linuxppc-dev
In-Reply-To: <1322973098-2528-1-git-send-email-shuo.liu@freescale.com>
From: Liu Shuo <b35362@freescale.com>
When we do a non-full-page write, the length be set to FBCR should
not be 'elbc_fcm_ctrl->index', it should be 'elbc_fcm_ctrl->index -
elbc_fcm_ctrl->column'.
Signed-off-by: Liu Shuo <b35362@freescale.com>
Signed-off-by: Li Yang <leoli@freescale.com>
---
drivers/mtd/nand/fsl_elbc_nand.c | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)
diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c
index 6fce7da..d634c5f 100644
--- a/drivers/mtd/nand/fsl_elbc_nand.c
+++ b/drivers/mtd/nand/fsl_elbc_nand.c
@@ -474,7 +474,8 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
*/
if (elbc_fcm_ctrl->oob || elbc_fcm_ctrl->column != 0 ||
elbc_fcm_ctrl->index != mtd->writesize + mtd->oobsize)
- out_be32(&lbc->fbcr, elbc_fcm_ctrl->index);
+ out_be32(&lbc->fbcr,
+ elbc_fcm_ctrl->index - elbc_fcm_ctrl->column);
else
out_be32(&lbc->fbcr, 0);
--
1.7.1
^ permalink raw reply related
* [PATCH 3/3] mtd/nand : workaround for Freescale FCM to support large-page Nand chip
From: shuo.liu @ 2011-12-04 4:31 UTC (permalink / raw)
To: dwmw2, Artem.Bityutskiy, scottwood
Cc: linux-kernel, shuo.liu, linux-mtd, akpm, linuxppc-dev
In-Reply-To: <1322973098-2528-1-git-send-email-shuo.liu@freescale.com>
From: Liu Shuo <shuo.liu@freescale.com>
Freescale FCM controller has a 2K size limitation of buffer RAM. In order
to support the Nand flash chip whose page size is larger than 2K bytes,
we read/write 2k data repeatedly by issuing FIR_OP_RB/FIR_OP_WB and save
them to a large buffer.
Signed-off-by: Liu Shuo <shuo.liu@freescale.com>
---
v3:
-remove page_size of struct fsl_elbc_mtd.
-do a oob write by NAND_CMD_RNDIN.
drivers/mtd/nand/fsl_elbc_nand.c | 243 ++++++++++++++++++++++++++++++++++----
1 files changed, 218 insertions(+), 25 deletions(-)
diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c
index d634c5f..a92411a 100644
--- a/drivers/mtd/nand/fsl_elbc_nand.c
+++ b/drivers/mtd/nand/fsl_elbc_nand.c
@@ -55,7 +55,6 @@ struct fsl_elbc_mtd {
struct device *dev;
int bank; /* Chip select bank number */
u8 __iomem *vbase; /* Chip select base virtual address */
- int page_size; /* NAND page size (0=512, 1=2048) */
unsigned int fmr; /* FCM Flash Mode Register value */
};
@@ -75,6 +74,8 @@ struct fsl_elbc_fcm_ctrl {
unsigned int use_mdr; /* Non zero if the MDR is to be set */
unsigned int oob; /* Non zero if operating on OOB data */
unsigned int counter; /* counter for the initializations */
+
+ char *buffer; /* just be used when pagesize > 2048 */
};
/* These map to the positions used by the FCM hardware ECC generator */
@@ -150,6 +151,42 @@ static struct nand_bbt_descr bbt_mirror_descr = {
};
/*=================================*/
+static void io_to_buffer(struct mtd_info *mtd, int subpage, int oob)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct fsl_elbc_mtd *priv = chip->priv;
+ struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
+ void *src, *dst;
+ int len = (oob ? 64 : 2048);
+
+ if (oob)
+ dst = elbc_fcm_ctrl->buffer + mtd->writesize + subpage * 64;
+ else
+ dst = elbc_fcm_ctrl->buffer + subpage * 2048;
+
+ src = elbc_fcm_ctrl->addr + (oob ? 2048 : 0);
+ memcpy_fromio(dst, src, len);
+}
+
+static void buffer_to_io(struct mtd_info *mtd, int subpage, int oob)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct fsl_elbc_mtd *priv = chip->priv;
+ struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
+ void *src, *dst;
+ int len = (oob ? 64 : 2048);
+
+ if (oob)
+ src = elbc_fcm_ctrl->buffer + mtd->writesize + subpage * 64;
+ else
+ src = elbc_fcm_ctrl->buffer + subpage * 2048;
+
+ dst = elbc_fcm_ctrl->addr + (oob ? 2048 : 0);
+ memcpy_toio(dst, src, len);
+
+ /* See the in_8() in fsl_elbc_write_buf() */
+ in_8(elbc_fcm_ctrl->addr + (oob ? 2111 : 2047));
+}
/*
* Set up the FCM hardware block and page address fields, and the fcm
@@ -166,7 +203,7 @@ static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob)
elbc_fcm_ctrl->page = page_addr;
- if (priv->page_size) {
+ if (mtd->writesize >= 2048) {
/*
* large page size chip : FPAR[PI] save the lowest 6 bits,
* FBAR[BLK] save the other bits.
@@ -193,7 +230,7 @@ static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob)
/* for OOB data point to the second half of the buffer */
if (oob)
- elbc_fcm_ctrl->index += priv->page_size ? 2048 : 512;
+ elbc_fcm_ctrl->index += mtd->writesize;
dev_vdbg(priv->dev, "set_addr: bank=%d, "
"elbc_fcm_ctrl->addr=0x%p (0x%p), "
@@ -272,13 +309,14 @@ static int fsl_elbc_run_command(struct mtd_info *mtd)
return 0;
}
-static void fsl_elbc_do_read(struct nand_chip *chip, int oob)
+static void fsl_elbc_do_read(struct mtd_info *mtd, int oob)
{
+ struct nand_chip *chip = mtd->priv;
struct fsl_elbc_mtd *priv = chip->priv;
struct fsl_lbc_ctrl *ctrl = priv->ctrl;
struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
- if (priv->page_size) {
+ if (mtd->writesize >= 2048) {
out_be32(&lbc->fir,
(FIR_OP_CM0 << FIR_OP0_SHIFT) |
(FIR_OP_CA << FIR_OP1_SHIFT) |
@@ -311,6 +349,7 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
struct fsl_lbc_ctrl *ctrl = priv->ctrl;
struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand;
struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
+ int i, n;
elbc_fcm_ctrl->use_mdr = 0;
@@ -337,8 +376,29 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
elbc_fcm_ctrl->read_bytes = mtd->writesize + mtd->oobsize;
elbc_fcm_ctrl->index += column;
- fsl_elbc_do_read(chip, 0);
+ fsl_elbc_do_read(mtd, 0);
fsl_elbc_run_command(mtd);
+
+ if (mtd->writesize <= 2048)
+ return;
+
+ /* Continue to read the rest bytes if writesize > 2048 */
+ io_to_buffer(mtd, 0, 0);
+ io_to_buffer(mtd, 0, 1);
+
+ out_be32(&lbc->fir, FIR_OP_RB << FIR_OP1_SHIFT);
+
+ n = mtd->writesize / 2048;
+ for (i = 1; i < n; i++) {
+ /*
+ * Maybe there are some reasons of FCM hardware timing,
+ * we must insert a FIR_OP_NOP(0x00) before FIR_OP_RB.
+ */
+ fsl_elbc_run_command(mtd);
+ io_to_buffer(mtd, i, 0);
+ io_to_buffer(mtd, i, 1);
+ }
+
return;
/* READOOB reads only the OOB because no ECC is performed. */
@@ -347,13 +407,37 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
"fsl_elbc_cmdfunc: NAND_CMD_READOOB, page_addr:"
" 0x%x, column: 0x%x.\n", page_addr, column);
- out_be32(&lbc->fbcr, mtd->oobsize - column);
- set_addr(mtd, column, page_addr, 1);
+ if (mtd->writesize <= 2048) {
+ out_be32(&lbc->fbcr, mtd->oobsize - column);
+ set_addr(mtd, column, page_addr, 1);
+ } else {
+ out_be32(&lbc->fbcr, 64);
+ set_addr(mtd, 0, page_addr, 1);
+ elbc_fcm_ctrl->index += column;
+ }
elbc_fcm_ctrl->read_bytes = mtd->writesize + mtd->oobsize;
- fsl_elbc_do_read(chip, 1);
+ fsl_elbc_do_read(mtd, 1);
fsl_elbc_run_command(mtd);
+
+ if (mtd->writesize <= 2048)
+ return;
+
+ if (column < 64)
+ io_to_buffer(mtd, 0, 1);
+
+ out_be32(&lbc->fbcr, 2112);
+ out_be32(&lbc->fir, FIR_OP_RB << FIR_OP1_SHIFT);
+ out_be32(&lbc->fpar, in_be32(&lbc->fpar) & ~FPAR_LP_MS);
+
+ n = mtd->writesize / 2048;
+ for (i = 1; i < n; i++) {
+ fsl_elbc_run_command(mtd);
+ if (column < (64 * (i + 1)))
+ io_to_buffer(mtd, i, 1);
+ }
+
return;
/* READID must read all 5 possible bytes while CEB is active */
@@ -429,7 +513,17 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
(NAND_CMD_SEQIN << FCR_CMD2_SHIFT) |
(NAND_CMD_PAGEPROG << FCR_CMD3_SHIFT);
- if (priv->page_size) {
+ if (mtd->writesize > 2048) {
+ /* writesize > 2048 */
+ out_be32(&lbc->fir,
+ (FIR_OP_CM2 << FIR_OP0_SHIFT) |
+ (FIR_OP_CA << FIR_OP1_SHIFT) |
+ (FIR_OP_PA << FIR_OP2_SHIFT) |
+ (FIR_OP_WB << FIR_OP3_SHIFT));
+
+ if (elbc_fcm_ctrl->oob)
+ fcr |= NAND_CMD_RNDIN << FCR_CMD0_SHIFT;
+ } else if (mtd->writesize == 2048) {
out_be32(&lbc->fir,
(FIR_OP_CM2 << FIR_OP0_SHIFT) |
(FIR_OP_CA << FIR_OP1_SHIFT) |
@@ -464,6 +558,7 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
/* PAGEPROG reuses all of the setup from SEQIN and adds the length */
case NAND_CMD_PAGEPROG: {
+ int pos;
dev_vdbg(priv->dev,
"fsl_elbc_cmdfunc: NAND_CMD_PAGEPROG "
"writing %d bytes.\n", elbc_fcm_ctrl->index);
@@ -473,13 +568,72 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
* write so the HW generates the ECC.
*/
if (elbc_fcm_ctrl->oob || elbc_fcm_ctrl->column != 0 ||
- elbc_fcm_ctrl->index != mtd->writesize + mtd->oobsize)
- out_be32(&lbc->fbcr,
- elbc_fcm_ctrl->index - elbc_fcm_ctrl->column);
- else
+ elbc_fcm_ctrl->index != mtd->writesize + mtd->oobsize) {
+ if (elbc_fcm_ctrl->oob && mtd->writesize > 2048) {
+ out_be32(&lbc->fbcr, 64);
+ } else {
+ out_be32(&lbc->fbcr, elbc_fcm_ctrl->index
+ - elbc_fcm_ctrl->column);
+ }
+ } else {
out_be32(&lbc->fbcr, 0);
+ }
+
+ if (mtd->writesize > 2048) {
+ if (!elbc_fcm_ctrl->oob)
+ buffer_to_io(mtd, 0, 0);
+ buffer_to_io(mtd, 0, 1);
+ }
fsl_elbc_run_command(mtd);
+
+ if (mtd->writesize <= 2048)
+ return;
+
+ n = mtd->writesize / 2048;
+
+ if (elbc_fcm_ctrl->oob) {
+ pos = 2048;
+ out_be32(&lbc->fir,
+ (FIR_OP_CM0 << FIR_OP0_SHIFT) |
+ (FIR_OP_UA << FIR_OP1_SHIFT) |
+ (FIR_OP_UA << FIR_OP2_SHIFT) |
+ (FIR_OP_WB << FIR_OP3_SHIFT));
+
+ for (i = 1; i < n; i++) {
+ pos += 2112;
+ elbc_fcm_ctrl->mdr = pos;
+ elbc_fcm_ctrl->use_mdr = 1;
+ if (i == n - 1) {
+ out_be32(&lbc->fir,
+ (FIR_OP_CM0 << FIR_OP1_SHIFT) |
+ (FIR_OP_UA << FIR_OP2_SHIFT) |
+ (FIR_OP_UA << FIR_OP3_SHIFT) |
+ (FIR_OP_WB << FIR_OP4_SHIFT) |
+ (FIR_OP_CM3 << FIR_OP5_SHIFT) |
+ (FIR_OP_CW1 << FIR_OP6_SHIFT) |
+ (FIR_OP_RS << FIR_OP7_SHIFT));
+ }
+ buffer_to_io(mtd, i, 1);
+ fsl_elbc_run_command(mtd);
+ }
+ } else {
+ out_be32(&lbc->fir, FIR_OP_WB << FIR_OP1_SHIFT);
+ for (i = 1; i < n; i++) {
+ if (i == n - 1) {
+ elbc_fcm_ctrl->use_mdr = 1;
+ out_be32(&lbc->fir,
+ (FIR_OP_WB << FIR_OP1_SHIFT) |
+ (FIR_OP_CM3 << FIR_OP2_SHIFT) |
+ (FIR_OP_CW1 << FIR_OP3_SHIFT) |
+ (FIR_OP_RS << FIR_OP4_SHIFT));
+ }
+ buffer_to_io(mtd, i, 0);
+ buffer_to_io(mtd, i, 1);
+ fsl_elbc_run_command(mtd);
+ }
+ }
+
return;
}
@@ -500,6 +654,7 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
* write-protected, even when it is not.
*/
setbits8(elbc_fcm_ctrl->addr, NAND_STATUS_WP);
+ elbc_fcm_ctrl->buffer[0] = in_8(elbc_fcm_ctrl->addr);
return;
/* RESET without waiting for the ready line */
@@ -548,7 +703,14 @@ static void fsl_elbc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
len = bufsize - elbc_fcm_ctrl->index;
}
- memcpy_toio(&elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index], buf, len);
+ if (mtd->writesize > 2048) {
+ memcpy(&elbc_fcm_ctrl->buffer[elbc_fcm_ctrl->index],
+ buf, len);
+ } else {
+ memcpy_toio(&elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index],
+ buf, len);
+ }
+
/*
* This is workaround for the weird elbc hangs during nand write,
* Scott Wood says: "...perhaps difference in how long it takes a
@@ -572,8 +734,13 @@ static u8 fsl_elbc_read_byte(struct mtd_info *mtd)
struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand;
/* If there are still bytes in the FCM, then use the next byte. */
- if (elbc_fcm_ctrl->index < elbc_fcm_ctrl->read_bytes)
- return in_8(&elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index++]);
+ if (elbc_fcm_ctrl->index < elbc_fcm_ctrl->read_bytes) {
+ int index = elbc_fcm_ctrl->index++;
+ if (mtd->writesize > 2048)
+ return elbc_fcm_ctrl->buffer[index];
+ else
+ return in_8(&elbc_fcm_ctrl->addr[index]);
+ }
dev_err(priv->dev, "read_byte beyond end of buffer\n");
return ERR_BYTE;
@@ -594,7 +761,13 @@ static void fsl_elbc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
avail = min((unsigned int)len,
elbc_fcm_ctrl->read_bytes - elbc_fcm_ctrl->index);
- memcpy_fromio(buf, &elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index], avail);
+ if (mtd->writesize > 2048) {
+ memcpy(buf, &elbc_fcm_ctrl->buffer[elbc_fcm_ctrl->index],
+ avail);
+ } else {
+ memcpy_fromio(buf, &elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index],
+ avail);
+ }
elbc_fcm_ctrl->index += avail;
if (len > avail)
@@ -630,10 +803,17 @@ static int fsl_elbc_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
return -EINVAL;
}
- for (i = 0; i < len; i++)
- if (in_8(&elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index + i])
- != buf[i])
- break;
+ if (mtd->writesize > 2048) {
+ for (i = 0; i < len; i++)
+ if (elbc_fcm_ctrl->buffer[elbc_fcm_ctrl->index + i]
+ != buf[i])
+ break;
+ } else {
+ for (i = 0; i < len; i++)
+ if (in_8(&elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index + i])
+ != buf[i])
+ break;
+ }
elbc_fcm_ctrl->index += len;
return i == len && elbc_fcm_ctrl->status == LTESR_CC ? 0 : -EIO;
@@ -714,10 +894,9 @@ static int fsl_elbc_chip_init_tail(struct mtd_info *mtd)
/* adjust Option Register and ECC to match Flash page size */
if (mtd->writesize == 512) {
- priv->page_size = 0;
clrbits32(&lbc->bank[priv->bank].or, OR_FCM_PGS);
- } else if (mtd->writesize == 2048) {
- priv->page_size = 1;
+ } else if (mtd->writesize >= 2048 && mtd->writesize <= 16 * 1024) {
+
setbits32(&lbc->bank[priv->bank].or, OR_FCM_PGS);
/* adjust ecc setup if needed */
if ((in_be32(&lbc->bank[priv->bank].br) & BR_DECC) ==
@@ -891,6 +1070,19 @@ static int __devinit fsl_elbc_nand_probe(struct platform_device *pdev)
goto err;
}
elbc_fcm_ctrl->counter++;
+ /*
+ * Freescale FCM controller has a 2K size limitation of buffer
+ * RAM, so elbc_fcm_ctrl->buffer have to be used if writesize
+ * of chip is greater than 2048.
+ * We malloc a large enough buffer (maximum page size is 16K).
+ */
+ elbc_fcm_ctrl->buffer = kmalloc(1024 * 16 + 1024, GFP_KERNEL);
+ if (!elbc_fcm_ctrl->buffer) {
+ dev_err(dev, "failed to allocate memory\n");
+ mutex_unlock(&fsl_elbc_nand_mutex);
+ ret = -ENOMEM;
+ goto err;
+ }
spin_lock_init(&elbc_fcm_ctrl->controller.lock);
init_waitqueue_head(&elbc_fcm_ctrl->controller.wq);
@@ -960,6 +1152,7 @@ static int fsl_elbc_nand_remove(struct platform_device *pdev)
elbc_fcm_ctrl->counter--;
if (!elbc_fcm_ctrl->counter) {
fsl_lbc_ctrl_dev->nand = NULL;
+ kfree(elbc_fcm_ctrl->buffer);
kfree(elbc_fcm_ctrl);
}
mutex_unlock(&fsl_elbc_nand_mutex);
--
1.7.1
^ permalink raw reply related
* Re: [PATCH-RFC 08/10] powerpc: switch to GENERIC_PCI_IOMAP
From: Michael S. Tsirkin @ 2011-12-04 10:48 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, linuxppc-dev
In-Reply-To: <54aba7d0694e98b9103ca278486485598086b2be.1322163031.git.mst@redhat.com>
On Thu, Nov 24, 2011 at 10:19:54PM +0200, Michael S. Tsirkin wrote:
> powerpc copied pci_iomap from generic code, probably to avoid
> pulling the rest of iomap.c in. Since that's in
> a separate file now, we can reuse the common implementation.
>
> The only difference is handling of nocache flag,
> that turns out to be done correctly by the
> generic code since arch/powerpc/include/asm/io.h
> defines ioremap_nocache same as ioremap.
>
> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Sorry to nag, any ACKs/NACKs on the powerpc changes?
I intend to send this to Linus if there are no
objections. Thanks!
> ---
> arch/powerpc/Kconfig | 1 +
> arch/powerpc/kernel/iomap.c | 19 -------------------
> 2 files changed, 1 insertions(+), 19 deletions(-)
>
> diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
> index 951e18f..6ffe3df 100644
> --- a/arch/powerpc/Kconfig
> +++ b/arch/powerpc/Kconfig
> @@ -710,6 +710,7 @@ config PCI
> default PCI_PERMEDIA if !4xx && !CPM2 && !8xx
> default PCI_QSPAN if !4xx && !CPM2 && 8xx
> select ARCH_SUPPORTS_MSI
> + select GENERIC_PCI_IOMAP
> help
> Find out whether your system includes a PCI bus. PCI is the name of
> a bus system, i.e. the way the CPU talks to the other stuff inside
> diff --git a/arch/powerpc/kernel/iomap.c b/arch/powerpc/kernel/iomap.c
> index 2627918..97a3715 100644
> --- a/arch/powerpc/kernel/iomap.c
> +++ b/arch/powerpc/kernel/iomap.c
> @@ -119,24 +119,6 @@ EXPORT_SYMBOL(ioport_map);
> EXPORT_SYMBOL(ioport_unmap);
>
> #ifdef CONFIG_PCI
> -void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max)
> -{
> - resource_size_t start = pci_resource_start(dev, bar);
> - resource_size_t len = pci_resource_len(dev, bar);
> - unsigned long flags = pci_resource_flags(dev, bar);
> -
> - if (!len)
> - return NULL;
> - if (max && len > max)
> - len = max;
> - if (flags & IORESOURCE_IO)
> - return ioport_map(start, len);
> - if (flags & IORESOURCE_MEM)
> - return ioremap(start, len);
> - /* What? */
> - return NULL;
> -}
> -
> void pci_iounmap(struct pci_dev *dev, void __iomem *addr)
> {
> if (isa_vaddr_is_ioport(addr))
> @@ -146,6 +128,5 @@ void pci_iounmap(struct pci_dev *dev, void __iomem *addr)
> iounmap(addr);
> }
>
> -EXPORT_SYMBOL(pci_iomap);
> EXPORT_SYMBOL(pci_iounmap);
> #endif /* CONFIG_PCI */
> --
> 1.7.5.53.gc233e
^ permalink raw reply
* [PATCHv5] atomic: add *_dec_not_zero
From: Sven Eckelmann @ 2011-12-04 15:42 UTC (permalink / raw)
To: Andrew Morton
Cc: linux-m32r-ja, linux-mips, linux-ia64, linux-doc, H. Peter Anvin,
Heiko Carstens, Randy Dunlap, Paul Mackerras, Helge Deller,
sparclinux, linux-hexagon, Sven Eckelmann, linux-arch, linux-s390,
Russell King, user-mode-linux-devel, Richard Weinberger,
Hirokazu Takata, x86, James E.J. Bottomley, Ingo Molnar,
Matt Turner, Fenghua Yu, Arnd Bergmann, Jeff Dike, Chris Metcalf,
linux-m32r, Ivan Kokshaysky, Thomas Gleixner, linux-arm-kernel,
Richard Henderson, Tony Luck, linux-parisc, b.a.t.m.a.n,
linux-kernel, Ralf Baechle, Kyle McMartin, linux-alpha,
Martin Schwidefsky, linux390, linuxppc-dev, David S. Miller
Introduce an *_dec_not_zero operation. Make this a special case of
*_add_unless because batman-adv uses atomic_dec_not_zero in different
places like re-broadcast queue or aggregation queue management. There
are other non-final patches which may also want to use this macro.
Suggested-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Cc: Randy Dunlap <rdunlap@xenotime.net>
Cc: Richard Henderson <rth@twiddle.net>
Cc: Ivan Kokshaysky <ink@jurassic.park.msu.ru>
Cc: Matt Turner <mattst88@gmail.com>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Fenghua Yu <fenghua.yu@intel.com>
Cc: Hirokazu Takata <takata@linux-m32r.org>
Cc: Ralf Baechle <ralf@linux-mips.org>
Cc: Kyle McMartin <kyle@mcmartin.ca>
Cc: Helge Deller <deller@gmx.de>
Cc: "James E.J. Bottomley" <jejb@parisc-linux.org>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
Cc: Heiko Carstens <heiko.carstens@de.ibm.com>
Cc: linux390@de.ibm.com
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Chris Metcalf <cmetcalf@tilera.com>
Cc: Jeff Dike <jdike@addtoit.com>
Cc: Richard Weinberger <richard@nod.at>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: x86@kernel.org
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: linux-doc@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Cc: linux-alpha@vger.kernel.org
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-ia64@vger.kernel.org
Cc: linux-m32r@ml.linux-m32r.org
Cc: linux-m32r-ja@ml.linux-m32r.org
Cc: linux-mips@linux-mips.org
Cc: linux-parisc@vger.kernel.org
Cc: linuxppc-dev@lists.ozlabs.org
Cc: linux-s390@vger.kernel.org
Cc: sparclinux@vger.kernel.org
Cc: user-mode-linux-devel@lists.sourceforge.net
Cc: linux-hexagon@vger.kernel.org
---
David S. Miller recommended this change in
https://lists.open-mesh.org/pipermail/b.a.t.m.a.n/2011-May/004560.html
Arnd Bergmann wanted to apply it in 201106172320.26476.arnd@arndb.de
... and then Arun Sharma created a big merge conflict with
https://lkml.org/lkml/2011/6/6/430
I don't think that it is a a good idea to assume that everyone still
agrees with the patch after I've rewritten it. I try Andrew Morton this
time because he applied the last changes to include/linux/atomic.h.
There are already two projects (batman-adv/fault_inject) which include
their private definition (not conflicting) and I have patches for 9
other modules that could use it.
Documentation/atomic_ops.txt | 1 +
arch/alpha/include/asm/atomic.h | 1 +
arch/alpha/include/asm/local.h | 1 +
arch/arm/include/asm/atomic.h | 1 +
arch/hexagon/include/asm/atomic.h | 1 +
arch/ia64/include/asm/atomic.h | 1 +
arch/m32r/include/asm/local.h | 1 +
arch/mips/include/asm/atomic.h | 1 +
arch/mips/include/asm/local.h | 1 +
arch/parisc/include/asm/atomic.h | 1 +
arch/powerpc/include/asm/atomic.h | 1 +
arch/powerpc/include/asm/local.h | 1 +
arch/s390/include/asm/atomic.h | 1 +
arch/sparc/include/asm/atomic_64.h | 1 +
arch/tile/include/asm/atomic_32.h | 1 +
arch/tile/include/asm/atomic_64.h | 1 +
arch/x86/include/asm/atomic64_32.h | 12 ++++++++++++
arch/x86/include/asm/atomic64_64.h | 1 +
arch/x86/include/asm/local.h | 1 +
arch/x86/lib/atomic64_32.c | 4 ++++
arch/x86/lib/atomic64_386_32.S | 21 +++++++++++++++++++++
arch/x86/lib/atomic64_cx8_32.S | 28 ++++++++++++++++++++++++++++
include/asm-generic/atomic-long.h | 2 ++
include/asm-generic/atomic64.h | 1 +
include/asm-generic/local.h | 1 +
include/asm-generic/local64.h | 2 ++
include/linux/atomic.h | 9 +++++++++
lib/atomic64_test.c | 19 +++++++++++++++++++
28 files changed, 117 insertions(+), 0 deletions(-)
diff --git a/Documentation/atomic_ops.txt b/Documentation/atomic_ops.txt
index 3bd585b..1eec221 100644
--- a/Documentation/atomic_ops.txt
+++ b/Documentation/atomic_ops.txt
@@ -190,6 +190,7 @@ atomic_add_unless requires explicit memory barriers around the operation
unless it fails (returns 0).
atomic_inc_not_zero, equivalent to atomic_add_unless(v, 1, 0)
+atomic_dec_not_zero, equivalent to atomic_add_unless(v, -1, 0)
If a caller requires memory barrier semantics around an atomic_t
diff --git a/arch/alpha/include/asm/atomic.h b/arch/alpha/include/asm/atomic.h
index 640f909..09d1571 100644
--- a/arch/alpha/include/asm/atomic.h
+++ b/arch/alpha/include/asm/atomic.h
@@ -225,6 +225,7 @@ static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u)
}
#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
+#define atomic64_dec_not_zero(v) atomic64_add_unless((v), -1, 0)
#define atomic_add_negative(a, v) (atomic_add_return((a), (v)) < 0)
#define atomic64_add_negative(a, v) (atomic64_add_return((a), (v)) < 0)
diff --git a/arch/alpha/include/asm/local.h b/arch/alpha/include/asm/local.h
index 9c94b84..51eb678 100644
--- a/arch/alpha/include/asm/local.h
+++ b/arch/alpha/include/asm/local.h
@@ -79,6 +79,7 @@ static __inline__ long local_sub_return(long i, local_t * l)
c != (u); \
})
#define local_inc_not_zero(l) local_add_unless((l), 1, 0)
+#define local_dec_not_zero(l) local_add_unless((l), -1, 0)
#define local_add_negative(a, l) (local_add_return((a), (l)) < 0)
diff --git a/arch/arm/include/asm/atomic.h b/arch/arm/include/asm/atomic.h
index 86976d0..80ed975 100644
--- a/arch/arm/include/asm/atomic.h
+++ b/arch/arm/include/asm/atomic.h
@@ -458,6 +458,7 @@ static inline int atomic64_add_unless(atomic64_t *v, u64 a, u64 u)
#define atomic64_dec_return(v) atomic64_sub_return(1LL, (v))
#define atomic64_dec_and_test(v) (atomic64_dec_return((v)) == 0)
#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1LL, 0LL)
+#define atomic64_dec_not_zero(v) atomic64_add_unless((v), -1LL, 0LL)
#endif /* !CONFIG_GENERIC_ATOMIC64 */
#endif
diff --git a/arch/hexagon/include/asm/atomic.h b/arch/hexagon/include/asm/atomic.h
index e220f90..3a1a33a 100644
--- a/arch/hexagon/include/asm/atomic.h
+++ b/arch/hexagon/include/asm/atomic.h
@@ -148,6 +148,7 @@ static inline int __atomic_add_unless(atomic_t *v, int a, int u)
}
#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+#define atomic_dec_not_zero(v) atomic_add_unless((v), -1, 0)
#define atomic_inc(v) atomic_add(1, (v))
#define atomic_dec(v) atomic_sub(1, (v))
diff --git a/arch/ia64/include/asm/atomic.h b/arch/ia64/include/asm/atomic.h
index 3fad89e..af6e9b2 100644
--- a/arch/ia64/include/asm/atomic.h
+++ b/arch/ia64/include/asm/atomic.h
@@ -122,6 +122,7 @@ static __inline__ long atomic64_add_unless(atomic64_t *v, long a, long u)
}
#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
+#define atomic64_dec_not_zero(v) atomic64_add_unless((v), -1, 0)
#define atomic_add_return(i,v) \
({ \
diff --git a/arch/m32r/include/asm/local.h b/arch/m32r/include/asm/local.h
index 734bca8..d536082 100644
--- a/arch/m32r/include/asm/local.h
+++ b/arch/m32r/include/asm/local.h
@@ -272,6 +272,7 @@ static inline int local_add_unless(local_t *l, long a, long u)
}
#define local_inc_not_zero(l) local_add_unless((l), 1, 0)
+#define local_dec_not_zero(l) local_add_unless((l), -1, 0)
static inline void local_clear_mask(unsigned long mask, local_t *addr)
{
diff --git a/arch/mips/include/asm/atomic.h b/arch/mips/include/asm/atomic.h
index 1d93f81..babb043 100644
--- a/arch/mips/include/asm/atomic.h
+++ b/arch/mips/include/asm/atomic.h
@@ -697,6 +697,7 @@ static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u)
}
#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
+#define atomic64_dec_not_zero(v) atomic64_add_unless((v), -1, 0)
#define atomic64_dec_return(v) atomic64_sub_return(1, (v))
#define atomic64_inc_return(v) atomic64_add_return(1, (v))
diff --git a/arch/mips/include/asm/local.h b/arch/mips/include/asm/local.h
index 94fde8d..0242256 100644
--- a/arch/mips/include/asm/local.h
+++ b/arch/mips/include/asm/local.h
@@ -137,6 +137,7 @@ static __inline__ long local_sub_return(long i, local_t * l)
c != (u); \
})
#define local_inc_not_zero(l) local_add_unless((l), 1, 0)
+#define local_dec_not_zero(l) local_add_unless((l), -1, 0)
#define local_dec_return(l) local_sub_return(1, (l))
#define local_inc_return(l) local_add_return(1, (l))
diff --git a/arch/parisc/include/asm/atomic.h b/arch/parisc/include/asm/atomic.h
index 4054b31..57b7069 100644
--- a/arch/parisc/include/asm/atomic.h
+++ b/arch/parisc/include/asm/atomic.h
@@ -334,6 +334,7 @@ static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u)
}
#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
+#define atomic64_dec_not_zero(v) atomic64_add_unless((v), -1, 0)
#endif /* !CONFIG_64BIT */
diff --git a/arch/powerpc/include/asm/atomic.h b/arch/powerpc/include/asm/atomic.h
index 02e41b5..0798420 100644
--- a/arch/powerpc/include/asm/atomic.h
+++ b/arch/powerpc/include/asm/atomic.h
@@ -468,6 +468,7 @@ static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u)
}
#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
+#define atomic64_dec_not_zero(v) atomic64_add_unless((v), -1, 0)
#endif /* __powerpc64__ */
diff --git a/arch/powerpc/include/asm/local.h b/arch/powerpc/include/asm/local.h
index b8da913..d182e34 100644
--- a/arch/powerpc/include/asm/local.h
+++ b/arch/powerpc/include/asm/local.h
@@ -134,6 +134,7 @@ static __inline__ int local_add_unless(local_t *l, long a, long u)
}
#define local_inc_not_zero(l) local_add_unless((l), 1, 0)
+#define local_dec_not_zero(l) local_add_unless((l), -1, 0)
#define local_sub_and_test(a, l) (local_sub_return((a), (l)) == 0)
#define local_dec_and_test(l) (local_dec_return((l)) == 0)
diff --git a/arch/s390/include/asm/atomic.h b/arch/s390/include/asm/atomic.h
index 8517d2a..92e7d5d 100644
--- a/arch/s390/include/asm/atomic.h
+++ b/arch/s390/include/asm/atomic.h
@@ -325,6 +325,7 @@ static inline long long atomic64_dec_if_positive(atomic64_t *v)
#define atomic64_dec_return(_v) atomic64_sub_return(1, _v)
#define atomic64_dec_and_test(_v) (atomic64_sub_return(1, _v) == 0)
#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
+#define atomic64_dec_not_zero(v) atomic64_add_unless((v), -1, 0)
#define smp_mb__before_atomic_dec() smp_mb()
#define smp_mb__after_atomic_dec() smp_mb()
diff --git a/arch/sparc/include/asm/atomic_64.h b/arch/sparc/include/asm/atomic_64.h
index 9f421df..94cf160 100644
--- a/arch/sparc/include/asm/atomic_64.h
+++ b/arch/sparc/include/asm/atomic_64.h
@@ -106,6 +106,7 @@ static inline long atomic64_add_unless(atomic64_t *v, long a, long u)
}
#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
+#define atomic64_dec_not_zero(v) atomic64_add_unless((v), -1, 0)
/* Atomic operations are already serializing */
#define smp_mb__before_atomic_dec() barrier()
diff --git a/arch/tile/include/asm/atomic_32.h b/arch/tile/include/asm/atomic_32.h
index c03349e..9cfafb3 100644
--- a/arch/tile/include/asm/atomic_32.h
+++ b/arch/tile/include/asm/atomic_32.h
@@ -233,6 +233,7 @@ static inline void atomic64_set(atomic64_t *v, u64 n)
#define atomic64_dec_return(v) atomic64_sub_return(1LL, (v))
#define atomic64_dec_and_test(v) (atomic64_dec_return((v)) == 0)
#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1LL, 0LL)
+#define atomic64_dec_not_zero(v) atomic64_add_unless((v), -1LL, 0LL)
/*
* We need to barrier before modifying the word, since the _atomic_xxx()
diff --git a/arch/tile/include/asm/atomic_64.h b/arch/tile/include/asm/atomic_64.h
index 27fe667..9c22f50 100644
--- a/arch/tile/include/asm/atomic_64.h
+++ b/arch/tile/include/asm/atomic_64.h
@@ -141,6 +141,7 @@ static inline long atomic64_add_unless(atomic64_t *v, long a, long u)
#define atomic64_add_negative(i, v) (atomic64_add_return((i), (v)) < 0)
#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
+#define atomic64_dec_not_zero(v) atomic64_add_unless((v), -1, 0)
/* Atomic dec and inc don't implement barrier, so provide them if needed. */
#define smp_mb__before_atomic_dec() smp_mb()
diff --git a/arch/x86/include/asm/atomic64_32.h b/arch/x86/include/asm/atomic64_32.h
index 24098aa..3cd4431 100644
--- a/arch/x86/include/asm/atomic64_32.h
+++ b/arch/x86/include/asm/atomic64_32.h
@@ -287,6 +287,18 @@ static inline int atomic64_inc_not_zero(atomic64_t *v)
return r;
}
+
+static inline int atomic64_dec_not_zero(atomic64_t *v)
+{
+ int r;
+ asm volatile(ATOMIC64_ALTERNATIVE(dec_not_zero)
+ : "=a" (r)
+ : "S" (v)
+ : "ecx", "edx", "memory"
+ );
+ return r;
+}
+
static inline long long atomic64_dec_if_positive(atomic64_t *v)
{
long long r;
diff --git a/arch/x86/include/asm/atomic64_64.h b/arch/x86/include/asm/atomic64_64.h
index 0e1cbfc..539e41b 100644
--- a/arch/x86/include/asm/atomic64_64.h
+++ b/arch/x86/include/asm/atomic64_64.h
@@ -216,6 +216,7 @@ static inline int atomic64_add_unless(atomic64_t *v, long a, long u)
}
#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
+#define atomic64_dec_not_zero(v) atomic64_add_unless((v), -1, 0)
/*
* atomic64_dec_if_positive - decrement by 1 if old value positive
diff --git a/arch/x86/include/asm/local.h b/arch/x86/include/asm/local.h
index 9cdae5d..2c8c92d 100644
--- a/arch/x86/include/asm/local.h
+++ b/arch/x86/include/asm/local.h
@@ -185,6 +185,7 @@ static inline long local_sub_return(long i, local_t *l)
c != (u); \
})
#define local_inc_not_zero(l) local_add_unless((l), 1, 0)
+#define local_dec_not_zero(l) local_add_unless((l), -1, 0)
/* On x86_32, these are no better than the atomic variants.
* On x86-64 these are better than the atomic variants on SMP kernels
diff --git a/arch/x86/lib/atomic64_32.c b/arch/x86/lib/atomic64_32.c
index 042f682..7da05c3 100644
--- a/arch/x86/lib/atomic64_32.c
+++ b/arch/x86/lib/atomic64_32.c
@@ -24,6 +24,8 @@ long long atomic64_dec_if_positive_cx8(atomic64_t *v);
EXPORT_SYMBOL(atomic64_dec_if_positive_cx8);
int atomic64_inc_not_zero_cx8(atomic64_t *v);
EXPORT_SYMBOL(atomic64_inc_not_zero_cx8);
+int atomic64_dec_not_zero_cx8(atomic64_t *v);
+EXPORT_SYMBOL(atomic64_dec_not_zero_cx8);
int atomic64_add_unless_cx8(atomic64_t *v, long long a, long long u);
EXPORT_SYMBOL(atomic64_add_unless_cx8);
@@ -54,6 +56,8 @@ long long atomic64_dec_if_positive_386(atomic64_t *v);
EXPORT_SYMBOL(atomic64_dec_if_positive_386);
int atomic64_inc_not_zero_386(atomic64_t *v);
EXPORT_SYMBOL(atomic64_inc_not_zero_386);
+int atomic64_dec_not_zero_386(atomic64_t *v);
+EXPORT_SYMBOL(atomic64_dec_not_zero_386);
int atomic64_add_unless_386(atomic64_t *v, long long a, long long u);
EXPORT_SYMBOL(atomic64_add_unless_386);
#endif
diff --git a/arch/x86/lib/atomic64_386_32.S b/arch/x86/lib/atomic64_386_32.S
index e8e7e0d..c78337b 100644
--- a/arch/x86/lib/atomic64_386_32.S
+++ b/arch/x86/lib/atomic64_386_32.S
@@ -181,6 +181,27 @@ ENDP
#undef v
#define v %esi
+BEGIN(dec_not_zero)
+ movl (v), %eax
+ movl 4(v), %edx
+ testl %eax, %eax
+ je 3f
+1:
+ subl $1, %eax
+ sbbl $0, %edx
+ movl %eax, (v)
+ movl %edx, 4(v)
+ movl $1, %eax
+2:
+ RET
+3:
+ testl %edx, %edx
+ jne 1b
+ jmp 2b
+ENDP
+#undef v
+
+#define v %esi
BEGIN(dec_if_positive)
movl (v), %eax
movl 4(v), %edx
diff --git a/arch/x86/lib/atomic64_cx8_32.S b/arch/x86/lib/atomic64_cx8_32.S
index 391a083..989638c 100644
--- a/arch/x86/lib/atomic64_cx8_32.S
+++ b/arch/x86/lib/atomic64_cx8_32.S
@@ -220,3 +220,31 @@ ENTRY(atomic64_inc_not_zero_cx8)
jmp 3b
CFI_ENDPROC
ENDPROC(atomic64_inc_not_zero_cx8)
+
+ENTRY(atomic64_dec_not_zero_cx8)
+ CFI_STARTPROC
+ SAVE ebx
+
+ read64 %esi
+1:
+ testl %eax, %eax
+ je 4f
+2:
+ movl %eax, %ebx
+ movl %edx, %ecx
+ subl $1, %ebx
+ sbbl $0, %ecx
+ LOCK_PREFIX
+ cmpxchg8b (%esi)
+ jne 1b
+
+ movl $1, %eax
+3:
+ RESTORE ebx
+ ret
+4:
+ testl %edx, %edx
+ jne 2b
+ jmp 3b
+ CFI_ENDPROC
+ENDPROC(atomic64_dec_not_zero_cx8)
diff --git a/include/asm-generic/atomic-long.h b/include/asm-generic/atomic-long.h
index b7babf0..0fe75ab 100644
--- a/include/asm-generic/atomic-long.h
+++ b/include/asm-generic/atomic-long.h
@@ -130,6 +130,7 @@ static inline long atomic_long_add_unless(atomic_long_t *l, long a, long u)
}
#define atomic_long_inc_not_zero(l) atomic64_inc_not_zero((atomic64_t *)(l))
+#define atomic_long_dec_not_zero(l) atomic64_dec_not_zero((atomic64_t *)(l))
#define atomic_long_cmpxchg(l, old, new) \
(atomic64_cmpxchg((atomic64_t *)(l), (old), (new)))
@@ -247,6 +248,7 @@ static inline long atomic_long_add_unless(atomic_long_t *l, long a, long u)
}
#define atomic_long_inc_not_zero(l) atomic_inc_not_zero((atomic_t *)(l))
+#define atomic_long_dec_not_zero(l) atomic_dec_not_zero((atomic_t *)(l))
#define atomic_long_cmpxchg(l, old, new) \
(atomic_cmpxchg((atomic_t *)(l), (old), (new)))
diff --git a/include/asm-generic/atomic64.h b/include/asm-generic/atomic64.h
index b18ce4f..90ff9b1 100644
--- a/include/asm-generic/atomic64.h
+++ b/include/asm-generic/atomic64.h
@@ -38,5 +38,6 @@ extern int atomic64_add_unless(atomic64_t *v, long long a, long long u);
#define atomic64_dec_return(v) atomic64_sub_return(1LL, (v))
#define atomic64_dec_and_test(v) (atomic64_dec_return((v)) == 0)
#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1LL, 0LL)
+#define atomic64_dec_not_zero(v) atomic64_add_unless((v), -1LL, 0LL)
#endif /* _ASM_GENERIC_ATOMIC64_H */
diff --git a/include/asm-generic/local.h b/include/asm-generic/local.h
index 9ceb03b..fabf4f3 100644
--- a/include/asm-generic/local.h
+++ b/include/asm-generic/local.h
@@ -44,6 +44,7 @@ typedef struct
#define local_xchg(l, n) atomic_long_xchg((&(l)->a), (n))
#define local_add_unless(l, _a, u) atomic_long_add_unless((&(l)->a), (_a), (u))
#define local_inc_not_zero(l) atomic_long_inc_not_zero(&(l)->a)
+#define local_dec_not_zero(l) atomic_long_dec_not_zero(&(l)->a)
/* Non-atomic variants, ie. preemption disabled and won't be touched
* in interrupt, etc. Some archs can optimize this case well. */
diff --git a/include/asm-generic/local64.h b/include/asm-generic/local64.h
index 5980002..76acbe2 100644
--- a/include/asm-generic/local64.h
+++ b/include/asm-generic/local64.h
@@ -45,6 +45,7 @@ typedef struct {
#define local64_xchg(l, n) local_xchg((&(l)->a), (n))
#define local64_add_unless(l, _a, u) local_add_unless((&(l)->a), (_a), (u))
#define local64_inc_not_zero(l) local_inc_not_zero(&(l)->a)
+#define local64_dec_not_zero(l) local_dec_not_zero(&(l)->a)
/* Non-atomic variants, ie. preemption disabled and won't be touched
* in interrupt, etc. Some archs can optimize this case well. */
@@ -83,6 +84,7 @@ typedef struct {
#define local64_xchg(l, n) atomic64_xchg((&(l)->a), (n))
#define local64_add_unless(l, _a, u) atomic64_add_unless((&(l)->a), (_a), (u))
#define local64_inc_not_zero(l) atomic64_inc_not_zero(&(l)->a)
+#define local64_dec_not_zero(l) atomic64_dec_not_zero(&(l)->a)
/* Non-atomic variants, ie. preemption disabled and won't be touched
* in interrupt, etc. Some archs can optimize this case well. */
diff --git a/include/linux/atomic.h b/include/linux/atomic.h
index 42b77b5..ad2b750 100644
--- a/include/linux/atomic.h
+++ b/include/linux/atomic.h
@@ -27,6 +27,15 @@ static inline int atomic_add_unless(atomic_t *v, int a, int u)
#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
/**
+ * atomic_dec_not_zero - decrement unless the number is zero
+ * @v: pointer of type atomic_t
+ *
+ * Atomically decrements @v by 1, so long as @v is non-zero.
+ * Returns non-zero if @v was non-zero, and zero otherwise.
+ */
+#define atomic_dec_not_zero(v) atomic_add_unless((v), -1, 0)
+
+/**
* atomic_inc_not_zero_hint - increment if not null
* @v: pointer of type atomic_t
* @hint: probable value of the atomic before the increment
diff --git a/lib/atomic64_test.c b/lib/atomic64_test.c
index 0c33cde..b7468b7 100644
--- a/lib/atomic64_test.c
+++ b/lib/atomic64_test.c
@@ -145,6 +145,25 @@ static __init int test_atomic64(void)
r += one;
BUG_ON(v.counter != r);
+ INIT(onestwos);
+ BUG_ON(!atomic64_dec_not_zero(&v));
+ r -= one;
+ BUG_ON(v.counter != r);
+
+ INIT(0);
+ BUG_ON(atomic64_dec_not_zero(&v));
+ BUG_ON(v.counter != r);
+
+ INIT(one);
+ BUG_ON(!atomic64_dec_not_zero(&v));
+ r -= one;
+ BUG_ON(v.counter != r);
+
+ INIT(-one);
+ BUG_ON(!atomic64_dec_not_zero(&v));
+ r -= one;
+ BUG_ON(v.counter != r);
+
#ifdef CONFIG_X86
printk(KERN_INFO "atomic64 test passed for %s platform %s CX8 and %s SSE\n",
#ifdef CONFIG_X86_64
--
1.7.7.3
^ 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