LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH] net: fsl_pq_mdio: fix non tbi phy access
From: Andy Fleming @ 2011-11-15 15:06 UTC (permalink / raw)
  To: Baruch Siach; +Cc: netdev@vger.kernel.org, linuxppc-dev
In-Reply-To: <20111115051713.GA4052@sapphire.tkos.co.il>


On Nov 14, 2011, at 11:17 PM, Baruch Siach wrote:

> Hi Andy,
>=20
> On Mon, Nov 14, 2011 at 09:04:47PM +0000, Fleming Andy-AFLEMING wrote:
>> Well, this got applied quickly, so I guess I can't NAK, but this =
requires discussion.
>>=20
>> On Nov 14, 2011, at 0:22, "Baruch Siach" <baruch@tkos.co.il> wrote:
>>=20
>>> Since 952c5ca1 (fsl_pq_mdio: Clean up tbi address configuration) =
.probe returns
>>> -EBUSY when the "tbi-phy" node is missing. Fix this.
>>=20
>> It returns an error because it finds no tbi node. Because without the =
tbi=20
>> node, there is no way for the driver to determine which address to =
set.
>>=20
>> Your solution is to ignore the error, and hope. That's a broken =
approach. =20
>> The real solution for a p1010 should be to have a tbi node in the =
dts.
>=20
> Can you elaborate a bit on why this approach is broken? The PHY used =
to work=20
> for me until 952c5ca1, and with this applied.


Yes, well, just because a problem goes away when a patch is applied does =
not mean that the patch is correct, or that it made things work.

An explanation:

In order to support certain types of serial data interfaces with =
external PHYs (like SGMII), it is necessary to translate the MAC's data =
signaling into the serialized signaling. On Freescale parts, this is =
done via a SerDes block, but the SerDes link needs a small amount of =
management. To perform this management, we have an onboard "TBI" PHY. =
This PHY is highly integrated with the MAC and MDIO devices. Each MAC =
has two relevant components:

1) a TBIPA register, which declares the address of the TBI PHY
2) an associated MDIO controller.

In order to configure the SerDes link, it is necessary to communicate =
via the "local" MDIO controller with the TBI PHY. For most of the MACs, =
this is simple: Choose an address for TBIPA, and then use that address =
to communicate with the TBI PHY. However, the *first* MDIO controller is =
also used to communicate with external PHYs. On this controller, we have =
to be fairly particular about which address we put in TBIPA, because all =
transactions to that address will go to the TBI PHY. On older parts, =
this value defaulted to "0", but it now defaults to "31", I believe.

Ok, so now we're at this code. The of_mdiobus_register() function will =
parse the device tree, and find all of the PHYs on the MDIO bus, and =
register them as devices. In order to ensure that all of those PHYs are =
accessible, we *MUST* set TBIPA to something that won't conflict with =
any existing addresses. The mechanism we have chosen for this is to =
assign the address in the device tree, via a tbi-phy node.

My recent patch changed the behavior, because we used to try to find a =
free address via scanning, but this was somewhat ugly, and failed (as =
you noticed) due to uninitialized mutexes.

The reason your latest patch is wrong is because it doesn't set the =
TBIPA register at all if there is no tbi-phy node. Instead, it just =
relies on luck, hoping that the TBIPA register was set to something that =
doesn't conflict already. It will work if 0x1f or 0 aren't necessary PHY =
addresses for your board, or if the firmware set it to something =
sensible.


>=20
>> And looking at the p1010si.dtsi, I see that it's automatically there =
for=20
>> you.
>>=20
>> How were you breaking?
>=20
> Adding linuxppc to Cc.
>=20
> My board is P1011 based, the single core version of P1020, not P1010. =
In=20
> p1020si.dtsi I see no tbi node. In p1020rdb.dts I see a tbi node but =
only for=20
> mdio@25000, not mdio@24000, which is what I'm using.
>=20
> Am I missing something?


Well, that's a bug. In truth, the silicon dtsi trees should not have tbi =
nodes, as that's highly machine-specific. The p1020rdb is apparently =
relying on the old behavior, which is broken, and due to the fact that =
the first ethernet interface doesn't *use* the TBI PHY.

You should add this to your board tree:

                mdio@24000 {

                        tbi0: tbi-phy@11 {
                                reg =3D <0x11>;
                                device_type =3D "tbi-phy";
                        };
                };

And add the PHYs you use, as well as set reg (and the value after the =
"@") to something that makes sense for your board.

I am going to go right now, and add tbi nodes for all of the Freescale =
platforms. I will also modify the fsl_pq_mdio code to be more explicit =
about its reason for failure.

Andy=

^ permalink raw reply

* RE: [PATCH 1/3] mtd/nand: fix coding style issue in drivers/mtd/nand/fsl_elbc.c
From: David Woodhouse @ 2011-11-15 15:05 UTC (permalink / raw)
  To: Jenkins, Clive
  Cc: Artem.Bityutskiy, b35362, linux-kernel, linux-mtd, scottwood,
	akpm, linuxppc-dev
In-Reply-To: <929D3CED81F34E43887A393170D66FB9053A8F81@GBRSUN01MS002.eu.xerox.net>

[-- Attachment #1: Type: text/plain, Size: 375 bytes --]

On Tue, 2011-11-15 at 14:42 +0000, Jenkins, Clive wrote:
> This may be your (not so humble :-) opinion, and I happen to agree that
> a tab setting of 8 is best, usually. However, as Linus says in his
> coding style document "Coding style is very personal, and I won't _force_
> my views on anybody". 

I refer you to the remainder of that same sentence.

-- 
dwmw2

[-- Attachment #2: smime.p7s --]
[-- Type: application/x-pkcs7-signature, Size: 5818 bytes --]

^ permalink raw reply

* RE: [PATCH 1/3] mtd/nand: fix coding style issue in drivers/mtd/nand/fsl_elbc.c
From: David Laight @ 2011-11-15 14:51 UTC (permalink / raw)
  To: David Woodhouse, Jenkins, Clive
  Cc: Artem.Bityutskiy, b35362, linux-kernel, linux-mtd, scottwood,
	akpm, linuxppc-dev
In-Reply-To: <1321362603.1932.67.camel@shinybook.infradead.org>

=20
> On Tue, 2011-11-15 at 11:26 +0000, Jenkins, Clive wrote:
> > > fix whitespaces,tabs coding style issue and ...
> >=20
> > In my opinion this code was already correct, and would display
correctly
> > at any TAB setting. This patch changes it so that it displays
> > incorrectly at all TAB settings other than 8.
>=20
> Any tab setting other than 8 is incorrect and should not be used for
> Linux code. If I view it in a proportionally-spaced font,=20
> it's not going to line up right either. Fix your editor, if that's an
issue for you.

Personally I don't even attempt to line up argumants on
continuation lines - it just wastes vertical space.
I just indent them as any other continuation line, so
double-indent if using 4-char indents and 1/2 indent for
8-char indents.

Tabs have to be assumed to be 8 columns, otherwise all sorts
of tools just get it wrong.
(Or you ban tabs from source files.)

	David

^ permalink raw reply

* RE: [PATCH 1/3] mtd/nand: fix coding style issue in drivers/mtd/nand/fsl_elbc.c
From: Jenkins, Clive @ 2011-11-15 14:42 UTC (permalink / raw)
  To: David Woodhouse
  Cc: Artem.Bityutskiy, b35362, linux-kernel, linux-mtd, scottwood,
	akpm, linuxppc-dev
In-Reply-To: <1321362603.1932.67.camel@shinybook.infradead.org>

PiA+ID4gZml4IHdoaXRlc3BhY2VzLHRhYnMgY29kaW5nIHN0eWxlIGlzc3VlIGFuZCAuLi4NCj4g
PiANCj4gPiBJbiBteSBvcGluaW9uIHRoaXMgY29kZSB3YXMgYWxyZWFkeSBjb3JyZWN0LCBhbmQg
d291bGQgZGlzcGxheSBjb3JyZWN0bHkNCj4gPiBhdCBhbnkgVEFCIHNldHRpbmcuIFRoaXMgcGF0
Y2ggY2hhbmdlcyBpdCBzbyB0aGF0IGl0IGRpc3BsYXlzDQo+ID4gaW5jb3JyZWN0bHkgYXQgYWxs
IFRBQiBzZXR0aW5ncyBvdGhlciB0aGFuIDguDQo+DQo+IEFueSB0YWIgc2V0dGluZyBvdGhlciB0
aGFuIDggaXMgaW5jb3JyZWN0IGFuZCBzaG91bGQgbm90IGJlIHVzZWQgZm9yDQo+IExpbnV4IGNv
ZGUuDQoNClRoaXMgbWF5IGJlIHlvdXIgKG5vdCBzbyBodW1ibGUgOi0pIG9waW5pb24sIGFuZCBJ
IGhhcHBlbiB0byBhZ3JlZSB0aGF0DQphIHRhYiBzZXR0aW5nIG9mIDggaXMgYmVzdCwgdXN1YWxs
eS4gSG93ZXZlciwgYXMgTGludXMgc2F5cyBpbiBoaXMNCmNvZGluZyBzdHlsZSBkb2N1bWVudCAi
Q29kaW5nIHN0eWxlIGlzIHZlcnkgcGVyc29uYWwsIGFuZCBJIHdvbid0IF9mb3JjZV8NCm15IHZp
ZXdzIG9uIGFueWJvZHkiLg0KDQo+IC4uLiBGaXggeW91ciBlZGl0b3IsIGlmIHRoYXQncyBhbiBp
c3N1ZSBmb3IgeW91Lg0KDQpNeSBlZGl0b3IgaGFzIGEgdGFiIHNldHRpbmcgb2YgOCwgYnV0IHJl
YWRlcnMgb2YgdGhpcyBsaXN0IGhhdmUgZGl2ZXJzZQ0KZW1haWwgY2xpZW50cywgc29tZSBvZiB3
aGljaCBkbyBub3QgZGlzcGxheSA4IHNwYWNlcyBwZXIgdGFiLg0KDQpDbGl2ZQ0K

^ permalink raw reply

* RE: [PATCH 1/3] mtd/nand: fix coding style issue in drivers/mtd/nand/fsl_elbc.c
From: David Woodhouse @ 2011-11-15 13:10 UTC (permalink / raw)
  To: Jenkins, Clive
  Cc: Artem.Bityutskiy, b35362, linux-kernel, linux-mtd, scottwood,
	akpm, linuxppc-dev
In-Reply-To: <929D3CED81F34E43887A393170D66FB9053A8C82@GBRSUN01MS002.eu.xerox.net>

[-- Attachment #1: Type: text/plain, Size: 536 bytes --]

On Tue, 2011-11-15 at 11:26 +0000, Jenkins, Clive wrote:
> > fix whitespaces,tabs coding style issue and ...
> 
> In my opinion this code was already correct, and would display correctly
> at any TAB setting. This patch changes it so that it displays
> incorrectly at all TAB settings other than 8.

Any tab setting other than 8 is incorrect and should not be used for
Linux code. If I view it in a proportionally-spaced font, it's not going
to line up right either. Fix your editor, if that's an issue for you.

-- 
dwmw2

[-- Attachment #2: smime.p7s --]
[-- Type: application/x-pkcs7-signature, Size: 5818 bytes --]

^ permalink raw reply

* RE: [PATCH 1/3] mtd/nand: fix coding style issue in drivers/mtd/nand/fsl_elbc.c
From: Jenkins, Clive @ 2011-11-15 11:26 UTC (permalink / raw)
  To: b35362, dwmw2, Artem.Bityutskiy
  Cc: scottwood, linuxppc-dev, akpm, linux-mtd, linux-kernel
In-Reply-To: <1321349355-1639-1-git-send-email-b35362@freescale.com>

> fix whitespaces,tabs coding style issue and ...

In my opinion this code was already correct, and would display correctly
at any TAB setting. This patch changes it so that it displays
incorrectly
at all TAB settings other than 8.

Example:

Correct:
<tabs>function(arg1,
<tabs><9spaces>arg2

Incorrect:
<tabs>function(arg1,
<tabs>< tab  > arg2

For any TAB setting other than 8, arg1 and arg2 no longer line up.

Clive

^ permalink raw reply

* [PATCH 1/3] mtd/nand: fix coding style issue in drivers/mtd/nand/fsl_elbc.c
From: b35362 @ 2011-11-15  9:29 UTC (permalink / raw)
  To: dwmw2, Artem.Bityutskiy
  Cc: Liu Shuo, linux-kernel, linux-mtd, scottwood, akpm, linuxppc-dev

From: Liu Shuo <b35362@freescale.com>

fix whitespaces,tabs coding style issue and use #include <linux/io.h> instead of <asm/io.h>
in drivers/mtd/nand/fsl_elbc.c.

Signed-off-by: Liu Shuo <b35362@freescale.com>
Signed-off-by: Li Yang <leoli@freescale.com>
---
 drivers/mtd/nand/fsl_elbc_nand.c |  194 +++++++++++++++++++-------------------
 1 files changed, 97 insertions(+), 97 deletions(-)

diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c
index eedd8ee..1bfcdef 100644
--- a/drivers/mtd/nand/fsl_elbc_nand.c
+++ b/drivers/mtd/nand/fsl_elbc_nand.c
@@ -38,7 +38,7 @@
 #include <linux/mtd/nand_ecc.h>
 #include <linux/mtd/partitions.h>
 
-#include <asm/io.h>
+#include <linux/io.h>
 #include <asm/fsl_lbc.h>
 
 #define MAX_BANKS 8
@@ -167,17 +167,17 @@ static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob)
 	elbc_fcm_ctrl->page = page_addr;
 
 	out_be32(&lbc->fbar,
-	         page_addr >> (chip->phys_erase_shift - chip->page_shift));
+		 page_addr >> (chip->phys_erase_shift - chip->page_shift));
 
 	if (priv->page_size) {
 		out_be32(&lbc->fpar,
-		         ((page_addr << FPAR_LP_PI_SHIFT) & FPAR_LP_PI) |
-		         (oob ? FPAR_LP_MS : 0) | column);
+			 ((page_addr << FPAR_LP_PI_SHIFT) & FPAR_LP_PI) |
+			 (oob ? FPAR_LP_MS : 0) | column);
 		buf_num = (page_addr & 1) << 2;
 	} else {
 		out_be32(&lbc->fpar,
-		         ((page_addr << FPAR_SP_PI_SHIFT) & FPAR_SP_PI) |
-		         (oob ? FPAR_SP_MS : 0) | column);
+			 ((page_addr << FPAR_SP_PI_SHIFT) & FPAR_SP_PI) |
+			 (oob ? FPAR_SP_MS : 0) | column);
 		buf_num = page_addr & 7;
 	}
 
@@ -190,10 +190,10 @@ static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob)
 
 	dev_vdbg(priv->dev, "set_addr: bank=%d, "
 			    "elbc_fcm_ctrl->addr=0x%p (0x%p), "
-	                    "index %x, pes %d ps %d\n",
+			    "index %x, pes %d ps %d\n",
 		 buf_num, elbc_fcm_ctrl->addr, priv->vbase,
 		 elbc_fcm_ctrl->index,
-	         chip->phys_erase_shift, chip->page_shift);
+		 chip->phys_erase_shift, chip->page_shift);
 }
 
 /*
@@ -213,13 +213,13 @@ static int fsl_elbc_run_command(struct mtd_info *mtd)
 		out_be32(&lbc->mdr, elbc_fcm_ctrl->mdr);
 
 	dev_vdbg(priv->dev,
-	         "fsl_elbc_run_command: fmr=%08x fir=%08x fcr=%08x\n",
-	         in_be32(&lbc->fmr), in_be32(&lbc->fir), in_be32(&lbc->fcr));
+		 "fsl_elbc_run_command: fmr=%08x fir=%08x fcr=%08x\n",
+		 in_be32(&lbc->fmr), in_be32(&lbc->fir), in_be32(&lbc->fcr));
 	dev_vdbg(priv->dev,
-	         "fsl_elbc_run_command: fbar=%08x fpar=%08x "
-	         "fbcr=%08x bank=%d\n",
-	         in_be32(&lbc->fbar), in_be32(&lbc->fpar),
-	         in_be32(&lbc->fbcr), priv->bank);
+		 "fsl_elbc_run_command: fbar=%08x fpar=%08x "
+		 "fbcr=%08x bank=%d\n",
+		 in_be32(&lbc->fbar), in_be32(&lbc->fpar),
+		 in_be32(&lbc->fbcr), priv->bank);
 
 	ctrl->irq_status = 0;
 	/* execute special operation */
@@ -227,7 +227,7 @@ static int fsl_elbc_run_command(struct mtd_info *mtd)
 
 	/* wait for FCM complete flag or timeout */
 	wait_event_timeout(ctrl->irq_wait, ctrl->irq_status,
-	                   FCM_TIMEOUT_MSECS * HZ/1000);
+			   FCM_TIMEOUT_MSECS * HZ/1000);
 	elbc_fcm_ctrl->status = ctrl->irq_status;
 	/* store mdr value in case it was needed */
 	if (elbc_fcm_ctrl->use_mdr)
@@ -237,8 +237,8 @@ static int fsl_elbc_run_command(struct mtd_info *mtd)
 
 	if (elbc_fcm_ctrl->status != LTESR_CC) {
 		dev_info(priv->dev,
-		         "command failed: fir %x fcr %x status %x mdr %x\n",
-		         in_be32(&lbc->fir), in_be32(&lbc->fcr),
+			 "command failed: fir %x fcr %x status %x mdr %x\n",
+			 in_be32(&lbc->fir), in_be32(&lbc->fcr),
 			 elbc_fcm_ctrl->status, elbc_fcm_ctrl->mdr);
 		return -EIO;
 	}
@@ -273,20 +273,20 @@ static void fsl_elbc_do_read(struct nand_chip *chip, int oob)
 
 	if (priv->page_size) {
 		out_be32(&lbc->fir,
-		         (FIR_OP_CM0 << FIR_OP0_SHIFT) |
-		         (FIR_OP_CA  << FIR_OP1_SHIFT) |
-		         (FIR_OP_PA  << FIR_OP2_SHIFT) |
-		         (FIR_OP_CM1 << FIR_OP3_SHIFT) |
-		         (FIR_OP_RBW << FIR_OP4_SHIFT));
+			 (FIR_OP_CM0 << FIR_OP0_SHIFT) |
+			 (FIR_OP_CA  << FIR_OP1_SHIFT) |
+			 (FIR_OP_PA  << FIR_OP2_SHIFT) |
+			 (FIR_OP_CM1 << FIR_OP3_SHIFT) |
+			 (FIR_OP_RBW << FIR_OP4_SHIFT));
 
 		out_be32(&lbc->fcr, (NAND_CMD_READ0 << FCR_CMD0_SHIFT) |
-		                    (NAND_CMD_READSTART << FCR_CMD1_SHIFT));
+				    (NAND_CMD_READSTART << FCR_CMD1_SHIFT));
 	} else {
 		out_be32(&lbc->fir,
-		         (FIR_OP_CM0 << FIR_OP0_SHIFT) |
-		         (FIR_OP_CA  << FIR_OP1_SHIFT) |
-		         (FIR_OP_PA  << FIR_OP2_SHIFT) |
-		         (FIR_OP_RBW << FIR_OP3_SHIFT));
+			 (FIR_OP_CM0 << FIR_OP0_SHIFT) |
+			 (FIR_OP_CA  << FIR_OP1_SHIFT) |
+			 (FIR_OP_PA  << FIR_OP2_SHIFT) |
+			 (FIR_OP_RBW << FIR_OP3_SHIFT));
 
 		if (oob)
 			out_be32(&lbc->fcr, NAND_CMD_READOOB << FCR_CMD0_SHIFT);
@@ -297,7 +297,7 @@ static void fsl_elbc_do_read(struct nand_chip *chip, int oob)
 
 /* cmdfunc send commands to the FCM */
 static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
-                             int column, int page_addr)
+				int column, int page_addr)
 {
 	struct nand_chip *chip = mtd->priv;
 	struct fsl_elbc_mtd *priv = chip->priv;
@@ -320,8 +320,8 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
 	/* fall-through */
 	case NAND_CMD_READ0:
 		dev_dbg(priv->dev,
-		        "fsl_elbc_cmdfunc: NAND_CMD_READ0, page_addr:"
-		        " 0x%x, column: 0x%x.\n", page_addr, column);
+			"fsl_elbc_cmdfunc: NAND_CMD_READ0, page_addr:"
+			" 0x%x, column: 0x%x.\n", page_addr, column);
 
 
 		out_be32(&lbc->fbcr, 0); /* read entire page to enable ECC */
@@ -337,7 +337,7 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
 	/* READOOB reads only the OOB because no ECC is performed. */
 	case NAND_CMD_READOOB:
 		dev_vdbg(priv->dev,
-		         "fsl_elbc_cmdfunc: NAND_CMD_READOOB, page_addr:"
+			 "fsl_elbc_cmdfunc: NAND_CMD_READOOB, page_addr:"
 			 " 0x%x, column: 0x%x.\n", page_addr, column);
 
 		out_be32(&lbc->fbcr, mtd->oobsize - column);
@@ -354,8 +354,8 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
 		dev_vdbg(priv->dev, "fsl_elbc_cmdfunc: NAND_CMD_READID.\n");
 
 		out_be32(&lbc->fir, (FIR_OP_CM0 << FIR_OP0_SHIFT) |
-		                    (FIR_OP_UA  << FIR_OP1_SHIFT) |
-		                    (FIR_OP_RBW << FIR_OP2_SHIFT));
+				    (FIR_OP_UA  << FIR_OP1_SHIFT) |
+				    (FIR_OP_RBW << FIR_OP2_SHIFT));
 		out_be32(&lbc->fcr, NAND_CMD_READID << FCR_CMD0_SHIFT);
 		/* nand_get_flash_type() reads 8 bytes of entire ID string */
 		out_be32(&lbc->fbcr, 8);
@@ -370,8 +370,8 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
 	/* ERASE1 stores the block and page address */
 	case NAND_CMD_ERASE1:
 		dev_vdbg(priv->dev,
-		         "fsl_elbc_cmdfunc: NAND_CMD_ERASE1, "
-		         "page_addr: 0x%x.\n", page_addr);
+			 "fsl_elbc_cmdfunc: NAND_CMD_ERASE1, "
+			 "page_addr: 0x%x.\n", page_addr);
 		set_addr(mtd, 0, page_addr, 0);
 		return;
 
@@ -380,16 +380,16 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
 		dev_vdbg(priv->dev, "fsl_elbc_cmdfunc: NAND_CMD_ERASE2.\n");
 
 		out_be32(&lbc->fir,
-		         (FIR_OP_CM0 << FIR_OP0_SHIFT) |
-		         (FIR_OP_PA  << FIR_OP1_SHIFT) |
-		         (FIR_OP_CM2 << FIR_OP2_SHIFT) |
-		         (FIR_OP_CW1 << FIR_OP3_SHIFT) |
-		         (FIR_OP_RS  << FIR_OP4_SHIFT));
+			 (FIR_OP_CM0 << FIR_OP0_SHIFT) |
+			 (FIR_OP_PA  << FIR_OP1_SHIFT) |
+			 (FIR_OP_CM2 << FIR_OP2_SHIFT) |
+			 (FIR_OP_CW1 << FIR_OP3_SHIFT) |
+			 (FIR_OP_RS  << FIR_OP4_SHIFT));
 
 		out_be32(&lbc->fcr,
-		         (NAND_CMD_ERASE1 << FCR_CMD0_SHIFT) |
-		         (NAND_CMD_STATUS << FCR_CMD1_SHIFT) |
-		         (NAND_CMD_ERASE2 << FCR_CMD2_SHIFT));
+			 (NAND_CMD_ERASE1 << FCR_CMD0_SHIFT) |
+			 (NAND_CMD_STATUS << FCR_CMD1_SHIFT) |
+			 (NAND_CMD_ERASE2 << FCR_CMD2_SHIFT));
 
 		out_be32(&lbc->fbcr, 0);
 		elbc_fcm_ctrl->read_bytes = 0;
@@ -403,8 +403,8 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
 		__be32 fcr;
 		dev_vdbg(priv->dev,
 			 "fsl_elbc_cmdfunc: NAND_CMD_SEQIN/PAGE_PROG, "
-		         "page_addr: 0x%x, column: 0x%x.\n",
-		         page_addr, column);
+			 "page_addr: 0x%x, column: 0x%x.\n",
+			 page_addr, column);
 
 		elbc_fcm_ctrl->column = column;
 		elbc_fcm_ctrl->oob = 0;
@@ -416,23 +416,23 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
 
 		if (priv->page_size) {
 			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) |
-			         (FIR_OP_CM3 << FIR_OP4_SHIFT) |
-			         (FIR_OP_CW1 << FIR_OP5_SHIFT) |
-			         (FIR_OP_RS  << FIR_OP6_SHIFT));
+				 (FIR_OP_CM2 << FIR_OP0_SHIFT) |
+				 (FIR_OP_CA  << FIR_OP1_SHIFT) |
+				 (FIR_OP_PA  << FIR_OP2_SHIFT) |
+				 (FIR_OP_WB  << FIR_OP3_SHIFT) |
+				 (FIR_OP_CM3 << FIR_OP4_SHIFT) |
+				 (FIR_OP_CW1 << FIR_OP5_SHIFT) |
+				 (FIR_OP_RS  << FIR_OP6_SHIFT));
 		} else {
 			out_be32(&lbc->fir,
-			         (FIR_OP_CM0 << FIR_OP0_SHIFT) |
-			         (FIR_OP_CM2 << FIR_OP1_SHIFT) |
-			         (FIR_OP_CA  << FIR_OP2_SHIFT) |
-			         (FIR_OP_PA  << 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));
+				 (FIR_OP_CM0 << FIR_OP0_SHIFT) |
+				 (FIR_OP_CM2 << FIR_OP1_SHIFT) |
+				 (FIR_OP_CA  << FIR_OP2_SHIFT) |
+				 (FIR_OP_PA  << 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));
 
 			if (column >= mtd->writesize) {
 				/* OOB area --> READOOB */
@@ -454,7 +454,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: {
 		dev_vdbg(priv->dev,
-		         "fsl_elbc_cmdfunc: NAND_CMD_PAGEPROG "
+			 "fsl_elbc_cmdfunc: NAND_CMD_PAGEPROG "
 			 "writing %d bytes.\n", elbc_fcm_ctrl->index);
 
 		/* if the write did not start at 0 or is not a full page
@@ -475,8 +475,8 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
 	/* Note - it does not wait for the ready line */
 	case NAND_CMD_STATUS:
 		out_be32(&lbc->fir,
-		         (FIR_OP_CM0 << FIR_OP0_SHIFT) |
-		         (FIR_OP_RBW << FIR_OP1_SHIFT));
+			 (FIR_OP_CM0 << FIR_OP0_SHIFT) |
+			 (FIR_OP_RBW << FIR_OP1_SHIFT));
 		out_be32(&lbc->fcr, NAND_CMD_STATUS << FCR_CMD0_SHIFT);
 		out_be32(&lbc->fbcr, 1);
 		set_addr(mtd, 0, 0, 0);
@@ -500,8 +500,8 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
 
 	default:
 		dev_err(priv->dev,
-		        "fsl_elbc_cmdfunc: error, unsupported command 0x%x.\n",
-		        command);
+			"fsl_elbc_cmdfunc: error, unsupported command 0x%x.\n",
+			command);
 	}
 }
 
@@ -530,8 +530,8 @@ static void fsl_elbc_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
 
 	if ((unsigned int)len > bufsize - elbc_fcm_ctrl->index) {
 		dev_err(priv->dev,
-		        "write_buf beyond end of buffer "
-		        "(%d requested, %u available)\n",
+			"write_buf beyond end of buffer "
+			"(%d requested, %u available)\n",
 			len, bufsize - elbc_fcm_ctrl->index);
 		len = bufsize - elbc_fcm_ctrl->index;
 	}
@@ -587,9 +587,9 @@ static void fsl_elbc_read_buf(struct mtd_info *mtd, u8 *buf, int len)
 
 	if (len > avail)
 		dev_err(priv->dev,
-		        "read_buf beyond end of buffer "
-		        "(%d requested, %d available)\n",
-		        len, avail);
+			"read_buf beyond end of buffer "
+			"(%d requested, %d available)\n",
+			len, avail);
 }
 
 /*
@@ -661,44 +661,44 @@ static int fsl_elbc_chip_init_tail(struct mtd_info *mtd)
 
 	/* add to ECCM mode set in fsl_elbc_init */
 	priv->fmr |= (12 << FMR_CWTO_SHIFT) |  /* Timeout > 12 ms */
-	             (al << FMR_AL_SHIFT);
+		     (al << FMR_AL_SHIFT);
 
 	dev_dbg(priv->dev, "fsl_elbc_init: nand->numchips = %d\n",
-	        chip->numchips);
+		chip->numchips);
 	dev_dbg(priv->dev, "fsl_elbc_init: nand->chipsize = %lld\n",
-	        chip->chipsize);
+		chip->chipsize);
 	dev_dbg(priv->dev, "fsl_elbc_init: nand->pagemask = %8x\n",
-	        chip->pagemask);
+		chip->pagemask);
 	dev_dbg(priv->dev, "fsl_elbc_init: nand->chip_delay = %d\n",
-	        chip->chip_delay);
+		chip->chip_delay);
 	dev_dbg(priv->dev, "fsl_elbc_init: nand->badblockpos = %d\n",
-	        chip->badblockpos);
+		chip->badblockpos);
 	dev_dbg(priv->dev, "fsl_elbc_init: nand->chip_shift = %d\n",
-	        chip->chip_shift);
+		chip->chip_shift);
 	dev_dbg(priv->dev, "fsl_elbc_init: nand->page_shift = %d\n",
-	        chip->page_shift);
+		chip->page_shift);
 	dev_dbg(priv->dev, "fsl_elbc_init: nand->phys_erase_shift = %d\n",
-	        chip->phys_erase_shift);
+		chip->phys_erase_shift);
 	dev_dbg(priv->dev, "fsl_elbc_init: nand->ecclayout = %p\n",
-	        chip->ecclayout);
+		chip->ecclayout);
 	dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.mode = %d\n",
-	        chip->ecc.mode);
+		chip->ecc.mode);
 	dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.steps = %d\n",
-	        chip->ecc.steps);
+		chip->ecc.steps);
 	dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.bytes = %d\n",
-	        chip->ecc.bytes);
+		chip->ecc.bytes);
 	dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.total = %d\n",
-	        chip->ecc.total);
+		chip->ecc.total);
 	dev_dbg(priv->dev, "fsl_elbc_init: nand->ecc.layout = %p\n",
-	        chip->ecc.layout);
+		chip->ecc.layout);
 	dev_dbg(priv->dev, "fsl_elbc_init: mtd->flags = %08x\n", mtd->flags);
 	dev_dbg(priv->dev, "fsl_elbc_init: mtd->size = %lld\n", mtd->size);
 	dev_dbg(priv->dev, "fsl_elbc_init: mtd->erasesize = %d\n",
-	        mtd->erasesize);
+		mtd->erasesize);
 	dev_dbg(priv->dev, "fsl_elbc_init: mtd->writesize = %d\n",
-	        mtd->writesize);
+		mtd->writesize);
 	dev_dbg(priv->dev, "fsl_elbc_init: mtd->oobsize = %d\n",
-	        mtd->oobsize);
+		mtd->oobsize);
 
 	/* adjust Option Register and ECC to match Flash page size */
 	if (mtd->writesize == 512) {
@@ -712,14 +712,14 @@ static int fsl_elbc_chip_init_tail(struct mtd_info *mtd)
 		    BR_DECC_CHK_GEN) {
 			chip->ecc.size = 512;
 			chip->ecc.layout = (priv->fmr & FMR_ECCM) ?
-			                   &fsl_elbc_oob_lp_eccm1 :
-			                   &fsl_elbc_oob_lp_eccm0;
+					   &fsl_elbc_oob_lp_eccm1 :
+					   &fsl_elbc_oob_lp_eccm0;
 			chip->badblock_pattern = &largepage_memorybased;
 		}
 	} else {
 		dev_err(priv->dev,
-		        "fsl_elbc_init: page size %d is not supported\n",
-		        mtd->writesize);
+			"fsl_elbc_init: page size %d is not supported\n",
+			mtd->writesize);
 		return -1;
 	}
 
@@ -727,9 +727,9 @@ static int fsl_elbc_chip_init_tail(struct mtd_info *mtd)
 }
 
 static int fsl_elbc_read_page(struct mtd_info *mtd,
-                              struct nand_chip *chip,
-			      uint8_t *buf,
-			      int page)
+				struct nand_chip *chip,
+				uint8_t *buf,
+				int page)
 {
 	fsl_elbc_read_buf(mtd, buf, mtd->writesize);
 	fsl_elbc_read_buf(mtd, chip->oob_poi, mtd->oobsize);
@@ -744,8 +744,8 @@ static int fsl_elbc_read_page(struct mtd_info *mtd,
  * waitfunc.
  */
 static void fsl_elbc_write_page(struct mtd_info *mtd,
-                                struct nand_chip *chip,
-                                const uint8_t *buf)
+				 struct nand_chip *chip,
+				 const uint8_t *buf)
 {
 	fsl_elbc_write_buf(mtd, buf, mtd->writesize);
 	fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
-- 
1.7.1

^ permalink raw reply related

* [PATCH 2/3] mtd/nand : set Nand flash page address to FBAR and FPAR correctly
From: b35362 @ 2011-11-15  9:29 UTC (permalink / raw)
  To: dwmw2, Artem.Bityutskiy
  Cc: Jerry Huang, Liu Shuo, linux-kernel, Tang Yuantian, linux-mtd,
	scottwood, akpm, linuxppc-dev
In-Reply-To: <1321349355-1639-1-git-send-email-b35362@freescale.com>

From: Liu Shuo <b35362@freescale.com>

If we use the Nand flash chip whose number of pages in a block is greater
than 64(for large page), we must treat the low bit of FBAR as being the
high bit of the page address due to the limitation of FCM, it simply uses
the low 6-bits (for large page) of the combined block/page address as the
FPAR component, rather than considering the actual block size.

Signed-off-by: Liu Shuo <b35362@freescale.com>
Signed-off-by: Jerry Huang <Chang-Ming.Huang@freescale.com>
Signed-off-by: Tang Yuantian <b29983@freescale.com>
Signed-off-by: Li Yang <leoli@freescale.com>
---
 drivers/mtd/nand/fsl_elbc_nand.c |   13 ++++++++++---
 1 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c
index 1bfcdef..c2c231b 100644
--- a/drivers/mtd/nand/fsl_elbc_nand.c
+++ b/drivers/mtd/nand/fsl_elbc_nand.c
@@ -166,15 +166,22 @@ static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob)
 
 	elbc_fcm_ctrl->page = page_addr;
 
-	out_be32(&lbc->fbar,
-		 page_addr >> (chip->phys_erase_shift - chip->page_shift));
-
 	if (priv->page_size) {
+		/*
+		 * large page size chip : FPAR[PI] save the lowest 6 bits,
+		 *                        FBAR[BLK] save the other bits.
+		 */
+		out_be32(&lbc->fbar, page_addr >> 6);
 		out_be32(&lbc->fpar,
 			 ((page_addr << FPAR_LP_PI_SHIFT) & FPAR_LP_PI) |
 			 (oob ? FPAR_LP_MS : 0) | column);
 		buf_num = (page_addr & 1) << 2;
 	} else {
+		/*
+		 * small page size chip : FPAR[PI] save the lowest 5 bits,
+		 *                        FBAR[BLK] save the other bits.
+		 */
+		out_be32(&lbc->fbar, page_addr >> 5);
 		out_be32(&lbc->fpar,
 			 ((page_addr << FPAR_SP_PI_SHIFT) & FPAR_SP_PI) |
 			 (oob ? FPAR_SP_MS : 0) | column);
-- 
1.7.1

^ permalink raw reply related

* [PATCH v3 3/3] mtd/nand : workaround for Freescale FCM to support large-page Nand chip
From: b35362 @ 2011-11-15  9:29 UTC (permalink / raw)
  To: dwmw2, Artem.Bityutskiy
  Cc: Liu Shuo, linux-kernel, Liu Shuo, Shengzhou Liu, linux-mtd,
	scottwood, akpm, linuxppc-dev
In-Reply-To: <1321349355-1639-2-git-send-email-b35362@freescale.com>

From: Liu Shuo <b35362@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>
Signed-off-by: Shengzhou Liu <Shengzhou.Liu@freescale.com>
Signed-off-by: Li Yang <leoli@freescale.com>
---
 drivers/mtd/nand/fsl_elbc_nand.c |  216 +++++++++++++++++++++++++++++++++++---
 1 files changed, 199 insertions(+), 17 deletions(-)

diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c
index c2c231b..415f87e 100644
--- a/drivers/mtd/nand/fsl_elbc_nand.c
+++ b/drivers/mtd/nand/fsl_elbc_nand.c
@@ -55,7 +55,9 @@ 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)    */
+	int page_size;          /* NAND page size (0=512, 1=2048, 2=4096...),
+				 * the mutiple of 2048.
+				 */
 	unsigned int fmr;       /* FCM Flash Mode Register value     */
 };
 
@@ -75,6 +77,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 +154,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);
+}
 
 /*
  * Set up the FCM hardware block and page address fields, and the fcm
@@ -193,7 +233,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), "
@@ -311,6 +351,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;
 
 	elbc_fcm_ctrl->use_mdr = 0;
 
@@ -339,21 +380,63 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
 
 		fsl_elbc_do_read(chip, 0);
 		fsl_elbc_run_command(mtd);
-		return;
 
+		if (priv->page_size <= 1)
+			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);
+
+		for (i = 1; i < priv->page_size; i++) {
+			/*
+			 * Maybe there are some reasons of FCM hardware timming,
+			 * 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. */
 	case NAND_CMD_READOOB:
 		dev_vdbg(priv->dev,
 			 "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 (priv->page_size <= 1) {
+			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_run_command(mtd);
+
+		if (priv->page_size <= 1)
+			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);
+
+		for (i = 1; i < priv->page_size; 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 */
@@ -421,7 +504,14 @@ 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 (priv->page_size > 1) {
+			/* 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));
+		} else if (priv->page_size) {
 			out_be32(&lbc->fir,
 				 (FIR_OP_CM2 << FIR_OP0_SHIFT) |
 				 (FIR_OP_CA  << FIR_OP1_SHIFT) |
@@ -454,27 +544,76 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
 		}
 
 		out_be32(&lbc->fcr, fcr);
-		set_addr(mtd, column, page_addr, elbc_fcm_ctrl->oob);
+		if (column >= mtd->writesize && priv->page_size > 1) {
+			/* write oob && writesize > 2048 */
+			set_addr(mtd, 0, page_addr, 0);
+			elbc_fcm_ctrl->index = column;
+		} else {
+			set_addr(mtd, column, page_addr, elbc_fcm_ctrl->oob);
+		}
+
 		return;
 	}
 
 	/* PAGEPROG reuses all of the setup from SEQIN and adds the length */
 	case NAND_CMD_PAGEPROG: {
+		int len;
 		dev_vdbg(priv->dev,
 			 "fsl_elbc_cmdfunc: NAND_CMD_PAGEPROG "
 			 "writing %d bytes.\n", elbc_fcm_ctrl->index);
-
 		/* if the write did not start at 0 or is not a full page
 		 * then set the exact length, otherwise use a full page
 		 * write so the HW generates the ECC.
 		 */
-		if (elbc_fcm_ctrl->oob || elbc_fcm_ctrl->column != 0 ||
+		if (elbc_fcm_ctrl->column >= mtd->writesize) {
+			/* write oob */
+			if (priv->page_size > 1) {
+				/* when pagesize of chip is greater than 2048,
+				 * we have to write full page to write spare
+				 * region, so we fill '0xff' to main region
+				 * and some bytes of spare region which we
+				 * don't want to rewrite.
+				 * (write '1' won't change the original value)
+				 */
+				memset(elbc_fcm_ctrl->buffer, 0xff,
+						elbc_fcm_ctrl->column);
+				len = 2112;
+			} else
+				len = mtd->writesize + mtd->oobsize -
+					elbc_fcm_ctrl->column;
+			out_be32(&lbc->fbcr, len);
+		} else if (elbc_fcm_ctrl->column != 0 ||
 		    elbc_fcm_ctrl->index != mtd->writesize + mtd->oobsize)
 			out_be32(&lbc->fbcr, elbc_fcm_ctrl->index);
 		else
 			out_be32(&lbc->fbcr, 0);
 
+		if (priv->page_size > 1) {
+			buffer_to_io(mtd, 0, 0);
+			buffer_to_io(mtd, 0, 1);
+		}
+
 		fsl_elbc_run_command(mtd);
+
+		if (priv->page_size <= 1)
+			return;
+
+		out_be32(&lbc->fir, FIR_OP_WB << FIR_OP1_SHIFT);
+		for (i = 1; i < priv->page_size; i++) {
+			elbc_fcm_ctrl->use_mdr = 1;
+			/* For the last subpage */
+			if (i == priv->page_size - 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;
 	}
 
@@ -543,7 +682,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
@@ -589,7 +735,12 @@ 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)
@@ -625,10 +776,16 @@ 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;
@@ -657,6 +814,7 @@ static int fsl_elbc_chip_init_tail(struct mtd_info *mtd)
 	struct fsl_elbc_mtd *priv = chip->priv;
 	struct fsl_lbc_ctrl *ctrl = priv->ctrl;
 	struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
+	struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = ctrl->nand;
 	unsigned int al;
 
 	/* calculate FMR Address Length field */
@@ -707,12 +865,17 @@ static int fsl_elbc_chip_init_tail(struct mtd_info *mtd)
 	dev_dbg(priv->dev, "fsl_elbc_init: mtd->oobsize = %d\n",
 		mtd->oobsize);
 
+	kfree(elbc_fcm_ctrl->buffer);
+	elbc_fcm_ctrl->buffer = NULL;
+
 	/* 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) {
+		/* page_size = writesize / 2048 */
+		priv->page_size = mtd->writesize >> 11;
+
 		setbits32(&lbc->bank[priv->bank].or, OR_FCM_PGS);
 		/* adjust ecc setup if needed */
 		if ((in_be32(&lbc->bank[priv->bank].br) & BR_DECC) ==
@@ -723,6 +886,14 @@ static int fsl_elbc_chip_init_tail(struct mtd_info *mtd)
 					   &fsl_elbc_oob_lp_eccm0;
 			chip->badblock_pattern = &largepage_memorybased;
 		}
+
+		/* re-malloc if pagesize > 2048*/
+		if (mtd->writesize > 2048) {
+			elbc_fcm_ctrl->buffer = kmalloc(mtd->writesize +
+						    mtd->oobsize, GFP_KERNEL);
+			if (!elbc_fcm_ctrl->buffer)
+				return -ENOMEM;
+		}
 	} else {
 		dev_err(priv->dev,
 			"fsl_elbc_init: page size %d is not supported\n",
@@ -886,6 +1057,17 @@ 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 at this point, because we
+		 * don't know writesize before calling nand_scan(). We will
+		 * re-malloc later if needed.
+		 */
+		elbc_fcm_ctrl->buffer = kmalloc(4096 * 6, GFP_KERNEL);
+		if (!elbc_fcm_ctrl->buffer)
+			return -ENOMEM;
 
 		spin_lock_init(&elbc_fcm_ctrl->controller.lock);
 		init_waitqueue_head(&elbc_fcm_ctrl->controller.wq);
-- 
1.7.1

^ permalink raw reply related

* 3.2.0-rc1 panic on PowerPC
From: Christian Kujau @ 2011-11-15  8:44 UTC (permalink / raw)
  To: LKML; +Cc: linuxppc-dev

Hi,

I noticed a few crashes on this PowerBook G4 lately, starting somewhere in 
3.2.0-rc1. The crashes are really rare and as I'm not on the system all 
the time I did not notice most of them. By the time I did, the screen was 
blank already and I had to hard-reset the box. But not this time:

  http://nerdbynature.de/bits/3.2.0-rc1/oops/

When the crash occured, the system was failry loaded (CPU and disk I/O 
wise), so that may have triggered it. I tried to type off the stack trace, 
I hope there are not too many typos, see below.

The machine is fairly old, so maybe it's "just" bad RAM or something, I 
wouldn't be suprised. But maybe not, the box us pretty stable most of the 
time and only now I notice these rare crashes.

If anyone could take a quick look...?

Thank you,
Christian.

Instruction dump:
92c40008 68000001 0f000000 80040000 5400003c 90040000 817f000c 380bffff
901f000c 2f090000 81640018 81440014 <916a0004> 914b0000 92840014 92a49918
Kernel panic - not syncing: Fatal exception in interrupt
Call Trace:
show_stack+0x70/0x1bc (unreliable)
panic+0xc8/0x220
die+0x2ac/0x2b8
bad_page_fault+0xbc/0x104
handle_page_fault+0x7c/0x80
Exception: 300 at T.975+0x3f4/0x570
LR = T.957+0x300/0x570
kmem_cache_alloc+0x150/0x150
__aloc_skb+0x50/0x148
tcp_send_ack+0x35/0x138
tcp_delay_timer+0x140/0x244
run_timer_softirq+0x1a0/0x2ec
__do_softirq+0xf4/0x1bc
call_do_softirq+0x14/0x24
do_softirq+0xfc/0x128
irq_exit+0xa0/0xa4
timer_interrupt+0x148/0x180
ret_from_except+0x0/0x14
cpu_idle+0xa0/0x118
rest_init+0xf0/0x114
start_kernel+0x2d0/0x2f0
0x3444
Rebooting in 180 seconds..

-- 
BOFH excuse #184:

loop found in loop in redundant loopback

^ permalink raw reply

* Re: [PATCH] net: fsl_pq_mdio: fix non tbi phy access
From: Baruch Siach @ 2011-11-15  5:17 UTC (permalink / raw)
  To: Fleming Andy-AFLEMING; +Cc: netdev@vger.kernel.org, linuxppc-dev
In-Reply-To: <C89A2124-7AB4-45B6-ACD1-8C5936027531@freescale.com>

Hi Andy,

On Mon, Nov 14, 2011 at 09:04:47PM +0000, Fleming Andy-AFLEMING wrote:
> Well, this got applied quickly, so I guess I can't NAK, but this requires discussion.
> 
> On Nov 14, 2011, at 0:22, "Baruch Siach" <baruch@tkos.co.il> wrote:
> 
> > Since 952c5ca1 (fsl_pq_mdio: Clean up tbi address configuration) .probe returns
> > -EBUSY when the "tbi-phy" node is missing. Fix this.
> 
> It returns an error because it finds no tbi node. Because without the tbi 
> node, there is no way for the driver to determine which address to set.
> 
> Your solution is to ignore the error, and hope. That's a broken approach.  
> The real solution for a p1010 should be to have a tbi node in the dts.

Can you elaborate a bit on why this approach is broken? The PHY used to work 
for me until 952c5ca1, and with this applied.

> And looking at the p1010si.dtsi, I see that it's automatically there for 
> you.
> 
> How were you breaking?

Adding linuxppc to Cc.

My board is P1011 based, the single core version of P1020, not P1010. In 
p1020si.dtsi I see no tbi node. In p1020rdb.dts I see a tbi node but only for 
mdio@25000, not mdio@24000, which is what I'm using.

Am I missing something?

baruch

-- 
                                                     ~. .~   Tk Open Systems
=}------------------------------------------------ooO--U--Ooo------------{=
   - baruch@tkos.co.il - tel: +972.2.679.5364, http://www.tkos.co.il -

^ permalink raw reply

* Re: [RFC PATCH 00/17] powerpc/e500: separate e500 from e500mc
From: Kyle Moffett @ 2011-11-15  3:40 UTC (permalink / raw)
  To: Tabi Timur-B04825
  Cc: Wood Scott-B07421, linux-kernel@vger.kernel.org, Paul Gortmaker,
	Moffett, Kyle D, linuxppc-dev@lists.ozlabs.org
In-Reply-To: <4EC1D15E.3010800@freescale.com>

On Mon, Nov 14, 2011 at 21:41, Tabi Timur-B04825 <B04825@freescale.com> wrote:
> Moffett, Kyle D wrote:
>>the PPC Book-E spec documents that the pagesize is an even multiple
>> of the cacheline size and the cachelines are always page-aligned.
>
> cachelines are page aligned?

Whoops, good catch.  That should have been:

"the PPC Book-E spec documents that the pagesize is an even multiple
of the cacheline size and that the pages are always cacheline-aligned."

Thanks!

Cheers,
Kyle Moffett

-- 
Curious about my work on the Debian powerpcspe port?
I'm keeping a blog here: http://pureperl.blogspot.com/

^ permalink raw reply

* RE: [PATCH 4/5, v3] powerpc/8xxx: Update device tree bus probe for new RapidIO node binding
From: Liu Gang-B34182 @ 2011-11-15  3:21 UTC (permalink / raw)
  To: Wood Scott-B07421
  Cc: Li Yang-R58472, 'linux-kernel@vger.kernel.org',
	Zang Roy-R61911, 'Alexandre.Bounine@idt.com',
	Jiang Kai-B18973, 'akpm@linux-foundation.org',
	'linuxppc-dev@lists.ozlabs.org', Gala Kumar-B11780
In-Reply-To: <4EC151D5.3040900@freescale.com>

Yeah, send binding first should be better for reviewing entire set of patch=
es.
Thanks!

-----Original Message-----
From: Wood Scott-B07421=20
Sent: Tuesday, November 15, 2011 1:37 AM
To: Liu Gang-B34182
Cc: Li Yang-R58472; Jiang Kai-B18973; linux-kernel@vger.kernel.org; Zang Ro=
y-R61911; Alexandre.Bounine@idt.com; akpm@linux-foundation.org; linuxppc-de=
v@lists.ozlabs.org; Gala Kumar-B11780
Subject: Re: [PATCH 4/5, v3] powerpc/8xxx: Update device tree bus probe for=
 new RapidIO node binding

On 11/14/2011 11:35 AM, Scott Wood wrote:
> On 11/12/2011 06:02 AM, Liu Gang wrote:
>> From: Kai Jiang <Kai.Jiang@freescale.com>
>>
>> Update of_platform_bus_probe() RapidIO node to be compitable with new=20
>> RapidIO dts compatible property.
>>
>> Signed-off-by: Kai Jiang <Kai.Jiang@freescale.com>
>> Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
>> ---
>>  arch/powerpc/platforms/85xx/corenet_ds.c   |    2 +-
>>  arch/powerpc/platforms/85xx/mpc85xx_mds.c  |    2 +-
>>  arch/powerpc/platforms/86xx/mpc86xx_hpcn.c |    2 +-
>>  3 files changed, 3 insertions(+), 3 deletions(-)
>>
>> diff --git a/arch/powerpc/platforms/85xx/corenet_ds.c=20
>> b/arch/powerpc/platforms/85xx/corenet_ds.c
>> index 802ad11..c48b661 100644
>> --- a/arch/powerpc/platforms/85xx/corenet_ds.c
>> +++ b/arch/powerpc/platforms/85xx/corenet_ds.c
>> @@ -112,7 +112,7 @@ static const struct of_device_id of_device_ids[] __d=
evinitconst =3D {
>>  		.compatible	=3D "simple-bus"
>>  	},
>>  	{
>> -		.compatible	=3D "fsl,rapidio-delta",
>> +		.compatible	=3D "fsl,srio",
>=20
> fsl,srio is too vague.  We need to identify the specific hardware (or=20
> at least a concrete programming interface document), not just the bus =20
> that the hardware implements.

Never mind, I see that the binding is more specific about what this string =
means.

Next time have the binding come first. :-)

-Scott

^ permalink raw reply

* Re: [RFC PATCH 00/17] powerpc/e500: separate e500 from e500mc
From: Moffett, Kyle D @ 2011-11-15  2:36 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: Timur Tabi, linux-kernel@vger.kernel.org, Paul Gortmaker,
	Scott Wood, linuxppc-dev@lists.ozlabs.org
In-Reply-To: <1320986410.21206.48.camel@pasglop>

On Nov 10, 2011, at 23:40, Benjamin Herrenschmidt wrote:
> On Thu, 2011-11-10 at 18:38 -0600, Moffett, Kyle D wrote:
>>  (2) Make the ppc64_caches struct apply to ppc32 as well, and
>>      preinitialize it with a minimum value used by any platform being
>>      compiled in (for "dcbXX"/"icbXX" purposes).  This is safe because
>>      the pagesize is always a multiple of the cache block size and the
>>      kernel only uses dcbXX/icbXX on whole pages.  The only impact is a
>>      temporary small performance hit from flushing or zeroing the same
>>      block 8 times if too small.
>=20
> Are you sure about dcbz ? Getting that wrong can be deadly ... I'd
> rather get rid of some fancy optims and use a soft value in some cases.
> That or we can compile multiple variants for the common case of some of
> the copy routines and use patching (alternate sections) to branch to the
> right one at runtime, at least for the common cases (32 and 128 for
> example for 440 and 476).

Well, all of the kernel loops that use dcbz are operating on whole pages,
and the PPC Book-E spec documents that the pagesize is an even multiple
of the cacheline size and the cachelines are always page-aligned.

So when you are clearing a whole page, there are only 2 things you can do
wrong with "dcbz":

  (1) Call "dcbz" with an address outside of the page you want to zero.

  (2) Omit calls "dcbz" to dcbz for some physical cachelines in the page.

Now, that's a totally different story from the userspace memset() calls
that caused the problem originally, because they were frequently given
memory much smaller than a page to clear, and if you didn't know exactly
how many bytes a "dcbz" was going to clear you couldn't use it at all.

But the kernel doesn't do that anywhere, it just uses it for page clears.

Cheers,
Kyle Moffett

--
Curious about my work on the Debian powerpcspe port?
I'm keeping a blog here: http://pureperl.blogspot.com/

^ permalink raw reply

* [UPDATED] [PATCH v3 1/8] [44x] Fix typo in KEXEC CONFIG dependency
From: Suzuki K. Poulose @ 2011-11-15  2:43 UTC (permalink / raw)
  To: linux-ppc dev, Josh Boyer; +Cc: Paul Bolle
In-Reply-To: <20111114054129.23410.57513.stgit@suzukikp.in.ibm.com>

Kexec is not supported on 47x. 47x is a variant of 44x with slightly
different MMU and SMP support. There was a typo in the config
dependency for KEXEC. This patch fixes the same.

Signed-off-by: Suzuki K. Poulose <suzuki@in.ibm.com>
Signed-off-by: Paul Bolle <pebolle@tiscali.nl>
Cc:	Kumar Gala <galak@kernel.crashing.org>
Cc:	Josh Boyer <jwboyer@gmail.com>
Cc:	linux ppc dev <linuxppc-dev@lists.ozlabs.org>
---

 arch/powerpc/Kconfig          |    2 +-
 arch/powerpc/kernel/misc_32.S |    2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 8523bd1..d7c2d1a 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -345,7 +345,7 @@ config ARCH_ENABLE_MEMORY_HOTREMOVE
 
 config KEXEC
 	bool "kexec system call (EXPERIMENTAL)"
-	depends on (PPC_BOOK3S || FSL_BOOKE || (44x && !SMP && !47x)) && EXPERIMENTAL
+	depends on (PPC_BOOK3S || FSL_BOOKE || (44x && !SMP && !PPC_47x)) && EXPERIMENTAL
 	help
 	  kexec is a system call that implements the ability to shutdown your
 	  current kernel, and to start another kernel.  It is like a reboot
diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S
index f7d760a..7cd07b4 100644
--- a/arch/powerpc/kernel/misc_32.S
+++ b/arch/powerpc/kernel/misc_32.S
@@ -738,7 +738,7 @@ relocate_new_kernel:
 	mr      r5, r31
 
 	li	r0, 0
-#elif defined(CONFIG_44x)  && !defined(CONFIG_47x)
+#elif defined(CONFIG_44x)  && !defined(CONFIG_PPC_47x)
 
 /*
  * Code for setting up 1:1 mapping for PPC440x for KEXEC

^ permalink raw reply related

* Re: [RFC PATCH 00/17] powerpc/e500: separate e500 from e500mc
From: Tabi Timur-B04825 @ 2011-11-15  2:41 UTC (permalink / raw)
  To: Moffett, Kyle D
  Cc: Wood Scott-B07421, linux-kernel@vger.kernel.org, Paul Gortmaker,
	linuxppc-dev@lists.ozlabs.org
In-Reply-To: <4A0007C2-1C2C-4162-98E8-ACCA4E673AFE@boeing.com>

Moffett, Kyle D wrote:
>the PPC Book-E spec documents that the pagesize is an even multiple
> of the cacheline size and the cachelines are always page-aligned.

cachelines are page aligned?

--=20
Timur Tabi
Linux kernel developer at Freescale=

^ permalink raw reply

* [RFC PATCH 1/2] powerpc: Remove duplicate cacheable_memcpy/memzero functions
From: Kyle Moffett @ 2011-11-15  2:32 UTC (permalink / raw)
  To: linuxppc-dev
  Cc: Mike Frysinger, Ian Campbell, Eric Dumazet, Jiri Pirko, B04825,
	linux-kernel, Milton Miller, paul.gortmaker, netdev,
	Paul Mackerras, Anton Blanchard, Kyle Moffett, Oleg Nesterov,
	scottwood, Andrew Morton, linuxppc-dev, David S. Miller,
	Jeff Kirsher
In-Reply-To: <1320986410.21206.48.camel@pasglop>

These functions are only used from one place each.  If the cacheable_*
versions really are more efficient, then those changes should be
migrated into the common code instead.

NOTE: The old routines are just flat buggy on kernels that support
      hardware with different cacheline sizes.

Signed-off-by: Kyle Moffett <Kyle.D.Moffett@boeing.com>
---
 arch/powerpc/include/asm/system.h    |    2 -
 arch/powerpc/kernel/ppc_ksyms.c      |    2 -
 arch/powerpc/lib/copy_32.S           |  127 ----------------------------------
 arch/powerpc/mm/ppc_mmu_32.c         |    2 +-
 drivers/net/ethernet/ibm/emac/core.c |   12 +---
 5 files changed, 3 insertions(+), 142 deletions(-)

diff --git a/arch/powerpc/include/asm/system.h b/arch/powerpc/include/asm/system.h
index e30a13d..25389d1 100644
--- a/arch/powerpc/include/asm/system.h
+++ b/arch/powerpc/include/asm/system.h
@@ -189,8 +189,6 @@ static inline void flush_spe_to_thread(struct task_struct *t)
 #endif
 
 extern int call_rtas(const char *, int, int, unsigned long *, ...);
-extern void cacheable_memzero(void *p, unsigned int nb);
-extern void *cacheable_memcpy(void *, const void *, unsigned int);
 extern int do_page_fault(struct pt_regs *, unsigned long, unsigned long);
 extern void bad_page_fault(struct pt_regs *, unsigned long, int);
 extern int die(const char *, struct pt_regs *, long);
diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c
index d3114a7..acba8ce 100644
--- a/arch/powerpc/kernel/ppc_ksyms.c
+++ b/arch/powerpc/kernel/ppc_ksyms.c
@@ -159,8 +159,6 @@ EXPORT_SYMBOL(screen_info);
 #ifdef CONFIG_PPC32
 EXPORT_SYMBOL(timer_interrupt);
 EXPORT_SYMBOL(tb_ticks_per_jiffy);
-EXPORT_SYMBOL(cacheable_memcpy);
-EXPORT_SYMBOL(cacheable_memzero);
 #endif
 
 #ifdef CONFIG_PPC32
diff --git a/arch/powerpc/lib/copy_32.S b/arch/powerpc/lib/copy_32.S
index 55f19f9..6813f80 100644
--- a/arch/powerpc/lib/copy_32.S
+++ b/arch/powerpc/lib/copy_32.S
@@ -69,54 +69,6 @@ CACHELINE_BYTES = L1_CACHE_BYTES
 LG_CACHELINE_BYTES = L1_CACHE_SHIFT
 CACHELINE_MASK = (L1_CACHE_BYTES-1)
 
-/*
- * Use dcbz on the complete cache lines in the destination
- * to set them to zero.  This requires that the destination
- * area is cacheable.  -- paulus
- */
-_GLOBAL(cacheable_memzero)
-	mr	r5,r4
-	li	r4,0
-	addi	r6,r3,-4
-	cmplwi	0,r5,4
-	blt	7f
-	stwu	r4,4(r6)
-	beqlr
-	andi.	r0,r6,3
-	add	r5,r0,r5
-	subf	r6,r0,r6
-	clrlwi	r7,r6,32-LG_CACHELINE_BYTES
-	add	r8,r7,r5
-	srwi	r9,r8,LG_CACHELINE_BYTES
-	addic.	r9,r9,-1	/* total number of complete cachelines */
-	ble	2f
-	xori	r0,r7,CACHELINE_MASK & ~3
-	srwi.	r0,r0,2
-	beq	3f
-	mtctr	r0
-4:	stwu	r4,4(r6)
-	bdnz	4b
-3:	mtctr	r9
-	li	r7,4
-10:	dcbz	r7,r6
-	addi	r6,r6,CACHELINE_BYTES
-	bdnz	10b
-	clrlwi	r5,r8,32-LG_CACHELINE_BYTES
-	addi	r5,r5,4
-2:	srwi	r0,r5,2
-	mtctr	r0
-	bdz	6f
-1:	stwu	r4,4(r6)
-	bdnz	1b
-6:	andi.	r5,r5,3
-7:	cmpwi	0,r5,0
-	beqlr
-	mtctr	r5
-	addi	r6,r6,3
-8:	stbu	r4,1(r6)
-	bdnz	8b
-	blr
-
 _GLOBAL(memset)
 	rlwimi	r4,r4,8,16,23
 	rlwimi	r4,r4,16,0,15
@@ -142,85 +94,6 @@ _GLOBAL(memset)
 	bdnz	8b
 	blr
 
-/*
- * This version uses dcbz on the complete cache lines in the
- * destination area to reduce memory traffic.  This requires that
- * the destination area is cacheable.
- * We only use this version if the source and dest don't overlap.
- * -- paulus.
- */
-_GLOBAL(cacheable_memcpy)
-	add	r7,r3,r5		/* test if the src & dst overlap */
-	add	r8,r4,r5
-	cmplw	0,r4,r7
-	cmplw	1,r3,r8
-	crand	0,0,4			/* cr0.lt &= cr1.lt */
-	blt	memcpy			/* if regions overlap */
-
-	addi	r4,r4,-4
-	addi	r6,r3,-4
-	neg	r0,r3
-	andi.	r0,r0,CACHELINE_MASK	/* # bytes to start of cache line */
-	beq	58f
-
-	cmplw	0,r5,r0			/* is this more than total to do? */
-	blt	63f			/* if not much to do */
-	andi.	r8,r0,3			/* get it word-aligned first */
-	subf	r5,r0,r5
-	mtctr	r8
-	beq+	61f
-70:	lbz	r9,4(r4)		/* do some bytes */
-	stb	r9,4(r6)
-	addi	r4,r4,1
-	addi	r6,r6,1
-	bdnz	70b
-61:	srwi.	r0,r0,2
-	mtctr	r0
-	beq	58f
-72:	lwzu	r9,4(r4)		/* do some words */
-	stwu	r9,4(r6)
-	bdnz	72b
-
-58:	srwi.	r0,r5,LG_CACHELINE_BYTES /* # complete cachelines */
-	clrlwi	r5,r5,32-LG_CACHELINE_BYTES
-	li	r11,4
-	mtctr	r0
-	beq	63f
-53:
-	dcbz	r11,r6
-	COPY_16_BYTES
-#if L1_CACHE_BYTES >= 32
-	COPY_16_BYTES
-#if L1_CACHE_BYTES >= 64
-	COPY_16_BYTES
-	COPY_16_BYTES
-#if L1_CACHE_BYTES >= 128
-	COPY_16_BYTES
-	COPY_16_BYTES
-	COPY_16_BYTES
-	COPY_16_BYTES
-#endif
-#endif
-#endif
-	bdnz	53b
-
-63:	srwi.	r0,r5,2
-	mtctr	r0
-	beq	64f
-30:	lwzu	r0,4(r4)
-	stwu	r0,4(r6)
-	bdnz	30b
-
-64:	andi.	r0,r5,3
-	mtctr	r0
-	beq+	65f
-40:	lbz	r0,4(r4)
-	stb	r0,4(r6)
-	addi	r4,r4,1
-	addi	r6,r6,1
-	bdnz	40b
-65:	blr
-
 _GLOBAL(memmove)
 	cmplw	0,r3,r4
 	bgt	backwards_memcpy
diff --git a/arch/powerpc/mm/ppc_mmu_32.c b/arch/powerpc/mm/ppc_mmu_32.c
index 11571e1..9f16b9f 100644
--- a/arch/powerpc/mm/ppc_mmu_32.c
+++ b/arch/powerpc/mm/ppc_mmu_32.c
@@ -224,7 +224,7 @@ void __init MMU_init_hw(void)
 	 */
 	if ( ppc_md.progress ) ppc_md.progress("hash:find piece", 0x322);
 	Hash = __va(memblock_alloc(Hash_size, Hash_size));
-	cacheable_memzero(Hash, Hash_size);
+	memset(Hash, 0, Hash_size);
 	_SDR1 = __pa(Hash) | SDR1_LOW_BITS;
 
 	Hash_end = (struct hash_pte *) ((unsigned long)Hash + Hash_size);
diff --git a/drivers/net/ethernet/ibm/emac/core.c b/drivers/net/ethernet/ibm/emac/core.c
index ed79b2d..be214ad 100644
--- a/drivers/net/ethernet/ibm/emac/core.c
+++ b/drivers/net/ethernet/ibm/emac/core.c
@@ -77,13 +77,6 @@ MODULE_AUTHOR
     ("Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>");
 MODULE_LICENSE("GPL");
 
-/*
- * PPC64 doesn't (yet) have a cacheable_memcpy
- */
-#ifdef CONFIG_PPC64
-#define cacheable_memcpy(d,s,n) memcpy((d),(s),(n))
-#endif
-
 /* minimum number of free TX descriptors required to wake up TX process */
 #define EMAC_TX_WAKEUP_THRESH		(NUM_TX_BUFF / 4)
 
@@ -1637,7 +1630,7 @@ static inline int emac_rx_sg_append(struct emac_instance *dev, int slot)
 			dev_kfree_skb(dev->rx_sg_skb);
 			dev->rx_sg_skb = NULL;
 		} else {
-			cacheable_memcpy(skb_tail_pointer(dev->rx_sg_skb),
+			memcpy(skb_tail_pointer(dev->rx_sg_skb),
 					 dev->rx_skb[slot]->data, len);
 			skb_put(dev->rx_sg_skb, len);
 			emac_recycle_rx_skb(dev, slot, len);
@@ -1694,8 +1687,7 @@ static int emac_poll_rx(void *param, int budget)
 				goto oom;
 
 			skb_reserve(copy_skb, EMAC_RX_SKB_HEADROOM + 2);
-			cacheable_memcpy(copy_skb->data - 2, skb->data - 2,
-					 len + 2);
+			memcpy(copy_skb->data - 2, skb->data - 2, len + 2);
 			emac_recycle_rx_skb(dev, slot, len);
 			skb = copy_skb;
 		} else if (unlikely(emac_alloc_rx_skb(dev, slot, GFP_ATOMIC)))
-- 
1.7.2.5

^ permalink raw reply related

* [RFC PATCH 0/2] powerpc: CPU cache op cleanup
From: Kyle Moffett @ 2011-11-15  2:32 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: B04825, linux-kernel, paul.gortmaker, scottwood
In-Reply-To: <1320986410.21206.48.camel@pasglop>

Ok, so I have a work-in-progress patch for cleaning up the CPU cache
handling, and I'd like some comments on the approach.

It's not really split up, and it's kind of a huge patch because it
tries to tackle a lot of things at once.  Unfortunately, I'm having a
hard time finding good clean places to break things apart.

Furthermore, I know 100% that it is not complete on PPC32 yet, and it
almost certainly does not build on PPC64 yet either.

These are the only files in arch/powerpc/ which have known-incorrect
references to L1_CACHE_* variables:
  arch/powerpc/lib/copy_32.S
  arch/powerpc/kernel/misc_32.S

Unfortunately, I've been staring at PPC asm for long enough that I
have a migraine headache and I'm going to have to stop here for now.
If somebody else wants to tackle fixing up the 32-bit copy_page() and
__copy_tofrom_user() routines it would be highly appreciated.

Cheers,
Kyle Moffett

--
Curious about my work on the Debian powerpcspe port?
I'm keeping a blog here: http://pureperl.blogspot.com/

^ permalink raw reply

* [RFC PATCH 2/2] WIP: PowerPC cache cleanup
From: Kyle Moffett @ 2011-11-15  2:32 UTC (permalink / raw)
  To: linuxppc-dev
  Cc: Dave Kleikamp, Sonny Rao, paul.gortmaker,
	Sebastian Andrzej Siewior, Paul Mackerras, Michel Lespinasse,
	Stephen Rothwell, Andrew Gabbasov, Matt Evans,
	Dmitry Eremin-Solenikov, B04825, Alexander Graf, Stephen Wilson,
	Suzuki Poulose, Kyle Moffett, David Rientjes, Anatolij Gustschin,
	Liu Yu, Mike Frysinger, Lucas De Marchi, devicetree-discuss,
	Rob Herring, Anton Blanchard, scottwood, Andrew Morton,
	David Gibson, Greg Kroah-Hartman, linux-kernel, Milton Miller,
	linuxppc-dev, Al Viro
In-Reply-To: <1320986410.21206.48.camel@pasglop>

This badly needs breaking up, and a better changelog... oh well...

The big changes:

* The "ppc64_caches" structure is now "powerpc_caches" and is used on
  both PPC32 and PPC64.  I hated staring at the pages and pages of
  assembly code, so nearly all of the functions are now C with tiny
  snippets of inline ASM in the loops.

* Lots of ugly assembly functions in arch/powerpc/kernel/misc_*.S were
  rewritten as cleaner inline ASM in arch/powerpc/mm/cache.c

* I'm not sure that the physical address functions from those files
  actually came out cleaner, but they are now more correct.

* I'm not 100% sure I like the new FOR_EACH_CACHE_LINE() macro, but it
  sure does make a lot of the other code much cleaner.

* I have a bit of a temptation to try to merge the 32/64-bit variants
  of copy_page() into a single C function.  A quick test seems to show
  that I can get nearly identical output to the 64-bit ASM with very
  little work.

---
 arch/powerpc/include/asm/cache.h             |  155 ++++++++++++---
 arch/powerpc/include/asm/cacheflush.h        |    3 -
 arch/powerpc/include/asm/page.h              |    6 +
 arch/powerpc/include/asm/page_32.h           |    4 +-
 arch/powerpc/include/asm/page_64.h           |   17 --
 arch/powerpc/kernel/align.c                  |    7 +-
 arch/powerpc/kernel/asm-offsets.c            |   13 +-
 arch/powerpc/kernel/head_32.S                |    9 +-
 arch/powerpc/kernel/head_64.S                |    2 +-
 arch/powerpc/kernel/misc_32.S                |  193 ------------------
 arch/powerpc/kernel/misc_64.S                |  182 -----------------
 arch/powerpc/kernel/ppc_ksyms.c              |    3 -
 arch/powerpc/kernel/setup-common.c           |  103 ++++++++++
 arch/powerpc/kernel/setup.h                  |    1 +
 arch/powerpc/kernel/setup_32.c               |   11 +-
 arch/powerpc/kernel/setup_64.c               |  118 +----------
 arch/powerpc/kernel/vdso.c                   |   27 +--
 arch/powerpc/lib/copypage_64.S               |   10 +-
 arch/powerpc/mm/Makefile                     |    2 +-
 arch/powerpc/mm/cache.c                      |  279 ++++++++++++++++++++++++++
 arch/powerpc/mm/dma-noncoherent.c            |    2 +-
 arch/powerpc/platforms/52xx/lite5200_sleep.S |    9 +-
 arch/powerpc/platforms/powermac/pci.c        |    2 +-
 arch/powerpc/xmon/xmon.c                     |   53 +++---
 drivers/macintosh/smu.c                      |    8 +-
 25 files changed, 599 insertions(+), 620 deletions(-)
 create mode 100644 arch/powerpc/mm/cache.c

diff --git a/arch/powerpc/include/asm/cache.h b/arch/powerpc/include/asm/cache.h
index 4b50941..b1dc08f 100644
--- a/arch/powerpc/include/asm/cache.h
+++ b/arch/powerpc/include/asm/cache.h
@@ -3,47 +3,142 @@
 
 #ifdef __KERNEL__
 
-
-/* bytes per L1 cache line */
-#if defined(CONFIG_8xx) || defined(CONFIG_403GCX)
-#define L1_CACHE_SHIFT		4
-#define MAX_COPY_PREFETCH	1
+/*
+ * Various PowerPC CPUs which are otherwise compatible have different L1
+ * cache line sizes.
+ *
+ * Unfortunately, lots of kernel code assumes that L1_CACHE_BYTES and
+ * L1_CACHE_SHIFT are compile-time constants that can be used to align
+ * data-structures to avoid false cacheline sharing, so we can't just
+ * compute them at runtime from the cputable values.
+ *
+ * So for alignment purposes, we will compute these values as safe maximums
+ * of all the CPU support compiled into the kernel.
+ */
+#if defined(CONFIG_PPC64) || defined(CONFIG_PPC_47x)
+# define L1_CACHE_SHIFT_MAX 7 /* 128-byte cache blocks */
 #elif defined(CONFIG_PPC_E500MC)
-#define L1_CACHE_SHIFT		6
-#define MAX_COPY_PREFETCH	4
-#elif defined(CONFIG_PPC32)
-#define MAX_COPY_PREFETCH	4
-#if defined(CONFIG_PPC_47x)
-#define L1_CACHE_SHIFT		7
+# define L1_CACHE_SHIFT_MAX 6 /* 64-byte cache blocks */
 #else
-#define L1_CACHE_SHIFT		5
+# define L1_CACHE_SHIFT_MAX 5 /* 32-byte cache blocks */
 #endif
+#define L1_CACHE_BYTES_MAX (1 << L1_CACHE_SHIFT_MAX)
+
+#define L1_CACHE_SHIFT  L1_CACHE_SHIFT_MAX
+#define L1_CACHE_BYTES  L1_CACHE_BYTES_MAX
+#define SMP_CACHE_BYTES L1_CACHE_BYTES_MAX
+
+/*
+ * Unfortunately, for other purposes, we can't just use a safe maximum value
+ * because it gets used in loops when invalidating or clearing cachelines and
+ * it would be very bad to only flush/invalidate/zero/etc every 4th one.
+ *
+ * During early initialization we load these values from the device-tree and
+ * the cputable into the powerpc_caches structure, but we need to be able to
+ * clear pages before that occurs, so these need sane default values.
+ *
+ * As explained in the powerpc_caches structure definition, the defaults
+ * should be safe minimums, so that's what we compute here.
+ */
+#if defined(CONFIG_8xx) || defined(CONFIG_403GCX)
+# define L1_CACHE_SHIFT_MIN 4 /* 16-byte cache blocks */
+#elif defined(CONFIG_PPC32)
+# define L1_CACHE_SHIFT_MIN 5 /* 32-byte cache blocks */
 #else /* CONFIG_PPC64 */
-#define L1_CACHE_SHIFT		7
+# define L1_CACHE_SHIFT_MIN 6 /* 64-byte cache blocks */
 #endif
+#define L1_CACHE_BYTES_MIN (1 << L1_CACHE_SHIFT_MIN)
 
-#define	L1_CACHE_BYTES		(1 << L1_CACHE_SHIFT)
+/*
+ * Apparently the 8xx and the 403GCX have tiny caches, so they never prefetch
+ * more than a single cacheline in the ASM memory copy functions.
+ *
+ * All other 32-bit CPUs prefetch 4 cachelines, and the 64-bit CPUs have
+ * their own copy routines which prefetch the entire page.
+ */
+#ifdef PPC32
+# if defined(CONFIG_8xx) || defined(CONFIG_403GCX)
+#  define MAX_COPY_PREFETCH 1
+# else
+#  define MAX_COPY_PREFETCH 4
+# endif
+#endif
 
-#define	SMP_CACHE_BYTES		L1_CACHE_BYTES
+#ifndef __ASSEMBLY__
 
-#if defined(__powerpc64__) && !defined(__ASSEMBLY__)
-struct ppc64_caches {
-	u32	dsize;			/* L1 d-cache size */
-	u32	dline_size;		/* L1 d-cache line size	*/
-	u32	log_dline_size;
-	u32	dlines_per_page;
-	u32	isize;			/* L1 i-cache size */
-	u32	iline_size;		/* L1 i-cache line size	*/
-	u32	log_iline_size;
-	u32	ilines_per_page;
-};
+/*
+ * A handy macro to iterate over all the cachelines referring to memory from
+ * "START" through "STOP - 1", inclusive.
+ */
+#define FOR_EACH_CACHELINE(LINE, START, STOP, CACHE)			\
+	for (u32 linesize__ = powerpc_caches.CACHE##_block_bytes,	\
+			(LINE) = (START) & ~(linesize__ - 1);		\
+			(LINE) < (STOP); (LINE) += linesize__)
+
+/* Write out a data cache block if it is dirty */
+static inline void dcbst(unsigned long addr)
+{
+	asm volatile("dcbst %y0" :: "Z"(addr) : "memory");
+}
 
-extern struct ppc64_caches ppc64_caches;
-#endif /* __powerpc64__ && ! __ASSEMBLY__ */
+/* Invalidate a data cache block (will lose data if dirty!) */
+static inline void dcbi(unsigned long addr)
+{
+	asm volatile("dcbi %y0" :: "Z"(addr) : "memory");
+}
+
+/* Write out (if dirty) and invalidate a data cache block */
+static inline void dcbf(unsigned long addr)
+{
+	asm volatile("dcbf %y0" :: "Z"(addr) : "memory");
+}
+
+/* Populate a data cache block with zeros */
+static inline void dcbz(unsigned long addr)
+{
+	asm volatile("dcbz %y0" :: "Z"(addr) : "memory");
+}
+
+/* Invalidate an instruction cache block */
+static inline void icbi(unsigned long addr)
+{
+	asm volatile("icbi %y0" :: "Z"(addr) : "memory");
+}
+
+/*
+ * This structure contains the various PowerPC cache parameters computed
+ * shortly after the device-tree has been unflattened during boot.
+ *
+ * Prior to that they have statically initialized values from L1_CACHE_*_MIN
+ * computed above.
+ *
+ * NOTE: If the dcache/icache are separate then ucache_* should be zeroed,
+ *       otherwise dcache == icache == ucache.
+ */
+struct powerpc_caches {
+	/* Data cache parameters */
+	u32 dcache_total_bytes;
+	u32 dcache_block_bytes;
+	u32 dcache_block_shift;
+	u32 dcache_blocks_per_page;
+
+	/* Instruction cache parameters */
+	u32 icache_total_bytes;
+	u32 icache_block_bytes;
+	u32 icache_block_shift;
+	u32 icache_blocks_per_page;
+
+	/* Unified cache parameters (If != 0, all 3 caches must be equal) */
+	u32 ucache_total_bytes;
+	u32 ucache_block_bytes;
+	u32 ucache_block_shift;
+	u32 ucache_blocks_per_page;
+};
+extern struct powerpc_caches powerpc_caches;
 
-#if !defined(__ASSEMBLY__)
 #define __read_mostly __attribute__((__section__(".data..read_mostly")))
-#endif
+
+#endif /* not __ASSEMBLY__ */
 
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_CACHE_H */
diff --git a/arch/powerpc/include/asm/cacheflush.h b/arch/powerpc/include/asm/cacheflush.h
index ab9e402..8646443 100644
--- a/arch/powerpc/include/asm/cacheflush.h
+++ b/arch/powerpc/include/asm/cacheflush.h
@@ -47,12 +47,9 @@ extern void __flush_dcache_icache_phys(unsigned long physaddr);
 #endif /* CONFIG_PPC32 && !CONFIG_BOOKE */
 
 extern void flush_dcache_range(unsigned long start, unsigned long stop);
-#ifdef CONFIG_PPC32
 extern void clean_dcache_range(unsigned long start, unsigned long stop);
 extern void invalidate_dcache_range(unsigned long start, unsigned long stop);
-#endif /* CONFIG_PPC32 */
 #ifdef CONFIG_PPC64
-extern void flush_inval_dcache_range(unsigned long start, unsigned long stop);
 extern void flush_dcache_phys_range(unsigned long start, unsigned long stop);
 #endif
 
diff --git a/arch/powerpc/include/asm/page.h b/arch/powerpc/include/asm/page.h
index dd9c4fd..b2e24ce 100644
--- a/arch/powerpc/include/asm/page.h
+++ b/arch/powerpc/include/asm/page.h
@@ -286,11 +286,17 @@ static inline int hugepd_ok(hugepd_t hpd)
 #endif /* CONFIG_HUGETLB_PAGE */
 
 struct page;
+extern void clear_pages(void *page, int order);
 extern void clear_user_page(void *page, unsigned long vaddr, struct page *pg);
 extern void copy_user_page(void *to, void *from, unsigned long vaddr,
 		struct page *p);
 extern int page_is_ram(unsigned long pfn);
 
+static inline void clear_page(void *page)
+{
+	clear_pages(page, 0);
+}
+
 #ifdef CONFIG_PPC_SMLPAR
 void arch_free_page(struct page *page, int order);
 #define HAVE_ARCH_FREE_PAGE
diff --git a/arch/powerpc/include/asm/page_32.h b/arch/powerpc/include/asm/page_32.h
index 68d73b2..12ae694 100644
--- a/arch/powerpc/include/asm/page_32.h
+++ b/arch/powerpc/include/asm/page_32.h
@@ -10,7 +10,7 @@
 #define VM_DATA_DEFAULT_FLAGS	VM_DATA_DEFAULT_FLAGS32
 
 #ifdef CONFIG_NOT_COHERENT_CACHE
-#define ARCH_DMA_MINALIGN	L1_CACHE_BYTES
+#define ARCH_DMA_MINALIGN	L1_CACHE_BYTES_MAX
 #endif
 
 #ifdef CONFIG_PTE_64BIT
@@ -37,8 +37,6 @@ typedef unsigned long pte_basic_t;
 #endif
 
 struct page;
-extern void clear_pages(void *page, int order);
-static inline void clear_page(void *page) { clear_pages(page, 0); }
 extern void copy_page(void *to, void *from);
 
 #include <asm-generic/getorder.h>
diff --git a/arch/powerpc/include/asm/page_64.h b/arch/powerpc/include/asm/page_64.h
index fb40ede..7e156f6 100644
--- a/arch/powerpc/include/asm/page_64.h
+++ b/arch/powerpc/include/asm/page_64.h
@@ -42,23 +42,6 @@
 
 typedef unsigned long pte_basic_t;
 
-static __inline__ void clear_page(void *addr)
-{
-	unsigned long lines, line_size;
-
-	line_size = ppc64_caches.dline_size;
-	lines = ppc64_caches.dlines_per_page;
-
-	__asm__ __volatile__(
-	"mtctr	%1	# clear_page\n\
-1:      dcbz	0,%0\n\
-	add	%0,%0,%3\n\
-	bdnz+	1b"
-        : "=r" (addr)
-        : "r" (lines), "0" (addr), "r" (line_size)
-	: "ctr", "memory");
-}
-
 extern void copy_page(void *to, void *from);
 
 /* Log 2 of page table size */
diff --git a/arch/powerpc/kernel/align.c b/arch/powerpc/kernel/align.c
index 8184ee9..debfb99 100644
--- a/arch/powerpc/kernel/align.c
+++ b/arch/powerpc/kernel/align.c
@@ -233,14 +233,9 @@ static inline unsigned make_dsisr(unsigned instr)
  */
 static int emulate_dcbz(struct pt_regs *regs, unsigned char __user *addr)
 {
+	int i, size = powerpc_caches.dcache_block_bytes;
 	long __user *p;
-	int i, size;
 
-#ifdef __powerpc64__
-	size = ppc64_caches.dline_size;
-#else
-	size = L1_CACHE_BYTES;
-#endif
 	p = (long __user *) (regs->dar & -size);
 	if (user_mode(regs) && !access_ok(VERIFY_WRITE, p, size))
 		return -EFAULT;
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index 7c5324f..505b25a 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -126,13 +126,14 @@ int main(void)
 	DEFINE(TI_TASK, offsetof(struct thread_info, task));
 	DEFINE(TI_CPU, offsetof(struct thread_info, cpu));
 
+	DEFINE(DCACHE_BLOCK_SHIFT,	offsetof(struct powerpc_caches, dcache_block_shift));
+	DEFINE(DCACHE_BLOCK_BYTES,	offsetof(struct powerpc_caches, dcache_block_bytes));
+	DEFINE(DCACHE_BLOCKS_PER_PAGE,	offsetof(struct powerpc_caches, dcache_blocks_per_page));
+	DEFINE(ICACHE_BLOCK_SHIFT,	offsetof(struct powerpc_caches, icache_block_shift));
+	DEFINE(ICACHE_BLOCK_BYTES,	offsetof(struct powerpc_caches, icache_block_bytes));
+	DEFINE(ICACHE_BLOCKS_PER_PAGE,	offsetof(struct powerpc_caches, icache_blocks_per_page));
+
 #ifdef CONFIG_PPC64
-	DEFINE(DCACHEL1LINESIZE, offsetof(struct ppc64_caches, dline_size));
-	DEFINE(DCACHEL1LOGLINESIZE, offsetof(struct ppc64_caches, log_dline_size));
-	DEFINE(DCACHEL1LINESPERPAGE, offsetof(struct ppc64_caches, dlines_per_page));
-	DEFINE(ICACHEL1LINESIZE, offsetof(struct ppc64_caches, iline_size));
-	DEFINE(ICACHEL1LOGLINESIZE, offsetof(struct ppc64_caches, log_iline_size));
-	DEFINE(ICACHEL1LINESPERPAGE, offsetof(struct ppc64_caches, ilines_per_page));
 	/* paca */
 	DEFINE(PACA_SIZE, sizeof(struct paca_struct));
 	DEFINE(PACA_LOCK_TOKEN, offsetof(struct paca_struct, lock_token));
diff --git a/arch/powerpc/kernel/head_32.S b/arch/powerpc/kernel/head_32.S
index 0654dba..8abc44a 100644
--- a/arch/powerpc/kernel/head_32.S
+++ b/arch/powerpc/kernel/head_32.S
@@ -786,7 +786,14 @@ relocate_kernel:
 _ENTRY(copy_and_flush)
 	addi	r5,r5,-4
 	addi	r6,r6,-4
-4:	li	r0,L1_CACHE_BYTES/4
+4:	li	r0,L1_CACHE_BYTES_MIN/4	/* Use the smallest common	*/
+					/* denominator cache line	*/
+					/* size.  This results in	*/
+					/* extra cache line flushes	*/
+					/* but operation is correct.	*/
+					/* Can't get cache line size	*/
+					/* from device-tree yet		*/
+
 	mtctr	r0
 3:	addi	r6,r6,4			/* copy a cache line */
 	lwzx	r0,r6,r4
diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S
index 06c7251..183d371 100644
--- a/arch/powerpc/kernel/head_64.S
+++ b/arch/powerpc/kernel/head_64.S
@@ -480,7 +480,7 @@ p_end:	.llong	_end - _stext
 _GLOBAL(copy_and_flush)
 	addi	r5,r5,-8
 	addi	r6,r6,-8
-4:	li	r0,8			/* Use the smallest common	*/
+4:	li	r0,L1_CACHE_BYTES_MIN/8	/* Use the smallest common	*/
 					/* denominator cache line	*/
 					/* size.  This results in	*/
 					/* extra cache line flushes	*/
diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S
index f7d760a..ee61600 100644
--- a/arch/powerpc/kernel/misc_32.S
+++ b/arch/powerpc/kernel/misc_32.S
@@ -321,199 +321,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_UNIFIED_ID_CACHE)
 	blr
 
 /*
- * Write any modified data cache blocks out to memory
- * and invalidate the corresponding instruction cache blocks.
- * This is a no-op on the 601.
- *
- * flush_icache_range(unsigned long start, unsigned long stop)
- */
-_KPROBE(__flush_icache_range)
-BEGIN_FTR_SECTION
-	blr				/* for 601, do nothing */
-END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
-	li	r5,L1_CACHE_BYTES-1
-	andc	r3,r3,r5
-	subf	r4,r3,r4
-	add	r4,r4,r5
-	srwi.	r4,r4,L1_CACHE_SHIFT
-	beqlr
-	mtctr	r4
-	mr	r6,r3
-1:	dcbst	0,r3
-	addi	r3,r3,L1_CACHE_BYTES
-	bdnz	1b
-	sync				/* wait for dcbst's to get to ram */
-#ifndef CONFIG_44x
-	mtctr	r4
-2:	icbi	0,r6
-	addi	r6,r6,L1_CACHE_BYTES
-	bdnz	2b
-#else
-	/* Flash invalidate on 44x because we are passed kmapped addresses and
-	   this doesn't work for userspace pages due to the virtually tagged
-	   icache.  Sigh. */
-	iccci	0, r0
-#endif
-	sync				/* additional sync needed on g4 */
-	isync
-	blr
-/*
- * Write any modified data cache blocks out to memory.
- * Does not invalidate the corresponding cache lines (especially for
- * any corresponding instruction cache).
- *
- * clean_dcache_range(unsigned long start, unsigned long stop)
- */
-_GLOBAL(clean_dcache_range)
-	li	r5,L1_CACHE_BYTES-1
-	andc	r3,r3,r5
-	subf	r4,r3,r4
-	add	r4,r4,r5
-	srwi.	r4,r4,L1_CACHE_SHIFT
-	beqlr
-	mtctr	r4
-
-1:	dcbst	0,r3
-	addi	r3,r3,L1_CACHE_BYTES
-	bdnz	1b
-	sync				/* wait for dcbst's to get to ram */
-	blr
-
-/*
- * Write any modified data cache blocks out to memory and invalidate them.
- * Does not invalidate the corresponding instruction cache blocks.
- *
- * flush_dcache_range(unsigned long start, unsigned long stop)
- */
-_GLOBAL(flush_dcache_range)
-	li	r5,L1_CACHE_BYTES-1
-	andc	r3,r3,r5
-	subf	r4,r3,r4
-	add	r4,r4,r5
-	srwi.	r4,r4,L1_CACHE_SHIFT
-	beqlr
-	mtctr	r4
-
-1:	dcbf	0,r3
-	addi	r3,r3,L1_CACHE_BYTES
-	bdnz	1b
-	sync				/* wait for dcbst's to get to ram */
-	blr
-
-/*
- * Like above, but invalidate the D-cache.  This is used by the 8xx
- * to invalidate the cache so the PPC core doesn't get stale data
- * from the CPM (no cache snooping here :-).
- *
- * invalidate_dcache_range(unsigned long start, unsigned long stop)
- */
-_GLOBAL(invalidate_dcache_range)
-	li	r5,L1_CACHE_BYTES-1
-	andc	r3,r3,r5
-	subf	r4,r3,r4
-	add	r4,r4,r5
-	srwi.	r4,r4,L1_CACHE_SHIFT
-	beqlr
-	mtctr	r4
-
-1:	dcbi	0,r3
-	addi	r3,r3,L1_CACHE_BYTES
-	bdnz	1b
-	sync				/* wait for dcbi's to get to ram */
-	blr
-
-/*
- * Flush a particular page from the data cache to RAM.
- * Note: this is necessary because the instruction cache does *not*
- * snoop from the data cache.
- * This is a no-op on the 601 which has a unified cache.
- *
- *	void __flush_dcache_icache(void *page)
- */
-_GLOBAL(__flush_dcache_icache)
-BEGIN_FTR_SECTION
-	blr
-END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
-	rlwinm	r3,r3,0,0,31-PAGE_SHIFT		/* Get page base address */
-	li	r4,PAGE_SIZE/L1_CACHE_BYTES	/* Number of lines in a page */
-	mtctr	r4
-	mr	r6,r3
-0:	dcbst	0,r3				/* Write line to ram */
-	addi	r3,r3,L1_CACHE_BYTES
-	bdnz	0b
-	sync
-#ifdef CONFIG_44x
-	/* We don't flush the icache on 44x. Those have a virtual icache
-	 * and we don't have access to the virtual address here (it's
-	 * not the page vaddr but where it's mapped in user space). The
-	 * flushing of the icache on these is handled elsewhere, when
-	 * a change in the address space occurs, before returning to
-	 * user space
-	 */
-BEGIN_MMU_FTR_SECTION
-	blr
-END_MMU_FTR_SECTION_IFSET(MMU_FTR_TYPE_44x)
-#endif /* CONFIG_44x */
-	mtctr	r4
-1:	icbi	0,r6
-	addi	r6,r6,L1_CACHE_BYTES
-	bdnz	1b
-	sync
-	isync
-	blr
-
-#ifndef CONFIG_BOOKE
-/*
- * Flush a particular page from the data cache to RAM, identified
- * by its physical address.  We turn off the MMU so we can just use
- * the physical address (this may be a highmem page without a kernel
- * mapping).
- *
- *	void __flush_dcache_icache_phys(unsigned long physaddr)
- */
-_GLOBAL(__flush_dcache_icache_phys)
-BEGIN_FTR_SECTION
-	blr					/* for 601, do nothing */
-END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
-	mfmsr	r10
-	rlwinm	r0,r10,0,28,26			/* clear DR */
-	mtmsr	r0
-	isync
-	rlwinm	r3,r3,0,0,31-PAGE_SHIFT		/* Get page base address */
-	li	r4,PAGE_SIZE/L1_CACHE_BYTES	/* Number of lines in a page */
-	mtctr	r4
-	mr	r6,r3
-0:	dcbst	0,r3				/* Write line to ram */
-	addi	r3,r3,L1_CACHE_BYTES
-	bdnz	0b
-	sync
-	mtctr	r4
-1:	icbi	0,r6
-	addi	r6,r6,L1_CACHE_BYTES
-	bdnz	1b
-	sync
-	mtmsr	r10				/* restore DR */
-	isync
-	blr
-#endif /* CONFIG_BOOKE */
-
-/*
- * Clear pages using the dcbz instruction, which doesn't cause any
- * memory traffic (except to write out any cache lines which get
- * displaced).  This only works on cacheable memory.
- *
- * void clear_pages(void *page, int order) ;
- */
-_GLOBAL(clear_pages)
-	li	r0,PAGE_SIZE/L1_CACHE_BYTES
-	slw	r0,r0,r4
-	mtctr	r0
-1:	dcbz	0,r3
-	addi	r3,r3,L1_CACHE_BYTES
-	bdnz	1b
-	blr
-
-/*
  * Copy a whole page.  We use the dcbz instruction on the destination
  * to reduce memory traffic (it eliminates the unnecessary reads of
  * the destination into cache).  This requires that the destination
diff --git a/arch/powerpc/kernel/misc_64.S b/arch/powerpc/kernel/misc_64.S
index 616921e..500fd61 100644
--- a/arch/powerpc/kernel/misc_64.S
+++ b/arch/powerpc/kernel/misc_64.S
@@ -53,188 +53,6 @@ _GLOBAL(call_handle_irq)
 	mtlr	r0
 	blr
 
-	.section	".toc","aw"
-PPC64_CACHES:
-	.tc		ppc64_caches[TC],ppc64_caches
-	.section	".text"
-
-/*
- * Write any modified data cache blocks out to memory
- * and invalidate the corresponding instruction cache blocks.
- *
- * flush_icache_range(unsigned long start, unsigned long stop)
- *
- *   flush all bytes from start through stop-1 inclusive
- */
-
-_KPROBE(__flush_icache_range)
-
-/*
- * Flush the data cache to memory 
- * 
- * Different systems have different cache line sizes
- * and in some cases i-cache and d-cache line sizes differ from
- * each other.
- */
- 	ld	r10,PPC64_CACHES@toc(r2)
-	lwz	r7,DCACHEL1LINESIZE(r10)/* Get cache line size */
-	addi	r5,r7,-1
-	andc	r6,r3,r5		/* round low to line bdy */
-	subf	r8,r6,r4		/* compute length */
-	add	r8,r8,r5		/* ensure we get enough */
-	lwz	r9,DCACHEL1LOGLINESIZE(r10)	/* Get log-2 of cache line size */
-	srw.	r8,r8,r9		/* compute line count */
-	beqlr				/* nothing to do? */
-	mtctr	r8
-1:	dcbst	0,r6
-	add	r6,r6,r7
-	bdnz	1b
-	sync
-
-/* Now invalidate the instruction cache */
-	
-	lwz	r7,ICACHEL1LINESIZE(r10)	/* Get Icache line size */
-	addi	r5,r7,-1
-	andc	r6,r3,r5		/* round low to line bdy */
-	subf	r8,r6,r4		/* compute length */
-	add	r8,r8,r5
-	lwz	r9,ICACHEL1LOGLINESIZE(r10)	/* Get log-2 of Icache line size */
-	srw.	r8,r8,r9		/* compute line count */
-	beqlr				/* nothing to do? */
-	mtctr	r8
-2:	icbi	0,r6
-	add	r6,r6,r7
-	bdnz	2b
-	isync
-	blr
-	.previous .text
-/*
- * Like above, but only do the D-cache.
- *
- * flush_dcache_range(unsigned long start, unsigned long stop)
- *
- *    flush all bytes from start to stop-1 inclusive
- */
-_GLOBAL(flush_dcache_range)
-
-/*
- * Flush the data cache to memory 
- * 
- * Different systems have different cache line sizes
- */
- 	ld	r10,PPC64_CACHES@toc(r2)
-	lwz	r7,DCACHEL1LINESIZE(r10)	/* Get dcache line size */
-	addi	r5,r7,-1
-	andc	r6,r3,r5		/* round low to line bdy */
-	subf	r8,r6,r4		/* compute length */
-	add	r8,r8,r5		/* ensure we get enough */
-	lwz	r9,DCACHEL1LOGLINESIZE(r10)	/* Get log-2 of dcache line size */
-	srw.	r8,r8,r9		/* compute line count */
-	beqlr				/* nothing to do? */
-	mtctr	r8
-0:	dcbst	0,r6
-	add	r6,r6,r7
-	bdnz	0b
-	sync
-	blr
-
-/*
- * Like above, but works on non-mapped physical addresses.
- * Use only for non-LPAR setups ! It also assumes real mode
- * is cacheable. Used for flushing out the DART before using
- * it as uncacheable memory 
- *
- * flush_dcache_phys_range(unsigned long start, unsigned long stop)
- *
- *    flush all bytes from start to stop-1 inclusive
- */
-_GLOBAL(flush_dcache_phys_range)
- 	ld	r10,PPC64_CACHES@toc(r2)
-	lwz	r7,DCACHEL1LINESIZE(r10)	/* Get dcache line size */
-	addi	r5,r7,-1
-	andc	r6,r3,r5		/* round low to line bdy */
-	subf	r8,r6,r4		/* compute length */
-	add	r8,r8,r5		/* ensure we get enough */
-	lwz	r9,DCACHEL1LOGLINESIZE(r10)	/* Get log-2 of dcache line size */
-	srw.	r8,r8,r9		/* compute line count */
-	beqlr				/* nothing to do? */
-	mfmsr	r5			/* Disable MMU Data Relocation */
-	ori	r0,r5,MSR_DR
-	xori	r0,r0,MSR_DR
-	sync
-	mtmsr	r0
-	sync
-	isync
-	mtctr	r8
-0:	dcbst	0,r6
-	add	r6,r6,r7
-	bdnz	0b
-	sync
-	isync
-	mtmsr	r5			/* Re-enable MMU Data Relocation */
-	sync
-	isync
-	blr
-
-_GLOBAL(flush_inval_dcache_range)
- 	ld	r10,PPC64_CACHES@toc(r2)
-	lwz	r7,DCACHEL1LINESIZE(r10)	/* Get dcache line size */
-	addi	r5,r7,-1
-	andc	r6,r3,r5		/* round low to line bdy */
-	subf	r8,r6,r4		/* compute length */
-	add	r8,r8,r5		/* ensure we get enough */
-	lwz	r9,DCACHEL1LOGLINESIZE(r10)/* Get log-2 of dcache line size */
-	srw.	r8,r8,r9		/* compute line count */
-	beqlr				/* nothing to do? */
-	sync
-	isync
-	mtctr	r8
-0:	dcbf	0,r6
-	add	r6,r6,r7
-	bdnz	0b
-	sync
-	isync
-	blr
-
-
-/*
- * Flush a particular page from the data cache to RAM.
- * Note: this is necessary because the instruction cache does *not*
- * snoop from the data cache.
- *
- *	void __flush_dcache_icache(void *page)
- */
-_GLOBAL(__flush_dcache_icache)
-/*
- * Flush the data cache to memory 
- * 
- * Different systems have different cache line sizes
- */
-
-/* Flush the dcache */
- 	ld	r7,PPC64_CACHES@toc(r2)
-	clrrdi	r3,r3,PAGE_SHIFT           	    /* Page align */
-	lwz	r4,DCACHEL1LINESPERPAGE(r7)	/* Get # dcache lines per page */
-	lwz	r5,DCACHEL1LINESIZE(r7)		/* Get dcache line size */
-	mr	r6,r3
-	mtctr	r4
-0:	dcbst	0,r6
-	add	r6,r6,r5
-	bdnz	0b
-	sync
-
-/* Now invalidate the icache */	
-
-	lwz	r4,ICACHEL1LINESPERPAGE(r7)	/* Get # icache lines per page */
-	lwz	r5,ICACHEL1LINESIZE(r7)		/* Get icache line size */
-	mtctr	r4
-1:	icbi	0,r3
-	add	r3,r3,r5
-	bdnz	1b
-	isync
-	blr
-
-
 #if defined(CONFIG_PPC_PMAC) || defined(CONFIG_PPC_MAPLE)
 /*
  * Do an IO access in real mode
diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c
index acba8ce..ccdceb7 100644
--- a/arch/powerpc/kernel/ppc_ksyms.c
+++ b/arch/powerpc/kernel/ppc_ksyms.c
@@ -53,7 +53,6 @@ extern void program_check_exception(struct pt_regs *regs);
 extern void single_step_exception(struct pt_regs *regs);
 extern int sys_sigreturn(struct pt_regs *regs);
 
-EXPORT_SYMBOL(clear_pages);
 EXPORT_SYMBOL(ISA_DMA_THRESHOLD);
 EXPORT_SYMBOL(DMA_MODE_READ);
 EXPORT_SYMBOL(DMA_MODE_WRITE);
@@ -113,8 +112,6 @@ EXPORT_SYMBOL(giveup_spe);
 #ifndef CONFIG_PPC64
 EXPORT_SYMBOL(flush_instruction_cache);
 #endif
-EXPORT_SYMBOL(__flush_icache_range);
-EXPORT_SYMBOL(flush_dcache_range);
 
 #ifdef CONFIG_SMP
 #ifdef CONFIG_PPC32
diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c
index 77bb77d..3abfea4 100644
--- a/arch/powerpc/kernel/setup-common.c
+++ b/arch/powerpc/kernel/setup-common.c
@@ -83,6 +83,54 @@ unsigned long klimit = (unsigned long) _end;
 char cmd_line[COMMAND_LINE_SIZE];
 
 /*
+ * Initialize these values to minimum safe defaults in case they need to be
+ * used early during the boot process.  While this may not seem safe, it is
+ * actually safe in practice, because all of the kernel loops that use this
+ * data operate on whole pages.
+ *
+ * The PowerPC Book III-E spec documents that the pagesize is an even
+ * multiple of the cache block size and the cache blocks are always
+ * page-aligned.
+ *
+ * So, for example, when clearing a whole page there are only two things that
+ * can be done wrong with "dcbz":
+ *
+ *   (1) Call "dcbz" with an address outside the page you want to zero.
+ *
+ *   (2) Call "dcbz" too few times to actually hit all of the cachelines,
+ *       IE: Use a too-large cacheline stride.
+ *
+ * So as long as we ensure that this number is small enough for the current
+ * CPU everything will operate correctly, albeit with a slight performance
+ * hit, until we get a chance to parse the device-tree for the right value.
+ *
+ * NOTE: Userspace expects an exact value, so none of the above applies after
+ * the device tree has been unflattened and actual values computed.
+ *
+ * See arch/powerpc/asm/caches.h for more information.
+ */
+struct powerpc_caches powerpc_caches = {
+	/* Data cache sizes */
+	.dcache_total_bytes  = 0, /* Unknown */
+	.dcache_block_bytes = L1_CACHE_BYTES_MIN,
+	.dcache_block_shift = L1_CACHE_SHIFT_MIN,
+	.dcache_blocks_per_page = (PAGE_SIZE >> L1_CACHE_SHIFT_MIN),
+
+	/* Instruction cache sizes */
+	.icache_total_bytes = 0,
+	.icache_block_bytes = L1_CACHE_BYTES_MIN,
+	.icache_block_shift = L1_CACHE_SHIFT_MIN,
+	.icache_blocks_per_page = (PAGE_SIZE >> L1_CACHE_SHIFT_MIN),
+
+	/* Unified cache (assume cache is split by default) */
+	.ucache_total_bytes = 0,
+	.ucache_block_bytes = 0,
+	.ucache_block_shift = 0,
+	.ucache_blocks_per_page = 0,
+};
+EXPORT_SYMBOL_GPL(powerpc_caches);
+
+/*
  * This still seems to be needed... -- paulus
  */ 
 struct screen_info screen_info = {
@@ -349,6 +397,61 @@ const struct seq_operations cpuinfo_op = {
 	.show =	show_cpuinfo,
 };
 
+/* Helper functions to compute various values from a cache block size */
+static void __init set_dcache_block_data(u32 bytes)
+{
+	u32 shift = __ilog2(bytes);
+	powerpc_caches.dcache_block_bytes = bytes;
+	powerpc_caches.dcache_block_shift = shift;
+	powerpc_caches.dcache_blocks_per_page = (PAGE_SIZE >> shift);
+}
+static void __init set_icache_block_data(u32 bytes)
+{
+	u32 shift = __ilog2(bytes);
+	powerpc_caches.icache_block_bytes = bytes;
+	powerpc_caches.icache_block_shift = shift;
+	powerpc_caches.icache_blocks_per_page = (PAGE_SIZE >> shift);
+}
+
+/*
+ * Preinitialize the powerpc_caches structure from the cputable.  We will
+ * later scan the device-tree for this information, which may be more
+ * accurate.
+ */
+void __init initialize_early_cache_info(void)
+{
+	set_dcache_block_data(cur_cpu_spec->dcache_bsize);
+	set_icache_block_data(cur_cpu_spec->icache_bsize);
+}
+
+/*
+ * Initialize the powerpc_caches structure from the device-tree for use by
+ * copy_page(), cache flush routines, and AT_DCACHEBSIZE elf headers.
+ *
+ * In the unlikely event that the device-tree doesn't have this information,
+ * the defaults loaded by initialize_early_cache_info() from the cputable
+ * will be used.
+ */
+void __init initialize_cache_info(void)
+{
+	/* Assume that the cache properties are the same across all nodes */
+	struct device_node *np = of_find_node_by_type(NULL, "cpu");
+	u32 value = 0;
+
+	/* First check data/instruction cache block sizes */
+	if (	!of_property_read_u32(np, "d-cache-block-size", &value) ||
+		!of_property_read_u32(np, "d-cache-line-size", &value))
+		set_dcache_block_data(value);
+
+	if (	!of_property_read_u32(np, "i-cache-block-size", &value) ||
+		!of_property_read_u32(np, "i-cache-line-size", &value))
+		set_icache_block_data(value);
+
+	/* Also read total cache sizes (no defaults here) */
+	of_property_read_u32(np, "d-cache-size", &powerpc_caches.dcache_total_bytes);
+	of_property_read_u32(np, "i-cache-size", &powerpc_caches.icache_total_bytes);
+}
+
 void __init check_for_initrd(void)
 {
 #ifdef CONFIG_BLK_DEV_INITRD
diff --git a/arch/powerpc/kernel/setup.h b/arch/powerpc/kernel/setup.h
index 4c67ad7..1ae16ec 100644
--- a/arch/powerpc/kernel/setup.h
+++ b/arch/powerpc/kernel/setup.h
@@ -1,6 +1,7 @@
 #ifndef _POWERPC_KERNEL_SETUP_H
 #define _POWERPC_KERNEL_SETUP_H
 
+void initialize_cache_info(void);
 void check_for_initrd(void);
 void do_init_bootmem(void);
 void setup_panic(void);
diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c
index c1ce863..1db2bfb 100644
--- a/arch/powerpc/kernel/setup_32.c
+++ b/arch/powerpc/kernel/setup_32.c
@@ -63,14 +63,6 @@ EXPORT_SYMBOL(vgacon_remap_base);
 #endif
 
 /*
- * These are used in binfmt_elf.c to put aux entries on the stack
- * for each elf executable being started.
- */
-int dcache_bsize;
-int icache_bsize;
-int ucache_bsize;
-
-/*
  * We're called here very early in the boot.  We determine the machine
  * type and call the appropriate low-level setup functions.
  *  -- Cort <cort@fsmlabs.com>
@@ -286,10 +278,13 @@ void __init setup_arch(char **cmdline_p)
 {
 	*cmdline_p = cmd_line;
 
+	initialize_early_cache_info();
+
 	/* so udelay does something sensible, assume <= 1000 bogomips */
 	loops_per_jiffy = 500000000 / HZ;
 
 	unflatten_device_tree();
+	initialize_cache_info();
 	check_for_initrd();
 
 	if (ppc_md.init_early)
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
index 1a9dea8..bb686de 100644
--- a/arch/powerpc/kernel/setup_64.c
+++ b/arch/powerpc/kernel/setup_64.c
@@ -77,25 +77,6 @@ int boot_cpuid = 0;
 int __initdata spinning_secondaries;
 u64 ppc64_pft_size;
 
-/* Pick defaults since we might want to patch instructions
- * before we've read this from the device tree.
- */
-struct ppc64_caches ppc64_caches = {
-	.dline_size = 0x40,
-	.log_dline_size = 6,
-	.iline_size = 0x40,
-	.log_iline_size = 6
-};
-EXPORT_SYMBOL_GPL(ppc64_caches);
-
-/*
- * These are used in binfmt_elf.c to put aux entries on the stack
- * for each elf executable being started.
- */
-int dcache_bsize;
-int icache_bsize;
-int ucache_bsize;
-
 #ifdef CONFIG_SMP
 
 static char *smt_enabled_cmdline;
@@ -265,82 +246,6 @@ void smp_release_cpus(void)
 #endif /* CONFIG_SMP || CONFIG_KEXEC */
 
 /*
- * Initialize some remaining members of the ppc64_caches and systemcfg
- * structures
- * (at least until we get rid of them completely). This is mostly some
- * cache informations about the CPU that will be used by cache flush
- * routines and/or provided to userland
- */
-static void __init initialize_cache_info(void)
-{
-	struct device_node *np;
-	unsigned long num_cpus = 0;
-
-	DBG(" -> initialize_cache_info()\n");
-
-	for_each_node_by_type(np, "cpu") {
-		num_cpus += 1;
-
-		/*
-		 * We're assuming *all* of the CPUs have the same
-		 * d-cache and i-cache sizes... -Peter
-		 */
-		if (num_cpus == 1) {
-			const u32 *sizep, *lsizep;
-			u32 size, lsize;
-
-			size = 0;
-			lsize = cur_cpu_spec->dcache_bsize;
-			sizep = of_get_property(np, "d-cache-size", NULL);
-			if (sizep != NULL)
-				size = *sizep;
-			lsizep = of_get_property(np, "d-cache-block-size",
-						 NULL);
-			/* fallback if block size missing */
-			if (lsizep == NULL)
-				lsizep = of_get_property(np,
-							 "d-cache-line-size",
-							 NULL);
-			if (lsizep != NULL)
-				lsize = *lsizep;
-			if (sizep == 0 || lsizep == 0)
-				DBG("Argh, can't find dcache properties ! "
-				    "sizep: %p, lsizep: %p\n", sizep, lsizep);
-
-			ppc64_caches.dsize = size;
-			ppc64_caches.dline_size = lsize;
-			ppc64_caches.log_dline_size = __ilog2(lsize);
-			ppc64_caches.dlines_per_page = PAGE_SIZE / lsize;
-
-			size = 0;
-			lsize = cur_cpu_spec->icache_bsize;
-			sizep = of_get_property(np, "i-cache-size", NULL);
-			if (sizep != NULL)
-				size = *sizep;
-			lsizep = of_get_property(np, "i-cache-block-size",
-						 NULL);
-			if (lsizep == NULL)
-				lsizep = of_get_property(np,
-							 "i-cache-line-size",
-							 NULL);
-			if (lsizep != NULL)
-				lsize = *lsizep;
-			if (sizep == 0 || lsizep == 0)
-				DBG("Argh, can't find icache properties ! "
-				    "sizep: %p, lsizep: %p\n", sizep, lsizep);
-
-			ppc64_caches.isize = size;
-			ppc64_caches.iline_size = lsize;
-			ppc64_caches.log_iline_size = __ilog2(lsize);
-			ppc64_caches.ilines_per_page = PAGE_SIZE / lsize;
-		}
-	}
-
-	DBG(" <- initialize_cache_info()\n");
-}
-
-
-/*
  * Do some initial setup of the system.  The parameters are those which 
  * were passed in from the bootloader.
  */
@@ -365,10 +270,7 @@ void __init setup_system(void)
 	 */
 	unflatten_device_tree();
 
-	/*
-	 * Fill the ppc64_caches & systemcfg structures with informations
- 	 * retrieved from the device-tree.
-	 */
+	/* Fill the powerpc_caches structure with device-tree data */
 	initialize_cache_info();
 
 #ifdef CONFIG_PPC_RTAS
@@ -423,12 +325,10 @@ void __init setup_system(void)
 	printk("-----------------------------------------------------\n");
 	printk("ppc64_pft_size                = 0x%llx\n", ppc64_pft_size);
 	printk("physicalMemorySize            = 0x%llx\n", memblock_phys_mem_size());
-	if (ppc64_caches.dline_size != 0x80)
-		printk("ppc64_caches.dcache_line_size = 0x%x\n",
-		       ppc64_caches.dline_size);
-	if (ppc64_caches.iline_size != 0x80)
-		printk("ppc64_caches.icache_line_size = 0x%x\n",
-		       ppc64_caches.iline_size);
+	if (powerpc_caches.dcache_block_bytes != 0x80)
+		printk("dcache_block_bytes = 0x%x\n", powerpc_caches.dcache_block_bytes);
+	if (powerpc_caches.icache_block_bytes != 0x80)
+		printk("icache_block_bytes = 0x%x\n", powerpc_caches.icache_block_bytes);
 #ifdef CONFIG_PPC_STD_MMU_64
 	if (htab_address)
 		printk("htab_address                  = 0x%p\n", htab_address);
@@ -545,13 +445,7 @@ void __init setup_arch(char **cmdline_p)
 
 	*cmdline_p = cmd_line;
 
-	/*
-	 * Set cache line size based on type of cpu as a default.
-	 * Systems with OF can look in the properties on the cpu node(s)
-	 * for a possibly more accurate value.
-	 */
-	dcache_bsize = ppc64_caches.dline_size;
-	icache_bsize = ppc64_caches.iline_size;
+	initialize_early_cache_info();
 
 	/* reboot on panic */
 	panic_timeout = 180;
diff --git a/arch/powerpc/kernel/vdso.c b/arch/powerpc/kernel/vdso.c
index 7d14bb6..4a038fb 100644
--- a/arch/powerpc/kernel/vdso.c
+++ b/arch/powerpc/kernel/vdso.c
@@ -726,6 +726,7 @@ static int __init vdso_init(void)
 	vdso_data->version.major = SYSTEMCFG_MAJOR;
 	vdso_data->version.minor = SYSTEMCFG_MINOR;
 	vdso_data->processor = mfspr(SPRN_PVR);
+
 	/*
 	 * Fake the old platform number for pSeries and iSeries and add
 	 * in LPAR bit if necessary
@@ -734,29 +735,25 @@ static int __init vdso_init(void)
 	if (firmware_has_feature(FW_FEATURE_LPAR))
 		vdso_data->platform |= 1;
 	vdso_data->physicalMemorySize = memblock_phys_mem_size();
-	vdso_data->dcache_size = ppc64_caches.dsize;
-	vdso_data->dcache_line_size = ppc64_caches.dline_size;
-	vdso_data->icache_size = ppc64_caches.isize;
-	vdso_data->icache_line_size = ppc64_caches.iline_size;
 
-	/* XXXOJN: Blocks should be added to ppc64_caches and used instead */
-	vdso_data->dcache_block_size = ppc64_caches.dline_size;
-	vdso_data->icache_block_size = ppc64_caches.iline_size;
-	vdso_data->dcache_log_block_size = ppc64_caches.log_dline_size;
-	vdso_data->icache_log_block_size = ppc64_caches.log_iline_size;
+	/* There are more cache parameters saved for 64-bit than 32-bit */
+	vdso_data->dcache_size           = powerpc_caches.dcache_total_size;
+	vdso_data->icache_size           = powerpc_caches.icache_total_size;
+	vdso_data->dcache_line_size      = powerpc_caches.dcache_block_bytes;
+	vdso_data->icache_line_size      = powerpc_caches.icache_block_bytes;
 
 	/*
 	 * Calculate the size of the 64 bits vDSO
 	 */
 	vdso64_pages = (&vdso64_end - &vdso64_start) >> PAGE_SHIFT;
 	DBG("vdso64_kbase: %p, 0x%x pages\n", vdso64_kbase, vdso64_pages);
-#else
-	vdso_data->dcache_block_size = L1_CACHE_BYTES;
-	vdso_data->dcache_log_block_size = L1_CACHE_SHIFT;
-	vdso_data->icache_block_size = L1_CACHE_BYTES;
-	vdso_data->icache_log_block_size = L1_CACHE_SHIFT;
-#endif /* CONFIG_PPC64 */
+#endif
 
+	/* Save the cache-block sizes for the VDSO */
+	vdso_data->dcache_block_size     = powerpc_caches.dcache_block_bytes;
+	vdso_data->icache_block_size     = powerpc_caches.icache_block_bytes;
+	vdso_data->dcache_log_block_size = powerpc_caches.dcache_block_shift;
+	vdso_data->icache_log_block_size = powerpc_caches.icache_block_shift;
 
 	/*
 	 * Calculate the size of the 32 bits vDSO
diff --git a/arch/powerpc/lib/copypage_64.S b/arch/powerpc/lib/copypage_64.S
index 53dcb6b..c466977 100644
--- a/arch/powerpc/lib/copypage_64.S
+++ b/arch/powerpc/lib/copypage_64.S
@@ -12,17 +12,17 @@
 #include <asm/asm-offsets.h>
 
         .section        ".toc","aw"
-PPC64_CACHES:
-        .tc             ppc64_caches[TC],ppc64_caches
+POWERPC_CACHES:
+        .tc             powerpc_caches[TC],powerpc_caches
         .section        ".text"
 
 _GLOBAL(copy_page)
 	lis	r5,PAGE_SIZE@h
 	ori	r5,r5,PAGE_SIZE@l
 BEGIN_FTR_SECTION
-	ld      r10,PPC64_CACHES@toc(r2)
-	lwz	r11,DCACHEL1LOGLINESIZE(r10)	/* log2 of cache line size */
-	lwz     r12,DCACHEL1LINESIZE(r10)	/* get cache line size */
+	ld      r10,POWERPC_CACHES@toc(r2)
+	lwz	r11,DCACHE_BLOCK_SHIFT(r10)	/* log2 of cache line size */
+	lwz     r12,DCACHE_BLOCK_BYTES(r10)	/* get cache line size */
 	li	r9,0
 	srd	r8,r5,r11
 
diff --git a/arch/powerpc/mm/Makefile b/arch/powerpc/mm/Makefile
index 991ee81..8ad36a9 100644
--- a/arch/powerpc/mm/Makefile
+++ b/arch/powerpc/mm/Makefile
@@ -6,7 +6,7 @@ subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror
 
 ccflags-$(CONFIG_PPC64)	:= -mno-minimal-toc
 
-obj-y				:= fault.o mem.o pgtable.o gup.o \
+obj-y				:= cache.o fault.o mem.o pgtable.o gup.o \
 				   init_$(CONFIG_WORD_SIZE).o \
 				   pgtable_$(CONFIG_WORD_SIZE).o
 obj-$(CONFIG_PPC_MMU_NOHASH)	+= mmu_context_nohash.o tlb_nohash.o \
diff --git a/arch/powerpc/mm/cache.c b/arch/powerpc/mm/cache.c
new file mode 100644
index 0000000..0fbf2d6
--- /dev/null
+++ b/arch/powerpc/mm/cache.c
@@ -0,0 +1,279 @@
+#include <linux/kprobes.h>
+#include <linux/export.h>
+#include <linux/types.h>
+
+#include <asm/cputable.h>
+#include <asm/system.h>
+#include <asm/cache.h>
+#include <asm/page.h>
+#include <asm/mmu.h>
+
+/*
+ * Write any modified data cache blocks out to memory.
+ * Does not invalidate the corresponding cache lines (especially for
+ * any corresponding instruction cache).
+ */
+void clean_dcache_range(unsigned long start, unsigned long stop)
+{
+	unsigned long addr;
+	FOR_EACH_CACHELINE(addr, start, stop, dcache)
+		dcbst(addr);
+	mb();
+}
+
+/*
+ * Write any modified data cache blocks out to memory and invalidate them.
+ * Does not invalidate the corresponding instruction cache blocks.
+ */
+void flush_dcache_range(unsigned long start, unsigned long stop)
+{
+	unsigned long addr;
+	FOR_EACH_CACHELINE(addr, start, stop, dcache)
+		dcbf(addr);
+	mb();
+}
+EXPORT_SYMBOL(flush_dcache_range);
+
+/*
+ * Like above, but invalidate the D-cache.  This is used by the 8xx
+ * to invalidate the cache so the PPC core doesn't get stale data
+ * from the CPM (no cache snooping here :-).
+ *
+ * invalidate_dcache_range(unsigned long start, unsigned long stop)
+ */
+void invalidate_dcache_range(unsigned long start, unsigned long stop)
+{
+	unsigned long addr;
+	FOR_EACH_CACHELINE(addr, start, stop, dcache)
+		dcbi(addr);
+	mb();
+}
+
+/*
+ * Unfortunately, we cannot flush individual chunks of the icache on 44x as
+ * we are passed kmapped addresses and we have a virtually-tagged icache.
+ *
+ * The only workaround is to invalidate the whole icache.
+ *
+ * NOTE: The CPU does not use the operands for this instruction, so
+ *       they are passed as dummies.
+ */
+__kprobes void __flush_icache_range(unsigned long start, unsigned long stop)
+{
+	unsigned long addr;
+
+	if (cpu_has_feature(CPU_FTR_COHERENT_ICACHE))
+		return;
+
+	/* First ensure that data has been written to memory */
+	FOR_EACH_CACHELINE(addr, start, stop, dcache)
+		dcbst(addr);
+	mb();
+
+#ifdef CONFIG_44x
+	if (mmu_has_feature(MMU_FTR_TYPE_44x)) {
+		asm volatile("iccci 0, r0" ::: "memory");
+		return;
+	}
+#endif
+
+	/* Now discard the corresponding icache */
+	FOR_EACH_CACHELINE(addr, start, stop, icache)
+		icbi(addr);
+	mb();
+	isync();
+}
+EXPORT_SYMBOL(__flush_icache_range);
+
+/*
+ * Flush a particular page from the data cache to RAM.
+ * Note: this is necessary because the instruction cache does *not*
+ * snoop from the data cache.
+ * This is a no-op on the 601 which has a unified cache.
+ *
+ *	void __flush_dcache_icache(void *page)
+ */
+void __flush_dcache_icache(void *page)
+{
+	unsigned long base = ((unsigned long)page) & ~(PAGE_SIZE-1);
+	unsigned long addr;
+
+	if (cpu_has_feature(CPU_FTR_COHERENT_ICACHE))
+		return;
+
+	/* First ensure that data has been written to memory */
+	FOR_EACH_CACHELINE(addr, base, base + PAGE_SIZE, dcache)
+		dcbst(addr);
+
+#ifdef CONFIG_44x
+	/*
+	 * We don't flush the icache on 44x. Those have a virtual icache and
+	 * we don't have access to the virtual address here (it's not the
+	 * page vaddr but where it's mapped in user space). The flushing of
+	 * the icache on these is handled elsewhere, when a change in the
+	 * address space occurs, before returning to user space.
+	 */
+	if (mmu_has_feature(MMU_FTR_TYPE_44x))
+		return;
+#endif
+
+	FOR_EACH_CACHELINE(addr, base, base + PAGE_SIZE, icache)
+		icbi(addr);
+
+	mb();
+	isync();
+}
+
+/*
+ * Clear pages using the dcbz instruction, which doesn't cause any
+ * memory traffic (except to write out any cache lines which get
+ * displaced).  This only works on cacheable memory.
+ *
+ */
+void clear_pages(void *page, int order)
+{
+	unsigned long addr, base = (unsigned long)page;
+	FOR_EACH_CACHELINE(addr, base, base + (PAGE_SIZE << order), dcache)
+		dcbz(addr);
+}
+EXPORT_SYMBOL(clear_pages);
+
+#if defined(CONFIG_PPC32) && !defined(CONFIG_BOOKE)
+/*
+ * Flush a particular page from the data cache to RAM, identified
+ * by its physical address.  We turn off the MMU so we can just use
+ * the physical address (this may be a highmem page without a kernel
+ * mapping).
+ */
+void __flush_dcache_icache_phys(unsigned long phys_page)
+{
+	u32 d_size	= powerpc_caches.dcache_block_bytes;
+	u32 i_size	= powerpc_caches.icache_block_bytes;
+	u32 d_per_page	= powerpc_caches.dcache_blocks_per_page;
+	u32 i_per_page	= powerpc_caches.icache_blocks_per_page;
+
+	/* Temporary registers for the ASM to use */
+	unsigned long old_msr, tmp_msr, d_phys_page, i_phys_page;
+
+	if (cpu_has_feature(CPU_FTR_COHERENT_ICACHE))
+		return;
+
+	/* Page base address (used in 2 different loops) */
+	d_phys_page = i_phys_page = phys_page & ~(PAGE_SIZE - 1);
+
+	/*
+	 * This part needs to be 100% ASM because we disable the MMU, and we
+	 * can't accidentally let some C code go poking at memory while the
+	 * MMU isn't enabled.
+	 *
+	 * NOTE: This looks blatantly unsafe with respect to interrupts.
+	 *       Hopefully all the callers provide sufficient protection?
+	 */
+	asm volatile(
+		/* First disable the MMU */
+		"mfmsr %[old_msr]\n\t"
+		"rlwinm %[tmp_msr], %[old_msr], 0, 28, 26\n\t"
+		"mtmsr %[tmp_msr]\n\t"
+		"isync\n\t"
+
+		/* Clean the data cache */
+		"mtctr %[d_per_page]\n"
+	"0:	dcbst 0, %[d_phys_page]\n\t"
+		"add %[d_phys_page], %[d_phys_page], %[d_size]\n\t"
+		"bdnz 0b\n\t"
+		"sync\n\t"
+
+		/* Invalidate the instruction cache */
+		"mtctr %[i_per_page]\n"
+	"0:	icbi 0, %[i_phys_page]\n\t"
+		"add %[i_phys_page], %[i_phys_page], %[i_size]\n\t"
+		"bdnz 0b\n\t"
+
+		/* Finally, re-enable the MMU */
+		"sync\n\t"
+		"mtmsr %[old_msr]\n\t"
+		"isync\n\t"
+
+		/* Temporary variables and inputs */
+		: [old_msr]    "=&r" (old_msr),
+		  [tmp_msr]    "=&r" (tmp_msr),
+		  [d_phys_page] "=b" (d_phys_page),
+		  [i_phys_page] "=b" (i_phys_page)
+
+		/* Inputs */
+		: [d_size]     "b" (d_size),
+		  [i_size]     "b" (i_size),
+		  [d_per_page] "b" (d_per_page),
+		  [i_per_page] "b" (i_per_page),
+		  "[d_phys_page]"  (d_phys_page),
+		  "[i_phys_page]"  (i_phys_page)
+
+		/* Clobbers */
+		: "memory", "c"
+	);
+}
+#endif /* CONFIG_PPC32 && !CONFIG_BOOKE */
+
+#ifdef CONFIG_PPC64
+/*
+ * Data cache flush that works on non-mapped physical addresses.
+ * Use only for non-LPAR setups ! It also assumes real mode
+ * is cacheable. Used for flushing out the DART before using
+ * it as uncacheable memory 
+ */
+void flush_dcache_phys_range(unsigned long start, unsigned long stop)
+{
+	/* System data cache block size */
+	unsigned long bytes = powerpc_caches.dcache_block_bytes;
+	unsigned long shift = powerpc_caches.dcache_block_shift;
+
+	/* Temporary registers for the ASM to use */
+	unsigned long old_msr, tmp_msr;
+
+	/* Compute a start address and number of cachelines */
+	unsigned long phys_addr = start & ~(bytes - 1);
+	unsigned long nr_lines = ((stop - phys_addr) + (bytes - 1)) >> shift;
+
+	/*
+	 * This part needs to be 100% ASM because we disable the MMU, and we
+	 * can't accidentally let some C code go poking at memory while the
+	 * MMU isn't enabled.
+	 *
+	 * NOTE: This looks blatantly unsafe with respect to interrupts.
+	 *       Hopefully all the callers provide sufficient protection?
+	 */
+	asm volatile(
+		/* First disable the MMU */
+		"mfmsr %[old_msr]\n\t"
+		"rlwinm %[tmp_msr], %[old_msr], 0, 28, 26\n\t"
+		"mtmsr %[tmp_msr]\n\t"
+		"isync\n\t"
+
+		/* Clean the data cache */
+		"mtctr %[nr_lines]\n"
+	"0:	dcbst 0, %[phys_addr]\n\t"
+		"add %[phys_addr], %[phys_addr], %[bytes]\n\t"
+		"bdnz 0b\n\t"
+		"sync\n\t"
+		"isync\n\t"
+
+		/* Finally, re-enable the MMU */
+		"mtmsr %[old_msr]\n\t"
+		"sync\n\t"
+		"isync\n\t"
+
+		/* Temporary variables and inputs */
+		: [old_msr]  "=&r" (old_msr),
+		  [tmp_msr]  "=&r" (tmp_msr),
+		  [phys_addr] "=b" (phys_addr)
+
+		/* Inputs */
+		: [bytes]    "b" (bytes),
+		  [nr_lines] "b" (nr_lines),
+		  "[phys_addr]"  (phys_addr)
+
+		/* Clobbers */
+		: "memory", "c"
+	);
+}
+#endif /* CONFIG_PPC64 */
diff --git a/arch/powerpc/mm/dma-noncoherent.c b/arch/powerpc/mm/dma-noncoherent.c
index 329be36..3823f64 100644
--- a/arch/powerpc/mm/dma-noncoherent.c
+++ b/arch/powerpc/mm/dma-noncoherent.c
@@ -328,7 +328,7 @@ void __dma_sync(void *vaddr, size_t size, int direction)
 		 * invalidate only when cache-line aligned otherwise there is
 		 * the potential for discarding uncommitted data from the cache
 		 */
-		if ((start & (L1_CACHE_BYTES - 1)) || (size & (L1_CACHE_BYTES - 1)))
+		if ((start | size) & (powerpc_caches.dcache_block_bytes - 1))
 			flush_dcache_range(start, end);
 		else
 			invalidate_dcache_range(start, end);
diff --git a/arch/powerpc/platforms/52xx/lite5200_sleep.S b/arch/powerpc/platforms/52xx/lite5200_sleep.S
index 08ab6fe..ac285d9 100644
--- a/arch/powerpc/platforms/52xx/lite5200_sleep.S
+++ b/arch/powerpc/platforms/52xx/lite5200_sleep.S
@@ -394,11 +394,16 @@ restore_regs:
 
 
 /* cache flushing code. copied from arch/ppc/boot/util.S */
-#define NUM_CACHE_LINES (128*8)
+#define NUM_CACHE_LINES ((128 * 8) << (L1_CACHE_SHIFT_MAX - L1_CACHE_SHIFT_MIN))
 
 /*
  * Flush data cache
  * Do this by just reading lots of stuff into the cache.
+ *
+ * NOTE: This does not handle variable-sized cachelines properly, but since
+ *       we are just trying to flush the data cache by reading lots of data,
+ *       this works anyways.  We just make sure we read as many cachelines
+ *       as we could possibly need to overflow the cache on any hardware.
  */
 flush_data_cache:
 	lis	r3,CONFIG_KERNEL_START@h
@@ -407,6 +412,6 @@ flush_data_cache:
 	mtctr	r4
 1:
 	lwz	r4,0(r3)
-	addi	r3,r3,L1_CACHE_BYTES	/* Next line, please */
+	addi	r3,r3,L1_CACHE_BYTES_MIN /* Next line, please */
 	bdnz	1b
 	blr
diff --git a/arch/powerpc/platforms/powermac/pci.c b/arch/powerpc/platforms/powermac/pci.c
index 31a7d3a..8503e38 100644
--- a/arch/powerpc/platforms/powermac/pci.c
+++ b/arch/powerpc/platforms/powermac/pci.c
@@ -1135,7 +1135,7 @@ int pmac_pci_enable_device_hook(struct pci_dev *dev)
 		pci_write_config_byte(dev, PCI_LATENCY_TIMER, 16);
 
 		pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE,
-				      L1_CACHE_BYTES >> 2);
+				powerpc_caches.dcache_block_bytes >> 2);
 	}
 
 	return 0;
diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
index 03a217a..c537d49 100644
--- a/arch/powerpc/xmon/xmon.c
+++ b/arch/powerpc/xmon/xmon.c
@@ -26,6 +26,7 @@
 
 #include <asm/ptrace.h>
 #include <asm/string.h>
+#include <asm/cache.h>
 #include <asm/prom.h>
 #include <asm/machdep.h>
 #include <asm/xmon.h>
@@ -254,16 +255,6 @@ static inline void store_inst(void *p)
 	asm volatile ("dcbst 0,%0; sync; icbi 0,%0; isync" : : "r" (p));
 }
 
-static inline void cflush(void *p)
-{
-	asm volatile ("dcbf 0,%0; icbi 0,%0" : : "r" (p));
-}
-
-static inline void cinval(void *p)
-{
-	asm volatile ("dcbi 0,%0; icbi 0,%0" : : "r" (p));
-}
-
 /*
  * Disable surveillance (the service processor watchdog function)
  * while we are in xmon.
@@ -1513,10 +1504,9 @@ static void prregs(struct pt_regs *fp)
 
 static void cacheflush(void)
 {
-	int cmd;
-	unsigned long nflush;
+	unsigned long nflush, i;
 
-	cmd = inchar();
+	int cmd = inchar();
 	if (cmd != 'i')
 		termch = cmd;
 	scanhex((void *)&adrs);
@@ -1524,23 +1514,30 @@ static void cacheflush(void)
 		termch = 0;
 	nflush = 1;
 	scanhex(&nflush);
-	nflush = (nflush + L1_CACHE_BYTES - 1) / L1_CACHE_BYTES;
-	if (setjmp(bus_error_jmp) == 0) {
-		catch_memory_errors = 1;
-		sync();
 
-		if (cmd != 'i') {
-			for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
-				cflush((void *) adrs);
-		} else {
-			for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES)
-				cinval((void *) adrs);
-		}
-		sync();
-		/* wait a little while to see if we get a machine check */
-		__delay(200);
+	if (setjmp(bus_error_jmp) != 0) {
+		catch_memory_errors = 0;
+		return;
 	}
-	catch_memory_errors = 0;
+	catch_memory_errors = 1;
+	sync();
+
+	/* First flush/invalidate data caches */
+	if (cmd != 'i') {
+		FOR_EACH_CACHELINE(i, adrs, adrs + nflush, dcache)
+			dcbf(i);
+	} else {
+		FOR_EACH_CACHELINE(i, adrs, adrs + nflush, dcache)
+			dcbi(i);
+	}
+
+	/* Now invalidate instruction caches */
+	FOR_EACH_CACHELINE(i, adrs, adrs + nflush, icache)
+		icbi(i);
+
+	sync();
+	/* wait a little while to see if we get a machine check */
+	__delay(200);
 }
 
 static unsigned long
diff --git a/drivers/macintosh/smu.c b/drivers/macintosh/smu.c
index 116a49c..04ead15 100644
--- a/drivers/macintosh/smu.c
+++ b/drivers/macintosh/smu.c
@@ -136,7 +136,9 @@ static void smu_start_cmd(void)
 	/* Flush command and data to RAM */
 	faddr = (unsigned long)smu->cmd_buf;
 	fend = faddr + smu->cmd_buf->length + 2;
-	flush_inval_dcache_range(faddr, fend);
+	flush_dcache_range(faddr, fend);
+	mb();
+	isync();
 
 
 	/* We also disable NAP mode for the duration of the command
@@ -198,7 +200,9 @@ static irqreturn_t smu_db_intr(int irq, void *arg)
 		 * reply length (it's only 2 cache lines anyway)
 		 */
 		faddr = (unsigned long)smu->cmd_buf;
-		flush_inval_dcache_range(faddr, faddr + 256);
+		flush_dcache_range(faddr, faddr + 256);
+		mb();
+		isync();
 
 		/* Now check ack */
 		ack = (~cmd->cmd) & 0xff;
-- 
1.7.2.5

^ permalink raw reply related

* Re: [PATCH] powerpc/44x: Fix typos '47x' and 'CONFIG_47x'
From: Suzuki Poulose @ 2011-11-15  2:30 UTC (permalink / raw)
  To: Paul Bolle; +Cc: Paul Mackerras, linuxppc-dev, linux-kernel
In-Reply-To: <1321309827.20271.146.camel@x61.thuisdomein>

On 11/15/11 04:00, Paul Bolle wrote:
> Commit 674bfa4855 ("powerpc/44x: Kexec support for PPC440X chipsets")
> used the Kconfig symbol '47x', and the macro 'CONFIG_47x'. Neither
> exist. These should have been 'PPC_47x' and 'CONFIG_PPC_47x'. Fix these
> typos.

Thanks for catching this. I have already sent a series which fixes the
same. (Sub: Kdump support for PPC440x ). But I think I missed one hunk in
the misc_32.S.

>
> Also fix a related preprocessor check at the top of kexec.h.
>

Thanks

Suzuki

^ permalink raw reply

* [PATCH] powerpc: panic if we can't instantiate RTAS
From: Anton Blanchard @ 2011-11-14 22:55 UTC (permalink / raw)
  To: benh, paulus; +Cc: linuxppc-dev


I had to debug a strange situation where all manner of things were
failing. SMT threads, storage and network were all completely broken.

The root cause was we couldn't find enough memory to instantiate RTAS -
this was a network install so the initrd was huge.

Instead of limping along and failing in mysterious ways we should just
panic up front if RTAS exists and we can't allocate space for it.

Signed-off-by: Anton Blanchard <anton@samba.org>
---

Index: linux-powerpc/arch/powerpc/kernel/prom_init.c
===================================================================
--- linux-powerpc.orig/arch/powerpc/kernel/prom_init.c	2011-11-03 10:49:02.735081551 +1100
+++ linux-powerpc/arch/powerpc/kernel/prom_init.c	2011-11-03 10:49:06.371143032 +1100
@@ -1579,10 +1579,8 @@ static void __init prom_instantiate_rtas
 		return;
 
 	base = alloc_down(size, PAGE_SIZE, 0);
-	if (base == 0) {
-		prom_printf("RTAS allocation failed !\n");
-		return;
-	}
+	if (base == 0)
+		prom_panic("Could not allocate memory for RTAS\n");
 
 	rtas_inst = call_prom("open", 1, 1, ADDR("/rtas"));
 	if (!IHANDLE_VALID(rtas_inst)) {

^ permalink raw reply

* [PATCH] powerpc: Copy down exception vectors after feature fixups
From: Anton Blanchard @ 2011-11-14 22:54 UTC (permalink / raw)
  To: benh, paulus, michael; +Cc: linuxppc-dev


kdump fails because we try to execute an HV only instruction. Feature
fixups are being applied after we copy the exception vectors down to 0
so they miss out on any updates.

We have always had this issue but it only became critical in v3.0
when we added CFAR support (breaks POWER5) and v3.1 when we added
POWERNV (breaks everyone).

Signed-off-by: Anton Blanchard <anton@samba.org>
Cc: <stable@kernel.org> [v3.0+]
---

Index: linux-build/arch/powerpc/include/asm/sections.h
===================================================================
--- linux-build.orig/arch/powerpc/include/asm/sections.h	2011-09-06 17:24:51.380399734 +1000
+++ linux-build/arch/powerpc/include/asm/sections.h	2011-11-14 11:07:52.167266682 +1100
@@ -8,7 +8,7 @@
 
 #ifdef __powerpc64__
 
-extern char _end[];
+extern char __end_interrupts[];
 
 static inline int in_kernel_text(unsigned long addr)
 {
Index: linux-build/arch/powerpc/kernel/kvm.c
===================================================================
--- linux-build.orig/arch/powerpc/kernel/kvm.c	2011-11-08 11:41:51.818584018 +1100
+++ linux-build/arch/powerpc/kernel/kvm.c	2011-11-14 11:07:52.167266682 +1100
@@ -132,7 +132,6 @@ static void kvm_patch_ins_b(u32 *inst, i
 	/* On relocatable kernels interrupts handlers and our code
 	   can be in different regions, so we don't patch them */
 
-	extern u32 __end_interrupts;
 	if ((ulong)inst < (ulong)&__end_interrupts)
 		return;
 #endif
Index: linux-build/arch/powerpc/include/asm/synch.h
===================================================================
--- linux-build.orig/arch/powerpc/include/asm/synch.h	2011-09-07 15:15:49.106458709 +1000
+++ linux-build/arch/powerpc/include/asm/synch.h	2011-11-14 11:07:52.167266682 +1100
@@ -13,6 +13,7 @@
 extern unsigned int __start___lwsync_fixup, __stop___lwsync_fixup;
 extern void do_lwsync_fixups(unsigned long value, void *fixup_start,
 			     void *fixup_end);
+extern void do_final_fixups(void);
 
 static inline void eieio(void)
 {
Index: linux-build/arch/powerpc/kernel/setup_64.c
===================================================================
--- linux-build.orig/arch/powerpc/kernel/setup_64.c	2011-11-08 11:41:51.822584088 +1100
+++ linux-build/arch/powerpc/kernel/setup_64.c	2011-11-14 11:07:52.167266682 +1100
@@ -359,6 +359,7 @@ void __init setup_system(void)
 			  &__start___fw_ftr_fixup, &__stop___fw_ftr_fixup);
 	do_lwsync_fixups(cur_cpu_spec->cpu_features,
 			 &__start___lwsync_fixup, &__stop___lwsync_fixup);
+	do_final_fixups();
 
 	/*
 	 * Unflatten the device-tree passed by prom_init or kexec
Index: linux-build/arch/powerpc/kernel/setup_32.c
===================================================================
--- linux-build.orig/arch/powerpc/kernel/setup_32.c	2011-11-08 11:41:51.822584088 +1100
+++ linux-build/arch/powerpc/kernel/setup_32.c	2011-11-14 11:07:52.171266753 +1100
@@ -107,6 +107,8 @@ notrace unsigned long __init early_init(
 			 PTRRELOC(&__start___lwsync_fixup),
 			 PTRRELOC(&__stop___lwsync_fixup));
 
+	do_final_fixups();
+
 	return KERNELBASE + offset;
 }
 
Index: linux-build/arch/powerpc/lib/feature-fixups.c
===================================================================
--- linux-build.orig/arch/powerpc/lib/feature-fixups.c	2011-09-07 15:15:49.146459439 +1000
+++ linux-build/arch/powerpc/lib/feature-fixups.c	2011-11-15 09:33:41.346993356 +1100
@@ -18,6 +18,8 @@
 #include <linux/init.h>
 #include <asm/cputable.h>
 #include <asm/code-patching.h>
+#include <asm/page.h>
+#include <asm/sections.h>
 
 
 struct fixup_entry {
@@ -128,6 +130,27 @@ void do_lwsync_fixups(unsigned long valu
 	}
 }
 
+void do_final_fixups(void)
+{
+#if defined(CONFIG_PPC64) && defined(CONFIG_RELOCATABLE)
+	int *src, *dest;
+	unsigned long length;
+
+	if (PHYSICAL_START == 0)
+		return;
+
+	src = (int *)(KERNELBASE + PHYSICAL_START);
+	dest = (int *)KERNELBASE;
+	length = (__end_interrupts - _stext) / sizeof(int);
+
+	while (length--) {
+		patch_instruction(dest, *src);
+		src++;
+		dest++;
+	}
+#endif
+}
+
 #ifdef CONFIG_FTR_FIXUP_SELFTEST
 
 #define check(x)	\

^ permalink raw reply

* [PATCH] powerpc/44x: Fix typos '47x' and 'CONFIG_47x'
From: Paul Bolle @ 2011-11-14 22:30 UTC (permalink / raw)
  To: Benjamin Herrenschmidt, Paul Mackerras
  Cc: linuxppc-dev, Suzuki Poulose, linux-kernel

Commit 674bfa4855 ("powerpc/44x: Kexec support for PPC440X chipsets")
used the Kconfig symbol '47x', and the macro 'CONFIG_47x'. Neither
exist. These should have been 'PPC_47x' and 'CONFIG_PPC_47x'. Fix these
typos.

Also fix a related preprocessor check at the top of kexec.h.

Signed-off-by: Paul Bolle <pebolle@tiscali.nl>
---
The commit explanation sounds very confident, but this is all just
educated guesswork. Entirely untested too (I haven't got the hardware
nor the toolchain). So this needs careful review. 

 arch/powerpc/Kconfig             |    2 +-
 arch/powerpc/include/asm/kexec.h |    3 ++-
 arch/powerpc/kernel/misc_32.S    |    2 +-
 3 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index b177caa..951e18f 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -345,7 +345,7 @@ config ARCH_ENABLE_MEMORY_HOTREMOVE
 
 config KEXEC
 	bool "kexec system call (EXPERIMENTAL)"
-	depends on (PPC_BOOK3S || FSL_BOOKE || (44x && !SMP && !47x)) && EXPERIMENTAL
+	depends on (PPC_BOOK3S || FSL_BOOKE || (44x && !SMP && !PPC_47x)) && EXPERIMENTAL
 	help
 	  kexec is a system call that implements the ability to shutdown your
 	  current kernel, and to start another kernel.  It is like a reboot
diff --git a/arch/powerpc/include/asm/kexec.h b/arch/powerpc/include/asm/kexec.h
index f921eb1..fadf513 100644
--- a/arch/powerpc/include/asm/kexec.h
+++ b/arch/powerpc/include/asm/kexec.h
@@ -2,7 +2,8 @@
 #define _ASM_POWERPC_KEXEC_H
 #ifdef __KERNEL__
 
-#if defined(CONFIG_FSL_BOOKE) || defined(CONFIG_44x)
+#if defined(CONFIG_FSL_BOOKE) || \
+	(defined(CONFIG_44x) && !defined(CONFIG_PPC_47x))
 
 /*
  * On FSL-BookE we setup a 1:1 mapping which covers the first 2GiB of memory
diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S
index f7d760a..7cd07b4 100644
--- a/arch/powerpc/kernel/misc_32.S
+++ b/arch/powerpc/kernel/misc_32.S
@@ -738,7 +738,7 @@ relocate_new_kernel:
 	mr      r5, r31
 
 	li	r0, 0
-#elif defined(CONFIG_44x)  && !defined(CONFIG_47x)
+#elif defined(CONFIG_44x)  && !defined(CONFIG_PPC_47x)
 
 /*
  * Code for setting up 1:1 mapping for PPC440x for KEXEC
-- 
1.7.4.4

^ permalink raw reply related

* Re: [PATCH 4/5] treewide: Convert uses of ATTRIB_NORETURN to __noreturn
From: Geert Uytterhoeven @ 2011-11-14 20:50 UTC (permalink / raw)
  To: Joe Perches
  Cc: Andrew Morton, Fenghua Yu, linux-s390, Tony Luck, linux-ia64,
	linux-mips, linux-sh, Heiko Carstens, linux-kernel, Ralf Baechle,
	David Howells, linux-m68k, Paul Mundt, Paul Mackerras,
	Chris Metcalf, Martin Schwidefsky, linux390, Koichi Yasutake,
	linuxppc-dev, linux-am33-list
In-Reply-To: <abb1d8b542872ef3bfd695e85d3b8a0fd70645b9.1320917558.git.joe@perches.com>

On Thu, Nov 10, 2011 at 10:41, Joe Perches <joe@perches.com> wrote:
> Use the more commonly used __noreturn instead of ATTRIB_NORETURN.
>
> Signed-off-by: Joe Perches <joe@perches.com>

For the m68k parts:
Acked-by: Geert Uytterhoeven <geert@linux-m68k.org>

Gr{oetje,eeting}s,

=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k=
.org

In personal conversations with technical people, I call myself a hacker. Bu=
t
when I'm talking to journalists I just say "programmer" or something like t=
hat.
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0=C2=A0 =C2=A0=C2=A0 -- Linus Torvalds

^ permalink raw reply

* Re: [PATCH 3/5] treewide: Remove useless NORET_TYPE macro and uses
From: Geert Uytterhoeven @ 2011-11-14 20:50 UTC (permalink / raw)
  To: Joe Perches
  Cc: Andrew Morton, Fenghua Yu, linux-s390, Tony Luck, linux-ia64,
	linux-mips, Peter Zijlstra, Heiko Carstens, linux-kernel,
	Ralf Baechle, linux-m68k, Paul Mackerras, Chris Metcalf,
	Martin Schwidefsky, linux390, Ingo Molnar, Haavard Skinnemoen,
	linuxppc-dev, Hans-Christian Egtvedt
In-Reply-To: <e69163f6245513b05d5d21c2f57b916931ad5bff.1320917557.git.joe@perches.com>

On Thu, Nov 10, 2011 at 10:41, Joe Perches <joe@perches.com> wrote:
> It's a very old and now unused prototype marking
> so just delete it.
>
> Neaten panic pointer argument style to keep checkpatch quiet.
>
> Signed-off-by: Joe Perches <joe@perches.com>

For the m68k parts:
Acked-by: Geert Uytterhoeven <geert@linux-m68k.org>

Gr{oetje,eeting}s,

=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k=
.org

In personal conversations with technical people, I call myself a hacker. Bu=
t
when I'm talking to journalists I just say "programmer" or something like t=
hat.
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0=C2=A0 =C2=A0=C2=A0 -- Linus Torvalds

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox