LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 6/6] crypto: talitos - sparse fix
From: Kim Phillips @ 2008-07-16 23:22 UTC (permalink / raw)
  To: linux-crypto; +Cc: linuxppc-dev, Herbert Xu

Signed-off-by: Kim Phillips <kim.phillips@freescale.com>
---
 drivers/crypto/talitos.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c
index a81265b..681c15f 100644
--- a/drivers/crypto/talitos.c
+++ b/drivers/crypto/talitos.c
@@ -848,7 +848,7 @@ static int sg_to_link_tbl(struct scatterlist *sg, int sg_count,
 
 	/* adjust (decrease) last one (or two) entry's len to cryptlen */
 	link_tbl_ptr--;
-	while (link_tbl_ptr->len <= (-cryptlen)) {
+	while (be16_to_cpu(link_tbl_ptr->len) <= (-cryptlen)) {
 		/* Empty this entry, and move to previous one */
 		cryptlen += be16_to_cpu(link_tbl_ptr->len);
 		link_tbl_ptr->len = 0;
-- 
1.5.6

^ permalink raw reply related

* Re: [PATCH 4/6] crypto: talitos - fix GFP flag usage
From: Kumar Gala @ 2008-07-16 23:33 UTC (permalink / raw)
  To: Kim Phillips; +Cc: linuxppc-dev, linux-crypto, Herbert Xu
In-Reply-To: <20080716182215.36c1bd11.kim.phillips@freescale.com>


On Jul 16, 2008, at 6:22 PM, Kim Phillips wrote:

> use GFP_ATOMIC when necessary; use atomic_t when allocating  
> submit_count.

why?

- k

^ permalink raw reply

* Re: [HOW] binutils-2.17 breaks the 2.6.26 kernel
From: Segher Boessenkool @ 2008-07-16 23:41 UTC (permalink / raw)
  To: Milton Miller; +Cc: ppcdev, Alan Modra
In-Reply-To: <1dce2aab6509053e60f7a59a30974749@bga.com>

> . = ALIGN(0x1000)   /* this align directive aparently gets lost
>                        when stripping the file */
>
> .rodata: AT (.rodata - LOAD_OFFSET): {
>   ...
> }
>
> the effects of that align were dropped during strip, shifting all
> following sections up in memory and the resulting failure.

The ELF headers show the .rodata section to have 256 byte alignment
only, but after the "bad" strip it isn't even aligned to that
anymore (file offset).  Curious.

I still can't reproduce this, but getting the bad binary now (it's
huge, heh).  We'll see.


Segher

^ permalink raw reply

* Re: [HOW] binutils-2.17 breaks the 2.6.26 kernel
From: Jon Smirl @ 2008-07-17  0:38 UTC (permalink / raw)
  To: Milton Miller; +Cc: ppcdev, Alan Modra
In-Reply-To: <1dce2aab6509053e60f7a59a30974749@bga.com>

On 7/16/08, Milton Miller <miltonm@bga.com> wrote:
> Hi.

Previous threads have mentioned that binutil-2.17 is broken for
building powerpc kernels. It is fixed in binutils-2.18.

I have encountered this and upgrading to 2.18 fixed my build. The
symptom is large kernel sizes and a long time in gzip. In my case it
was gziping a 2GB file.

>
>  I've been working with Debian bintuils 2.17-3 (which identifies
>  itself as 2.17) on my build box for some time.
>
>  When testing all-yes-config, I was getting warnings, but the
>  vmlinux was booting via kexec.
>
>  Since I was replicating the warnings from BFD about section lmas
>  overlapping in vmlinux.strip.$$, I was encouraged to actually try
>  booting the resulting stripped kernel.  After a false start (getting
>  the old binary) I ended up replicating the fail-to-boot some people
>  have reported on linuxppc-dev.
>
>  Digging into the failure, we were trying to copy *way* too much data
>  in copy_and_flush from after_prom.   I found the value loaded from
>  _klimit was something like 0x00002fea_00400000, not quite _end that
>  it was initialized.
>
>  I tracked this down to the .rodata and all sections following loosing
>  the inter-section alignment.
>
>
>  /DISCARD/ {
>   ....
>  }
>  text: AT( .text - LOAD_OFFSET): {
>   ....
>  }
>
>  . = ALIGN(0x1000)   /* this align directive aparently gets lost
>                        when stripping the file */
>
>  .rodata: AT (.rodata - LOAD_OFFSET): {
>   ...
>  }
>
>  the effects of that align were dropped during strip, shifting all
>  following sections up in memory and the resulting failure.
>
>  I don't know if the fault is ld or strip.
>
>  The behavior came between 2.6.24 and -next-20080710, but others
>  have suggested their kernels don't boot in the 2.6.25 to 2.6.26
>  transition, and a likely candidate is the addition of AT(x) to
>  set the lma, although we also switched form TEXT_TEXT macro in
>  include/asm-generic.h to a hand-rolled .text section.
>
>  Can we come up with a workaround?
>
>  thanks,
>  milton
>
>  _______________________________________________
>  Linuxppc-dev mailing list
>  Linuxppc-dev@ozlabs.org
>  https://ozlabs.org/mailman/listinfo/linuxppc-dev
>


-- 
Jon Smirl
jonsmirl@gmail.com

^ permalink raw reply

* Re: [HOW] binutils-2.17 breaks the 2.6.26 kernel
From: Gabriel Paubert @ 2008-07-17  0:49 UTC (permalink / raw)
  To: Jon Smirl; +Cc: ppcdev, Alan Modra, Milton Miller
In-Reply-To: <9e4733910807161738g58da8bd7v78e9d50dc4d846cb@mail.gmail.com>

On Wed, Jul 16, 2008 at 08:38:14PM -0400, Jon Smirl wrote:
> On 7/16/08, Milton Miller <miltonm@bga.com> wrote:
> > Hi.
> 
> Previous threads have mentioned that binutil-2.17 is broken for
> building powerpc kernels. It is fixed in binutils-2.18.
> 
> I have encountered this and upgrading to 2.18 fixed my build. The
> symptom is large kernel sizes and a long time in gzip. In my case it
> was gziping a 2GB file.

Only? Mine was over 3GB :-)

I've not yet had time to update the binutils (the machine has
a standard Debian Etch and I have trouble when adding Lenny
sources).

I also bisected it for fun and got 366234f6 as the culprit.

	Gabriel

^ permalink raw reply

* Re: [PATCH] Add AMCC Arches 460GT eval board support to platforms/44x
From: Josh Boyer @ 2008-07-17  2:15 UTC (permalink / raw)
  To: Arnd Bergmann; +Cc: linuxppc-dev, Victor Gallardo, fkan, linuxppc-embedded
In-Reply-To: <200807170058.53599.arnd@arndb.de>

On Thu, 2008-07-17 at 00:58 +0200, Arnd Bergmann wrote:
> On Wednesday 16 July 2008, Grant Likely wrote:
> > 
> > > Shouldn't it be enough to have a common compatible value in each
> > > of these boards, e.g. "amcc,generic-ppc44x" and then just ignore the
> > > specific type unless you need to do something special?
> > 
> > This is bad for the same reason that "amcc,44x-<blah>" compatible values
> > are bad in device nodes.  The definition of '*-44x-*' changes over time as
> > new parts are added.  Compatible values should always reflect an exact
> > part number.
> 
> I agree in general, but I also think that all 44x boards should be
> regarded as the same machine time, in the same way that all powermacs
> are detected as compatible with "Power Macintosh" or "MacRISC", or
> how all sorts of serial ports claim compatibility with i8250.
> 
> For classic SOCs like 4xx or 52xx, the SOC familiy more or less defines
> the platform, and all the details about peripherals can be expressed
> in the device tree elsewhere.

This is what Grant has done for 52xx and what I was talking about with
"4xx_board.c", though 4xx_soc.c is probably a better name.

My hesitation is that while it's true today that 440<chip name> defines
the SoC, it might not always be.  And the Virtex boards are craziness
with the core and FPGA setup.  So we need to be careful a bit when
chosing what do "bind" to for generics.

> If one board is so different that you need a separate board setup
> in the kernel, it should simply not claim compatibility with the
> SOC platform.

Right.  Today we only have a few "overrides" in 4xx.  Namely
Canyonlands/Glacier, and Bamboo/Yosemite (Sequoia/Rainier should also
really be that way, but they aren't).  So if we decide to go to a
different scheme, it shouldn't be a big deal to switch.

josh

^ permalink raw reply

* Re: [PATCH] Add AMCC Arches 460GT eval board support to platforms/44x
From: Segher Boessenkool @ 2008-07-17  3:15 UTC (permalink / raw)
  To: Josh Boyer; +Cc: linuxppc-dev, Victor Gallardo, fkan, linuxppc-embedded
In-Reply-To: <20080716103752.463e00cb@zod.rchland.ibm.com>

>>> And then you don't need this file at all.  Just add a
>>> "amcc,canyonlands" string to your root node compatible property.
>>
>> No!  Don't do this because it is not true!

If the board actually _is_ compatible to the canyonlands board (it
only _adds_ stuff, doesn't change things or takes away things), it
is perfectly valid to declare it compatible, since it _is_.

In my opinion, for the root compatible value, it is also okay to
declare a board compatible if it is only "largely" compatible,
just has some little differences -- esp. if you're declaring a
board to be compatible to some reference design.  This does of
course have downsides as well.

> Meh. You're splitting hairs.  It _is_ true from a kernel perspective.

That doesn't matter.  The device tree describes the hardware, it doesn't
matter what the Linux kernel does.  For one thing, the kernel isn't
necessarily the only OS (or other client) to run with this DTS; also,
the kernel is a moving target, while the DTS can be burned into ROM.

>> Instead, add your board name to canyonlands.c in canyonlands_probe().
>> It's not the most scalable solution, but it keeps you from lying about
>> your hardware in the .dts file.
>
> That could also be done.  Frankly though, if you look at the existing
> board.c files in there now, none of them are special.  The device tree
> really provides the differences these days, not the C code.

Yes.  It would be more scalable if the platform probe code checks
the device tree for the features it expects (certain CPU, certain
interrupt controller, certain chipsets / bridges), instead of it
checking the root "compatible" property.

> I'm this
> || close to just killing them all and doing a 4xx_board.c file that
> does the right thing based on the few boards that have differences.

Oh, the kernel code even considers these things to be different
platforms?  Insane :-)


Segher

^ permalink raw reply

* Re: [PATCH] Add AMCC Arches 460GT eval board support to platforms/44x
From: Segher Boessenkool @ 2008-07-17  3:19 UTC (permalink / raw)
  To: Grant Likely
  Cc: linuxppc-dev, Victor Gallardo, fkan, Arnd Bergmann,
	linuxppc-embedded
In-Reply-To: <20080716154646.GH24045@secretlab.ca>

>> Shouldn't it be enough to have a common compatible value in each
>> of these boards, e.g. "amcc,generic-ppc44x" and then just ignore the
>> specific type unless you need to do something special?
>
> This is bad for the same reason that "amcc,44x-<blah>" compatible 
> values
> are bad in device nodes.  The definition of '*-44x-*' changes over 
> time as
> new parts are added.  Compatible values should always reflect an exact
> part number.

Erm, no.

"compatible" entries should always contain the real part name to reduce
the chance that separate parties come up with the same "compatible"
name for two different devices.

Other than that, the name really doesn't matter, it's just _some_
string that uniquely identifies a device; and the device bindings will
document what is what.

Of course, if no binding is written, it becomes a lot more important
that names have a sane value ;-)


Segher

^ permalink raw reply

* Re: [PATCH] Add AMCC Arches 460GT eval board support to platforms/44x
From: Segher Boessenkool @ 2008-07-17  3:24 UTC (permalink / raw)
  To: Arnd Bergmann; +Cc: linuxppc-dev, Victor Gallardo, fkan, linuxppc-embedded
In-Reply-To: <200807170058.53599.arnd@arndb.de>

>>> Shouldn't it be enough to have a common compatible value in each
>>> of these boards, e.g. "amcc,generic-ppc44x" and then just ignore the
>>> specific type unless you need to do something special?
>>
>> This is bad for the same reason that "amcc,44x-<blah>" compatible=20
>> values
>> are bad in device nodes. =A0The definition of '*-44x-*' changes over=20=

>> time as
>> new parts are added. =A0Compatible values should always reflect an =
exact
>> part number.
>
> I agree in general, but I also think that all 44x boards should be
> regarded as the same machine time, in the same way that all powermacs
> are detected as compatible with "Power Macintosh" or "MacRISC", or
> how all sorts of serial ports claim compatibility with i8250.

And they can do that because a binding for those "compatible" names
exists, that describes exactly what it means for a device to be "i8250"
or "MacRISC" (well, in that last case, maybe such a binding exists, or
maybe it doesn't, but we don't know about it anyway, sigh).


Segher

^ permalink raw reply

* Re: [PATCH v3] leds: implement OpenFirmare GPIO LED driver
From: Grant Likely @ 2008-07-17  4:15 UTC (permalink / raw)
  To: Trent Piepho; +Cc: Stephen Rothwell, linux-kernel, linuxppc-dev, Richard Purdie
In-Reply-To: <Pine.LNX.4.64.0807161546010.12709@t2.domain.actdsltmp>

On Wed, Jul 16, 2008 at 04:18:52PM -0700, Trent Piepho wrote:
> On Tue, 15 Jul 2008, Anton Vorontsov wrote:
> > Despite leds-gpio and leds-openfirmware-gpio similar purposes, there
> > is not much code can be shared between the two drivers (both are mostly
> > driver bindings anyway).
> 
> Why can't this driver use the existing gpio-led driver?  Basically, do
> something like this:
> 
> of_gpio_leds_probe(...)
> {
>  	gpio = of_get_gpio(np, 0);
>  	label = of_get_property(np, "label", NULL);
> 
>  	struct gpio_led led = {
>  		.name = label,
>  		.gpio = gpio,
>  	};
> 
>  	pdev = platform_device_register_simple("leds-gpio", 0, NULL, 0);
>  	platform_device_add_data(pdev, &led, sizeof(led));
> }

Ugh; that means registering *2* 'struct device' with the kernel instead of
one.  One as a platform device and one as an of_platform device.
It's bad enough that the LED scheme we're using for OF bindings has a
separate registration for every single LED.

Now that it comes to it, I worry that this driver takes the wrong
approach.  The number of resources dedicated per LED in this driver
seems pretty loony to me (one of_platform device per LED).  The fact
that the binding specifies one node per LED makes of_platform not a very
efficient solution.

I think it would be better to have a module that scans the device tree
for LED nodes and registers a single leds-gpio platform device for the
whole lot.

Thoughts?

g.

^ permalink raw reply

* [PATCH] powerpc: Use WARN_ON(1) instead of __WARN()
From: Michael Ellerman @ 2008-07-17  4:46 UTC (permalink / raw)
  To: linuxppc-dev

__WARN() is not defined for all configs, use WARN_ON(1) instead.

Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---
 arch/powerpc/lib/feature-fixups.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/arch/powerpc/lib/feature-fixups.c b/arch/powerpc/lib/feature-fixups.c
index 4e43702..8c5a03b 100644
--- a/arch/powerpc/lib/feature-fixups.c
+++ b/arch/powerpc/lib/feature-fixups.c
@@ -99,7 +99,7 @@ void do_feature_fixups(unsigned long value, void *fixup_start, void *fixup_end)
 
 	for (; fcur < fend; fcur++) {
 		if (patch_feature_section(value, fcur)) {
-			__WARN();
+			WARN_ON(1);
 			printk("Unable to patch feature section at %p - %p" \
 				" with %p - %p\n",
 				calc_addr(fcur, fcur->start_off),
-- 
1.5.5

^ permalink raw reply related

* [PATCH] fbdev: Teaches offb about palette on radeon r5xx/r6xx
From: Benjamin Herrenschmidt @ 2008-07-17  5:05 UTC (permalink / raw)
  To: Linux Fbdev development list; +Cc: linuxppc-dev list

The offb driver already has a collection of hacks to be able to set
the palette on various chips. This adds support for r5xx/r6xx radeons.

This is needed as offb is the only console solution on these currently
and the firmware in some cases sets a really bad color palette. This
fixes using some Radeon X16xx on the Powerstation for example.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---

I'm happy to merge that via the powerpc tree if there is no objection
as offb is a powerpc-only driver at this stage.

Index: linux-work/drivers/video/offb.c
===================================================================
--- linux-work.orig/drivers/video/offb.c	2008-07-14 15:57:58.000000000 +1000
+++ linux-work/drivers/video/offb.c	2008-07-15 11:12:56.000000000 +1000
@@ -47,6 +47,7 @@ enum {
 	cmap_M3B,		/* ATI Rage Mobility M3 Head B */
 	cmap_radeon,		/* ATI Radeon */
 	cmap_gxt2000,		/* IBM GXT2000 */
+	cmap_avivo,		/* ATI R5xx */
 };
 
 struct offb_par {
@@ -58,26 +59,36 @@ struct offb_par {
 
 struct offb_par default_par;
 
-    /*
-     *  Interface used by the world
-     */
-
-static int offb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
-			  u_int transp, struct fb_info *info);
-static int offb_blank(int blank, struct fb_info *info);
-
 #ifdef CONFIG_PPC32
 extern boot_infos_t *boot_infos;
 #endif
 
-static struct fb_ops offb_ops = {
-	.owner		= THIS_MODULE,
-	.fb_setcolreg	= offb_setcolreg,
-	.fb_blank	= offb_blank,
-	.fb_fillrect	= cfb_fillrect,
-	.fb_copyarea	= cfb_copyarea,
-	.fb_imageblit	= cfb_imageblit,
-};
+/* Definitions used by the Avivo palette hack */
+#define AVIVO_DC_LUT_RW_SELECT                  0x6480
+#define AVIVO_DC_LUT_RW_MODE                    0x6484
+#define AVIVO_DC_LUT_RW_INDEX                   0x6488
+#define AVIVO_DC_LUT_SEQ_COLOR                  0x648c
+#define AVIVO_DC_LUT_PWL_DATA                   0x6490
+#define AVIVO_DC_LUT_30_COLOR                   0x6494
+#define AVIVO_DC_LUT_READ_PIPE_SELECT           0x6498
+#define AVIVO_DC_LUT_WRITE_EN_MASK              0x649c
+#define AVIVO_DC_LUT_AUTOFILL                   0x64a0
+
+#define AVIVO_DC_LUTA_CONTROL                   0x64c0
+#define AVIVO_DC_LUTA_BLACK_OFFSET_BLUE         0x64c4
+#define AVIVO_DC_LUTA_BLACK_OFFSET_GREEN        0x64c8
+#define AVIVO_DC_LUTA_BLACK_OFFSET_RED          0x64cc
+#define AVIVO_DC_LUTA_WHITE_OFFSET_BLUE         0x64d0
+#define AVIVO_DC_LUTA_WHITE_OFFSET_GREEN        0x64d4
+#define AVIVO_DC_LUTA_WHITE_OFFSET_RED          0x64d8
+
+#define AVIVO_DC_LUTB_CONTROL                   0x6cc0
+#define AVIVO_DC_LUTB_BLACK_OFFSET_BLUE         0x6cc4
+#define AVIVO_DC_LUTB_BLACK_OFFSET_GREEN        0x6cc8
+#define AVIVO_DC_LUTB_BLACK_OFFSET_RED          0x6ccc
+#define AVIVO_DC_LUTB_WHITE_OFFSET_BLUE         0x6cd0
+#define AVIVO_DC_LUTB_WHITE_OFFSET_GREEN        0x6cd4
+#define AVIVO_DC_LUTB_WHITE_OFFSET_RED          0x6cd8
 
     /*
      *  Set a single color register. The values supplied are already
@@ -160,6 +171,17 @@ static int offb_setcolreg(u_int regno, u
 		out_le32(((unsigned __iomem *) par->cmap_adr) + regno,
 			 (red << 16 | green << 8 | blue));
 		break;
+	case cmap_avivo:
+		/* Write to both LUTs for now */
+		writel(1, par->cmap_adr + AVIVO_DC_LUT_RW_SELECT);
+		writeb(regno, par->cmap_adr + AVIVO_DC_LUT_RW_INDEX);
+		writel(((red) << 22) | ((green) << 12) | ((blue) << 2),
+		       par->cmap_adr + AVIVO_DC_LUT_30_COLOR);
+		writel(0, par->cmap_adr + AVIVO_DC_LUT_RW_SELECT);
+		writeb(regno, par->cmap_adr + AVIVO_DC_LUT_RW_INDEX);
+		writel(((red) << 22) | ((green) << 12) | ((blue) << 2),
+		       par->cmap_adr + AVIVO_DC_LUT_30_COLOR);
+		break;
 	}
 
 	return 0;
@@ -216,12 +238,59 @@ static int offb_blank(int blank, struct 
 				out_le32(((unsigned __iomem *) par->cmap_adr) + i,
 					 0);
 				break;
+			case cmap_avivo:
+				writel(1, par->cmap_adr + AVIVO_DC_LUT_RW_SELECT);
+				writeb(i, par->cmap_adr + AVIVO_DC_LUT_RW_INDEX);
+				writel(0, par->cmap_adr + AVIVO_DC_LUT_30_COLOR);
+				writel(0, par->cmap_adr + AVIVO_DC_LUT_RW_SELECT);
+				writeb(i, par->cmap_adr + AVIVO_DC_LUT_RW_INDEX);
+				writel(0, par->cmap_adr + AVIVO_DC_LUT_30_COLOR);
+				break;
 			}
 	} else
 		fb_set_cmap(&info->cmap, info);
 	return 0;
 }
 
+static int offb_set_par(struct fb_info *info)
+{
+	struct offb_par *par = (struct offb_par *) info->par;
+
+	/* On avivo, initialize palette control */
+	if (par->cmap_type == cmap_avivo) {
+		writel(0, par->cmap_adr + AVIVO_DC_LUTA_CONTROL);
+		writel(0, par->cmap_adr + AVIVO_DC_LUTA_BLACK_OFFSET_BLUE);
+		writel(0, par->cmap_adr + AVIVO_DC_LUTA_BLACK_OFFSET_GREEN);
+		writel(0, par->cmap_adr + AVIVO_DC_LUTA_BLACK_OFFSET_RED);
+		writel(0x0000ffff, par->cmap_adr + AVIVO_DC_LUTA_WHITE_OFFSET_BLUE);
+		writel(0x0000ffff, par->cmap_adr + AVIVO_DC_LUTA_WHITE_OFFSET_GREEN);
+		writel(0x0000ffff, par->cmap_adr + AVIVO_DC_LUTA_WHITE_OFFSET_RED);
+		writel(0, par->cmap_adr + AVIVO_DC_LUTB_CONTROL);
+		writel(0, par->cmap_adr + AVIVO_DC_LUTB_BLACK_OFFSET_BLUE);
+		writel(0, par->cmap_adr + AVIVO_DC_LUTB_BLACK_OFFSET_GREEN);
+		writel(0, par->cmap_adr + AVIVO_DC_LUTB_BLACK_OFFSET_RED);
+		writel(0x0000ffff, par->cmap_adr + AVIVO_DC_LUTB_WHITE_OFFSET_BLUE);
+		writel(0x0000ffff, par->cmap_adr + AVIVO_DC_LUTB_WHITE_OFFSET_GREEN);
+		writel(0x0000ffff, par->cmap_adr + AVIVO_DC_LUTB_WHITE_OFFSET_RED);
+		writel(1, par->cmap_adr + AVIVO_DC_LUT_RW_SELECT);
+		writel(0, par->cmap_adr + AVIVO_DC_LUT_RW_MODE);
+		writel(0x0000003f, par->cmap_adr + AVIVO_DC_LUT_WRITE_EN_MASK);
+		writel(0, par->cmap_adr + AVIVO_DC_LUT_RW_SELECT);
+		writel(0, par->cmap_adr + AVIVO_DC_LUT_RW_MODE);
+		writel(0x0000003f, par->cmap_adr + AVIVO_DC_LUT_WRITE_EN_MASK);
+	}
+	return 0;
+}
+
+static struct fb_ops offb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_setcolreg	= offb_setcolreg,
+	.fb_set_par	= offb_set_par,
+	.fb_blank	= offb_blank,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+};
 
 static void __iomem *offb_map_reg(struct device_node *np, int index,
 				  unsigned long offset, unsigned long size)
@@ -245,6 +314,59 @@ static void __iomem *offb_map_reg(struct
 	return ioremap(taddr + offset, size);
 }
 
+static void offb_init_palette_hacks(struct fb_info *info, struct device_node *dp,
+				    const char *name, unsigned long address)
+{
+	struct offb_par *par = (struct offb_par *) info->par;
+
+	if (dp && !strncmp(name, "ATY,Rage128", 11)) {
+		par->cmap_adr = offb_map_reg(dp, 2, 0, 0x1fff);
+		if (par->cmap_adr)
+			par->cmap_type = cmap_r128;
+	} else if (dp && (!strncmp(name, "ATY,RageM3pA", 12)
+			  || !strncmp(name, "ATY,RageM3p12A", 14))) {
+		par->cmap_adr = offb_map_reg(dp, 2, 0, 0x1fff);
+		if (par->cmap_adr)
+			par->cmap_type = cmap_M3A;
+	} else if (dp && !strncmp(name, "ATY,RageM3pB", 12)) {
+		par->cmap_adr = offb_map_reg(dp, 2, 0, 0x1fff);
+		if (par->cmap_adr)
+			par->cmap_type = cmap_M3B;
+	} else if (dp && !strncmp(name, "ATY,Rage6", 9)) {
+		par->cmap_adr = offb_map_reg(dp, 1, 0, 0x1fff);
+		if (par->cmap_adr)
+			par->cmap_type = cmap_radeon;
+	} else if (!strncmp(name, "ATY,", 4)) {
+		unsigned long base = address & 0xff000000UL;
+		par->cmap_adr =
+			ioremap(base + 0x7ff000, 0x1000) + 0xcc0;
+		par->cmap_data = par->cmap_adr + 1;
+		par->cmap_type = cmap_m64;
+	} else if (dp && (of_device_is_compatible(dp, "pci1014,b7") ||
+			  of_device_is_compatible(dp, "pci1014,21c"))) {
+		par->cmap_adr = offb_map_reg(dp, 0, 0x6000, 0x1000);
+		if (par->cmap_adr)
+			par->cmap_type = cmap_gxt2000;
+	} else if (dp && !strncmp(name, "vga,Display-", 12)) {
+		/* Look for AVIVO initialized by SLOF */
+		struct device_node *pciparent = of_get_parent(dp);
+		const u32 *vid, *did;
+		vid = of_get_property(pciparent, "vendor-id", NULL);
+		did = of_get_property(pciparent, "device-id", NULL);
+		/* This will match most R5xx */
+		if (vid && did && *vid == 0x1002 &&
+		    ((*did >= 0x7100 && *did < 0x7800) ||
+		     (*did >= 0x9400))) {
+			par->cmap_adr = offb_map_reg(pciparent, 2, 0, 0x10000);
+			if (par->cmap_adr)
+				par->cmap_type = cmap_avivo;
+		}
+		of_node_put(pciparent);
+	}
+	info->fix.visual = (par->cmap_type != cmap_unknown) ?
+		FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_STATIC_PSEUDOCOLOR;
+}
+
 static void __init offb_init_fb(const char *name, const char *full_name,
 				int width, int height, int depth,
 				int pitch, unsigned long address,
@@ -283,6 +405,7 @@ static void __init offb_init_fb(const ch
 
 	fix = &info->fix;
 	var = &info->var;
+	info->par = par;
 
 	strcpy(fix->id, "OFfb ");
 	strncat(fix->id, name, sizeof(fix->id) - sizeof("OFfb "));
@@ -298,39 +421,9 @@ static void __init offb_init_fb(const ch
 	fix->type_aux = 0;
 
 	par->cmap_type = cmap_unknown;
-	if (depth == 8) {
-		if (dp && !strncmp(name, "ATY,Rage128", 11)) {
-			par->cmap_adr = offb_map_reg(dp, 2, 0, 0x1fff);
-			if (par->cmap_adr)
-				par->cmap_type = cmap_r128;
-		} else if (dp && (!strncmp(name, "ATY,RageM3pA", 12)
-				  || !strncmp(name, "ATY,RageM3p12A", 14))) {
-			par->cmap_adr = offb_map_reg(dp, 2, 0, 0x1fff);
-			if (par->cmap_adr)
-				par->cmap_type = cmap_M3A;
-		} else if (dp && !strncmp(name, "ATY,RageM3pB", 12)) {
-			par->cmap_adr = offb_map_reg(dp, 2, 0, 0x1fff);
-			if (par->cmap_adr)
-				par->cmap_type = cmap_M3B;
-		} else if (dp && !strncmp(name, "ATY,Rage6", 9)) {
-			par->cmap_adr = offb_map_reg(dp, 1, 0, 0x1fff);
-			if (par->cmap_adr)
-				par->cmap_type = cmap_radeon;
-		} else if (!strncmp(name, "ATY,", 4)) {
-			unsigned long base = address & 0xff000000UL;
-			par->cmap_adr =
-			    ioremap(base + 0x7ff000, 0x1000) + 0xcc0;
-			par->cmap_data = par->cmap_adr + 1;
-			par->cmap_type = cmap_m64;
-		} else if (dp && (of_device_is_compatible(dp, "pci1014,b7") ||
-				  of_device_is_compatible(dp, "pci1014,21c"))) {
-			par->cmap_adr = offb_map_reg(dp, 0, 0x6000, 0x1000);
-			if (par->cmap_adr)
-				par->cmap_type = cmap_gxt2000;
-		}
-		fix->visual = (par->cmap_type != cmap_unknown) ?
-			FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_STATIC_PSEUDOCOLOR;
-	} else
+	if (depth == 8)
+		offb_init_palette_hacks(info, dp, name, address);
+	else
 		fix->visual = FB_VISUAL_TRUECOLOR;
 
 	var->xoffset = var->yoffset = 0;
@@ -395,7 +488,6 @@ static void __init offb_init_fb(const ch
 
 	info->fbops = &offb_ops;
 	info->screen_base = ioremap(address, fix->smem_len);
-	info->par = par;
 	info->pseudo_palette = (void *) (info + 1);
 	info->flags = FBINFO_DEFAULT | foreign_endian;
 

^ permalink raw reply

* Re: [PATCH v3] leds: implement OpenFirmare GPIO LED driver
From: Trent Piepho @ 2008-07-17  5:13 UTC (permalink / raw)
  To: Grant Likely; +Cc: Stephen Rothwell, linux-kernel, linuxppc-dev, Richard Purdie
In-Reply-To: <20080717041531.GA27243@secretlab.ca>

on Wed, 16 Jul 2008, Grant Likely wrote:
> On Wed, Jul 16, 2008 at 04:18:52PM -0700, Trent Piepho wrote:
>> On Tue, 15 Jul 2008, Anton Vorontsov wrote:
>>> Despite leds-gpio and leds-openfirmware-gpio similar purposes, there
>>> is not much code can be shared between the two drivers (both are mostly
>>> driver bindings anyway).
>>
>> Why can't this driver use the existing gpio-led driver?  Basically, do
>> something like this:
>>
>
> Ugh; that means registering *2* 'struct device' with the kernel instead of
> one.  One as a platform device and one as an of_platform device.
> It's bad enough that the LED scheme we're using for OF bindings has a
> separate registration for every single LED.

Ok, how about adding code the existing leds-gpio driver so that it can creates
LEDs from of_platform devices too?

I've made a patch to do this and it works ok.  The code added to leds-gpio is
about half what was involved in Anton's new driver.  What I did was re-factor
the existing platform device probe function to use a new function that creates
a single led.  Then a new of_platform probe function can use it too.  That way
most of the probe code is shared.  remove, suspend and resume aren't shared,
but they're short.  And the existing code to actually drive the led gets
reused as is.

There is still one of_platform device per led because of how the bindings work
(but that could be changed with new bindings), but there are zero extra
platform devices created.

Here's an example patch.  It won't apply to the git kernel as is, but should
make it clear how this works.

diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c
index a4a2838..12e681e 100644
--- a/drivers/leds/leds-gpio.c
+++ b/drivers/leds/leds-gpio.c
@@ -71,11 +71,45 @@ static int gpio_blink_set(struct led_classdev *led_cdev,
  	return led_dat->platform_gpio_blink_set(led_dat->gpio, delay_on, delay_off);
  }

+static int create_gpio_led(struct gpio_led *cur_led,
+	struct gpio_led_data *led_dat, struct device *parent,
+	int (*blink_set)(unsigned, unsigned long *, unsigned long *))
+
+{
+	int ret;
+
+	ret = gpio_request(cur_led->gpio, cur_led->name);
+	if (ret < 0)
+		return ret;
+
+	led_dat->cdev.name = cur_led->name;
+	led_dat->cdev.default_trigger = cur_led->default_trigger;
+	led_dat->gpio = cur_led->gpio;
+	led_dat->can_sleep = gpio_cansleep(cur_led->gpio);
+	led_dat->active_low = cur_led->active_low;
+	if (blink_set) {
+		led_dat->platform_gpio_blink_set = blink_set;
+		led_dat->cdev.blink_set = gpio_blink_set;
+	}
+	led_dat->cdev.brightness_set = gpio_led_set;
+	led_dat->cdev.brightness = cur_led->start_on ? LED_FULL : LED_OFF;
+
+	gpio_direction_output(led_dat->gpio,
+			      led_dat->active_low ^ cur_led->start_on);
+
+	INIT_WORK(&led_dat->work, gpio_led_work);
+
+	ret = led_classdev_register(parent, &led_dat->cdev);
+	if (ret < 0)
+		gpio_free(led_dat->gpio);
+
+	return ret;
+}
+
  static int gpio_led_probe(struct platform_device *pdev)
  {
  	struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
-	struct gpio_led *cur_led;
-	struct gpio_led_data *leds_data, *led_dat;
+	struct gpio_led_data *leds_data;
  	int i, ret = 0;

  	if (!pdata)
@@ -87,36 +121,10 @@ static int gpio_led_probe(struct platform_device *pdev)
  		return -ENOMEM;

  	for (i = 0; i < pdata->num_leds; i++) {
-		cur_led = &pdata->leds[i];
-		led_dat = &leds_data[i];
-
-		ret = gpio_request(cur_led->gpio, cur_led->name);
+		ret = create_gpio_led(&pdata->leds[i], &leds_data[i],
+				      &pdev->dev, pdata->gpio_blink_set);
  		if (ret < 0)
  			goto err;
-
-		led_dat->cdev.name = cur_led->name;
-		led_dat->cdev.default_trigger = cur_led->default_trigger;
-		led_dat->gpio = cur_led->gpio;
-		led_dat->can_sleep = gpio_cansleep(cur_led->gpio);
-		led_dat->active_low = cur_led->active_low;
-		if (pdata->gpio_blink_set) {
-			led_dat->platform_gpio_blink_set = pdata->gpio_blink_set;
-			led_dat->cdev.blink_set = gpio_blink_set;
-		}
-		led_dat->cdev.brightness_set = gpio_led_set;
-		led_dat->cdev.brightness =
-			cur_led->start_on ? LED_FULL : LED_OFF;
-
-		gpio_direction_output(led_dat->gpio,
-				      led_dat->active_low ^ cur_led->start_on);
-
-		INIT_WORK(&led_dat->work, gpio_led_work);
-
-		ret = led_classdev_register(&pdev->dev, &led_dat->cdev);
-		if (ret < 0) {
-			gpio_free(led_dat->gpio);
-			goto err;
-		}
  	}

  	platform_set_drvdata(pdev, leds_data);
@@ -217,3 +225,105 @@ MODULE_AUTHOR("Raphael Assenat <raph@8d.com>");
  MODULE_DESCRIPTION("GPIO LED driver");
  MODULE_LICENSE("GPL");
  MODULE_ALIAS("platform:leds-gpio");
+
+
+/* #ifdef CONFIG_LEDS_GPIO_OF */
+/* OpenFirmware bindings */
+#include <linux/of_platform.h>
+
+/* crap for old kernel, ignore */
+static inline const char *dev_name(struct device *dev)
+{ return dev->bus_id; }
+int of_get_gpio(struct device_node *np, int index)
+{ const u32 *pp = of_get_property(np, "gpio", NULL); return pp ? *pp : -1; }
+
+static int __devinit of_gpio_leds_probe(struct of_device *ofdev,
+					const struct of_device_id *match)
+{
+	struct device_node *np = ofdev->node;
+	struct gpio_led led;
+	struct gpio_led_data *led_dat;
+	int ret;
+
+	led_dat = kzalloc(sizeof(*led_dat), GFP_KERNEL);
+	if (!led_dat)
+		return -ENOMEM;
+
+	memset(&led, 0, sizeof(led));
+	led.gpio = of_get_gpio(np, 0);
+	led.name = of_get_property(np, "label", NULL);
+	if (!led.name)
+		led.name = dev_name(&ofdev->dev);
+
+	ret = create_gpio_led(&led, led_dat, &ofdev->dev, NULL);
+	if (ret < 0) {
+		kfree(led_dat);
+		return ret;
+	}
+
+	dev_set_drvdata(&ofdev->dev, led_dat);
+
+	return 0;
+}
+
+static int __devexit of_gpio_leds_remove(struct of_device *ofdev)
+{
+	struct gpio_led_data *led = dev_get_drvdata(&ofdev->dev);
+
+	led_classdev_unregister(&led->cdev);
+	cancel_work_sync(&led->work);
+	gpio_free(led->gpio);
+	kfree(led);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int of_gpio_led_suspend(struct of_device *ofdev, pm_message_t state)
+{
+	struct gpio_led_data *led = dev_get_drvdata(&ofdev->dev);
+
+	led_classdev_suspend(&led->cdev);
+	return 0;
+}
+
+static int of_gpio_led_resume(struct of_device *ofdev)
+{
+	struct gpio_led_data *led = dev_get_drvdata(&ofdev->dev);
+
+	led_classdev_resume(&led->cdev);
+	return 0;
+}
+#else
+#define of_gpio_led_suspend NULL
+#define of_gpio_led_resume NULL
+#endif /* CONFIG_PM */
+
+static const struct of_device_id of_gpio_leds_match[] = {
+	{ .compatible = "gpio-led", },
+	{},
+};
+
+static struct of_platform_driver of_gpio_leds_driver = {
+	.driver = {
+		.name = "of_gpio_leds",
+		.owner = THIS_MODULE,
+	},
+	.match_table = of_gpio_leds_match,
+	.probe = of_gpio_leds_probe,
+	.remove = __devexit_p(of_gpio_leds_remove),
+	.suspend = of_gpio_led_suspend,
+	.resume = of_gpio_led_resume,
+};
+
+static int __init of_gpio_leds_init(void)
+{
+	return of_register_platform_driver(&of_gpio_leds_driver);
+}
+module_init(of_gpio_leds_init);
+
+static void __exit of_gpio_leds_exit(void)
+{
+	of_unregister_platform_driver(&of_gpio_leds_driver);
+}
+module_exit(of_gpio_leds_exit);

^ permalink raw reply related

* Re: [PATCH] powerpc: fix support for latencytop
From: Chris Friesen @ 2008-07-17  5:30 UTC (permalink / raw)
  To: Nathan Lynch; +Cc: linuxppc-dev, Arnd Bergmann
In-Reply-To: <20080716224208.GF9594@localdomain>

Nathan Lynch wrote:
> Arnd Bergmann wrote:
> 
>>We need to pass the kernel stack pointer instead of the user space
>>stack pointer in save_stack_trace_tsk().
> 
> 
> Thanks, this fixes it, and latencytop even seems to work. :)

Sweet.  One week from mention to working in -next...not bad.

My thanks to Arnd and Nathan for implementing and testing it out.

Chris

^ permalink raw reply

* Re: [PATCH] dtc: supply a definition for YYRHSLOC if there isn't one
From: David Gibson @ 2008-07-17  5:47 UTC (permalink / raw)
  To: Paul Gortmaker; +Cc: linuxppc-dev, jdl
In-Reply-To: <1216230837-17557-1-git-send-email-paul.gortmaker@windriver.com>

On Wed, Jul 16, 2008 at 01:53:57PM -0400, Paul Gortmaker wrote:
> It seems that some machines, like a default RHEL4 install, will
> not have a definition for YYRHSLOC, and that prevents building
> dtc.  This supplies what appears to be the standard definition
> for it in the event that the host system does not have it defined.

I'm pretty uneasy about this, since it relies on knowing the internals
of how bison manages its tokens.  What version of bison is it in RHEL4
that causes the trouble?

In fact I have a feeling that the extra 'file' field in YYLTYPE never
gets used, which means we could just ditch our custom YYLLOC_DEFAULT
definition, which would be a better idea, IMO, except that we'll
probably want the file info back at some point.

Ick.

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

^ permalink raw reply

* powerpc: Fix OF parsing of 64 bits PCI addresses
From: Benjamin Herrenschmidt @ 2008-07-17  5:53 UTC (permalink / raw)
  To: linuxppc-dev list

The OF parsing code for PCI addresses isn't always treating properly
the address space indication 0b11 (ie. 0x3) as meaning 64 bits
memory space.

This means that it fails to parse addresses for PCI BARs that have
this encoding set by the firmware, which happens on some SLOF
versions and breaks offb palette handling on Powerstation.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---

Index: linux-work/arch/powerpc/kernel/pci-common.c
===================================================================
--- linux-work.orig/arch/powerpc/kernel/pci-common.c	2008-07-17 15:09:11.000000000 +1000
+++ linux-work/arch/powerpc/kernel/pci-common.c	2008-07-17 15:09:22.000000000 +1000
@@ -598,6 +598,7 @@ void __devinit pci_process_bridge_OF_ran
 			res->start = pci_addr;
 			break;
 		case 2:		/* PCI Memory space */
+		case 3:		/* PCI 64 bits Memory space */
 			printk(KERN_INFO
 			       " MEM 0x%016llx..0x%016llx -> 0x%016llx %s\n",
 			       cpu_addr, cpu_addr + size - 1, pci_addr,
Index: linux-work/arch/powerpc/kernel/prom_parse.c
===================================================================
--- linux-work.orig/arch/powerpc/kernel/prom_parse.c	2008-07-17 15:06:43.000000000 +1000
+++ linux-work/arch/powerpc/kernel/prom_parse.c	2008-07-17 15:08:16.000000000 +1000
@@ -128,12 +128,35 @@ static void of_bus_pci_count_cells(struc
 		*sizec = 2;
 }
 
+static unsigned int of_bus_pci_get_flags(const u32 *addr)
+{
+	unsigned int flags = 0;
+	u32 w = addr[0];
+
+	switch((w >> 24) & 0x03) {
+	case 0x01:
+		flags |= IORESOURCE_IO;
+		break;
+	case 0x02: /* 32 bits */
+	case 0x03: /* 64 bits */
+		flags |= IORESOURCE_MEM;
+		break;
+	}
+	if (w & 0x40000000)
+		flags |= IORESOURCE_PREFETCH;
+	return flags;
+}
+
 static u64 of_bus_pci_map(u32 *addr, const u32 *range, int na, int ns, int pna)
 {
 	u64 cp, s, da;
+	unsigned int af, rf;
+
+	af = of_bus_pci_get_flags(addr);
+	rf = of_bus_pci_get_flags(range);
 
 	/* Check address type match */
-	if ((addr[0] ^ range[0]) & 0x03000000)
+	if ((af ^ rf) & (IORESOURCE_MEM | IORESOURCE_IO))
 		return OF_BAD_ADDR;
 
 	/* Read address values, skipping high cell */
@@ -153,25 +176,6 @@ static int of_bus_pci_translate(u32 *add
 	return of_bus_default_translate(addr + 1, offset, na - 1);
 }
 
-static unsigned int of_bus_pci_get_flags(const u32 *addr)
-{
-	unsigned int flags = 0;
-	u32 w = addr[0];
-
-	switch((w >> 24) & 0x03) {
-	case 0x01:
-		flags |= IORESOURCE_IO;
-		break;
-	case 0x02: /* 32 bits */
-	case 0x03: /* 64 bits */
-		flags |= IORESOURCE_MEM;
-		break;
-	}
-	if (w & 0x40000000)
-		flags |= IORESOURCE_PREFETCH;
-	return flags;
-}
-
 const u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size,
 			unsigned int *flags)
 {

^ permalink raw reply

* Re: [patch 1/9] powerpc/cell/edac: log a syndrome code in case of correctable error
From: Benjamin Herrenschmidt @ 2008-07-17  5:59 UTC (permalink / raw)
  To: arnd, Doug Thompson
  Cc: Maxim Shchetynin, linuxppc-dev, cbe-oss-dev, bluesmoke-devel
In-Reply-To: <20080715195739.006221652@arndb.de>

Arnd, Maxim, please, next time, send that patch or at least CC the
bluesmoke-devel list for EDAC related bits.

Doug, if you are ok with this patch, I'll merge it via the powerpc
tree.

Cheers,
Ben.

On Tue, 2008-07-15 at 21:51 +0200, arnd@arndb.de 

> From: Maxim Shchetynin <maxim@de.ibm.com>
> 
> If correctable error occurs the syndrome code was logged as 0. This patch
> lets EDAC to log a correct syndrome code to make problem investigation
> easier.
> 
> Signed-off-by: Maxim Shchetynin <maxim@de.ibm.com>
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> ---
>  drivers/edac/cell_edac.c |    5 +++--
>  1 files changed, 3 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/edac/cell_edac.c b/drivers/edac/cell_edac.c
> index b54112f..0e024fe 100644
> --- a/drivers/edac/cell_edac.c
> +++ b/drivers/edac/cell_edac.c
> @@ -33,7 +33,7 @@ static void cell_edac_count_ce(struct mem_ctl_info *mci, int chan, u64 ar)
>  {
>  	struct cell_edac_priv		*priv = mci->pvt_info;
>  	struct csrow_info		*csrow = &mci->csrows[0];
> -	unsigned long			address, pfn, offset;
> +	unsigned long			address, pfn, offset, syndrome;
>  
>  	dev_dbg(mci->dev, "ECC CE err on node %d, channel %d, ar = 0x%016lx\n",
>  		priv->node, chan, ar);
> @@ -44,10 +44,11 @@ static void cell_edac_count_ce(struct mem_ctl_info *mci, int chan, u64 ar)
>  		address = (address << 1) | chan;
>  	pfn = address >> PAGE_SHIFT;
>  	offset = address & ~PAGE_MASK;
> +	syndrome = (ar & 0x000000001fe00000ul) >> 21;
>  
>  	/* TODO: Decoding of the error addresss */
>  	edac_mc_handle_ce(mci, csrow->first_page + pfn, offset,
> -			  0, 0, chan, "");
> +			  syndrome, 0, chan, "");
>  }
>  
>  static void cell_edac_count_ue(struct mem_ctl_info *mci, int chan, u64 ar)
> -- 
> 1.5.4.3
> 

^ permalink raw reply

* Re: [PATCH] leds: implement OpenFirmare GPIO LED driver
From: Segher Boessenkool @ 2008-07-17  5:59 UTC (permalink / raw)
  To: Anton Vorontsov; +Cc: linuxppc-dev, Richard Purdie, linux-kernel
In-Reply-To: <20080714164114.GA18784@polina.dev.rtsoft.ru>

> diff --git a/Documentation/powerpc/dts-bindings/gpio/led.txt 
> b/Documentation/powerpc/dts-bindings/gpio/led.txt
> new file mode 100644
> index 0000000..7e9ce81
> --- /dev/null
> +++ b/Documentation/powerpc/dts-bindings/gpio/led.txt
> @@ -0,0 +1,15 @@
> +LED connected to GPIO
> +
> +Required properties:
> +- compatible : should be "gpio-led".

This "compatible" name is a bit too generic.  No, I don't know a
better name :-(

> +- label : (optional) the label for this LED. If omitted, the label is
> +  taken from the node name (excluding the unit address).

What is a label?  It should be described here.  Also, its encoding
should be described ("a string" I guess).

> +- gpios : should specify LED GPIO.
> +
> +Example:
> +
> +led@0 {
> +	compatible = "gpio-led";
> +	label = "hdd";
> +	gpios = <&mcu_pio 0 0>;
> +};

You show a unit address but have no "reg" value.  This is
incorrect.

What would be the parent node of this, btw?


Segher

^ permalink raw reply

* Re: [alsa-devel] WRITING AN SOC DRIVER WITHOUT DMA
From: dinesh @ 2008-07-17  6:03 UTC (permalink / raw)
  To: Nobin Mathew; +Cc: linuxppc-dev, alsa-devel, liam.girdwood
In-Reply-To: <1216203206.9723.0.camel@dinesh.dua>

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

Hi,
I think no one is able to understand my problem, let me break it to low
level.
What i want is that i have a buffer in driver code which is also handled
by some other application i want that this buffer data is to be used for
capture and playback  stream fills data to another buffer which i can
passover to my other application.
If someone can help me please.
Regards,
Dinesh


-----Original Message-----
From: dinesh <dinesh.dua@coraltele.com>
To: Nobin Mathew <nobin.mathew@gmail.com>
Cc: Grant Likely <grant.likely@secretlab.ca>, linuxppc-dev@ozlabs.org,
alsa-devel@alsa-project.org, liam.girdwood@wolfsonmicro.com
Subject: Re: [alsa-devel] WRITING AN SOC DRIVER WITHOUT DMA
Date: Wed, 16 Jul 2008 15:43:26 +0530


no i am working on powerpc.     MPC8323


-----Original Message-----
From: Nobin Mathew <nobin.mathew@gmail.com>
To: dinesh <dinesh.dua@coraltele.com>
Cc: Grant Likely <grant.likely@secretlab.ca>, linuxppc-dev@ozlabs.org,
alsa-devel@alsa-project.org, liam.girdwood@wolfsonmicro.com
Subject: Re: [alsa-devel] WRITING AN SOC DRIVER WITHOUT DMA
Date: Wed, 16 Jul 2008 15:37:54 +0530


Hi dinesh,

If you are working on ARM, see the ARM AACi code, in sound/arm/aaci.c

Thanks
Nobin Mathew.


On 7/16/08, dinesh <dinesh.dua@coraltele.com> wrote:
>
> Hi,
> I am writing a soc sound driver for MPC8323 board linux 2.6.24 in which i
> want to do data transfer to and from device myself using BUFFER DESCRIPTOR
> not with the usual DMA transfer.
> Please help me.
> _______________________________________________
> Alsa-devel mailing list
> Alsa-devel@alsa-project.org
> http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
>
_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel

[-- Attachment #2: Type: text/html, Size: 3509 bytes --]

^ permalink raw reply

* Re: [patch 7/9] azfs: initial submit of azfs, a non-buffered filesystem
From: Benjamin Herrenschmidt @ 2008-07-17  6:13 UTC (permalink / raw)
  To: arnd; +Cc: Maxim Shchetynin, linuxppc-dev, cbe-oss-dev
In-Reply-To: <20080715195739.820365109@arndb.de>

On Tue, 2008-07-15 at 21:51 +0200, arnd@arndb.de wrote:
> plain text document attachment
> (0007-azfs-initial-submit-of-azfs-a-non-buffered-filesys.patch)
> From: Maxim Shchetynin <maxim@linux.vnet.ibm.com>
> 
> AZFS is a file system which keeps all files on memory mapped random
> access storage. It was designed to work on the axonram device driver
> for IBM QS2x blade servers, but can operate on any block device
> that exports a direct_access method.
> 
> Signed-off-by: Maxim Shchetynin <maxim@de.ibm.com>
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> ---

Can I get this acked by some filesystem person like Al ?

Cheers,
Ben.

>  Documentation/filesystems/azfs.txt  |   22 +
>  arch/powerpc/configs/cell_defconfig |    1 +
>  fs/Kconfig                          |   15 +
>  fs/Makefile                         |    1 +
>  fs/azfs/Makefile                    |    7 +
>  fs/azfs/inode.c                     | 1184 +++++++++++++++++++++++++++++++++++
>  6 files changed, 1230 insertions(+), 0 deletions(-)
>  create mode 100644 Documentation/filesystems/azfs.txt
>  create mode 100644 fs/azfs/Makefile
>  create mode 100644 fs/azfs/inode.c
> 
> diff --git a/Documentation/filesystems/azfs.txt b/Documentation/filesystems/azfs.txt
> new file mode 100644
> index 0000000..c4bf659
> --- /dev/null
> +++ b/Documentation/filesystems/azfs.txt
> @@ -0,0 +1,22 @@
> +AZFS is a file system which keeps all files on memory backed random
> +access storage. It was designed to work on the axonram device driver
> +for IBM QS2x blade servers, but can operate on any block device
> +that exports a direct_access method.
> +
> +Everything in AZFS is temporary in the sense that all the data stored
> +therein is lost when you switch off or reboot a system. If you unmount
> +an AZFS instance, all the data will be kept on device as long your system
> +is not shut down or rebooted. You can later mount AZFS on from device again
> +to get access to your files.
> +
> +AZFS uses a block device only for data but not for file information.
> +All inodes (file and directory information) is kept in RAM.
> +
> +When you mount AZFS you are able to specify a file system block size with
> +'-o bs=<size in bytes>' option. There are no software limitations for
> +a block size but you would not be able to mmap files on AZFS if block size
> +is less than a system page size. If no '-o bs' option is specified on mount
> +a block size of the used block device is used as a default block size for AZFS.
> +
> +Other available mount options for AZFS are '-o uid=<id>' and '-o gid=<id>',
> +which allow you to set the owner and group of the root of the file system.
> diff --git a/arch/powerpc/configs/cell_defconfig b/arch/powerpc/configs/cell_defconfig
> index c420e47..235a0c8 100644
> --- a/arch/powerpc/configs/cell_defconfig
> +++ b/arch/powerpc/configs/cell_defconfig
> @@ -240,6 +240,7 @@ CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
>  # CPU Frequency drivers
>  #
>  CONFIG_AXON_RAM=m
> +CONFIG_AZ_FS=m
>  # CONFIG_FSL_ULI1575 is not set
>  
>  #
> diff --git a/fs/Kconfig b/fs/Kconfig
> index 2694648..2d4e42b 100644
> --- a/fs/Kconfig
> +++ b/fs/Kconfig
> @@ -1017,6 +1017,21 @@ config HUGETLBFS
>  config HUGETLB_PAGE
>  	def_bool HUGETLBFS
>  
> +config AZ_FS
> +	tristate "AZFS filesystem support"
> +	help
> +	  azfs is a file system for I/O attached memory backing. It requires
> +	  a block device with direct_access capability, e.g. axonram.
> +	  Mounting such device with azfs gives memory mapped access to the
> +	  underlying memory to user space.
> +
> +	  Read <file:Documentation/filesystems/azfs.txt> for details.
> +
> +	  To compile this file system support as a module, choose M here: the
> +	  module will be called azfs.
> +
> +	  If unsure, say N.
> +
>  config CONFIGFS_FS
>  	tristate "Userspace-driven configuration filesystem"
>  	depends on SYSFS
> diff --git a/fs/Makefile b/fs/Makefile
> index 1e7a11b..20e3253 100644
> --- a/fs/Makefile
> +++ b/fs/Makefile
> @@ -119,3 +119,4 @@ obj-$(CONFIG_HPPFS)		+= hppfs/
>  obj-$(CONFIG_DEBUG_FS)		+= debugfs/
>  obj-$(CONFIG_OCFS2_FS)		+= ocfs2/
>  obj-$(CONFIG_GFS2_FS)           += gfs2/
> +obj-$(CONFIG_AZ_FS)		+= azfs/
> diff --git a/fs/azfs/Makefile b/fs/azfs/Makefile
> new file mode 100644
> index 0000000..ff04d41
> --- /dev/null
> +++ b/fs/azfs/Makefile
> @@ -0,0 +1,7 @@
> +#
> +# Makefile for azfs routines
> +#
> +
> +obj-$(CONFIG_AZ_FS) += azfs.o
> +
> +azfs-y := inode.o
> diff --git a/fs/azfs/inode.c b/fs/azfs/inode.c
> new file mode 100644
> index 0000000..00dc2af
> --- /dev/null
> +++ b/fs/azfs/inode.c
> @@ -0,0 +1,1184 @@
> +/*
> + * (C) Copyright IBM Deutschland Entwicklung GmbH 2007
> + *
> + * Author: Maxim Shchetynin <maxim@de.ibm.com>
> + *
> + * Non-buffered filesystem driver.
> + * It registers a filesystem which may be used for all kind of block devices
> + * which have a direct_access() method in block_device_operations.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2, or (at your option)
> + * any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
> + */
> +
> +#include <linux/backing-dev.h>
> +#include <linux/blkdev.h>
> +#include <linux/cache.h>
> +#include <linux/dcache.h>
> +#include <linux/device.h>
> +#include <linux/err.h>
> +#include <linux/fs.h>
> +#include <linux/genhd.h>
> +#include <linux/kernel.h>
> +#include <linux/limits.h>
> +#include <linux/list.h>
> +#include <linux/module.h>
> +#include <linux/mount.h>
> +#include <linux/mm.h>
> +#include <linux/mm_types.h>
> +#include <linux/mutex.h>
> +#include <linux/namei.h>
> +#include <linux/pagemap.h>
> +#include <linux/parser.h>
> +#include <linux/slab.h>
> +#include <linux/spinlock.h>
> +#include <linux/stat.h>
> +#include <linux/statfs.h>
> +#include <linux/string.h>
> +#include <linux/time.h>
> +#include <linux/types.h>
> +#include <linux/aio.h>
> +#include <linux/uio.h>
> +#include <asm/bug.h>
> +#include <asm/page.h>
> +#include <asm/pgtable.h>
> +#include <asm/string.h>
> +
> +#define AZFS_FILESYSTEM_NAME		"azfs"
> +#define AZFS_FILESYSTEM_FLAGS		FS_REQUIRES_DEV
> +
> +#define AZFS_SUPERBLOCK_MAGIC		0xABBA1972
> +#define AZFS_SUPERBLOCK_FLAGS		MS_SYNCHRONOUS | \
> +					MS_DIRSYNC | \
> +					MS_ACTIVE
> +
> +#define AZFS_BDI_CAPABILITIES		BDI_CAP_NO_ACCT_DIRTY | \
> +					BDI_CAP_NO_WRITEBACK | \
> +					BDI_CAP_MAP_COPY | \
> +					BDI_CAP_MAP_DIRECT | \
> +					BDI_CAP_VMFLAGS
> +
> +#define AZFS_CACHE_FLAGS		SLAB_HWCACHE_ALIGN | \
> +					SLAB_RECLAIM_ACCOUNT | \
> +					SLAB_MEM_SPREAD
> +
> +struct azfs_super {
> +	struct list_head		list;
> +	unsigned long			media_size;
> +	unsigned long			block_size;
> +	unsigned short			block_shift;
> +	unsigned long			sector_size;
> +	unsigned short			sector_shift;
> +	uid_t				uid;
> +	gid_t				gid;
> +	unsigned long			ph_addr;
> +	unsigned long			io_addr;
> +	struct block_device		*blkdev;
> +	struct dentry			*root;
> +	struct list_head		block_list;
> +	rwlock_t			lock;
> +};
> +
> +struct azfs_super_list {
> +	struct list_head		head;
> +	spinlock_t			lock;
> +};
> +
> +struct azfs_block {
> +	struct list_head		list;
> +	unsigned long			id;
> +	unsigned long			count;
> +};
> +
> +struct azfs_znode {
> +	struct list_head		block_list;
> +	rwlock_t			lock;
> +	loff_t				size;
> +	struct inode			vfs_inode;
> +};
> +
> +static struct azfs_super_list		super_list;
> +static struct kmem_cache		*azfs_znode_cache __read_mostly = NULL;
> +static struct kmem_cache		*azfs_block_cache __read_mostly = NULL;
> +
> +#define I2S(inode) \
> +	inode->i_sb->s_fs_info
> +#define I2Z(inode) \
> +	container_of(inode, struct azfs_znode, vfs_inode)
> +
> +#define for_each_block(block, block_list) \
> +	list_for_each_entry(block, block_list, list)
> +#define for_each_block_reverse(block, block_list) \
> +	list_for_each_entry_reverse(block, block_list, list)
> +#define for_each_block_safe(block, temp, block_list) \
> +	list_for_each_entry_safe(block, temp, block_list, list)
> +#define for_each_block_safe_reverse(block, temp, block_list) \
> +	list_for_each_entry_safe_reverse(block, temp, block_list, list)
> +
> +/**
> + * azfs_block_init - create and initialise a new block in a list
> + * @block_list: destination list
> + * @id: block id
> + * @count: size of a block
> + */
> +static inline struct azfs_block*
> +azfs_block_init(struct list_head *block_list,
> +		unsigned long id, unsigned long count)
> +{
> +	struct azfs_block *block;
> +
> +	block = kmem_cache_alloc(azfs_block_cache, GFP_KERNEL);
> +	if (!block)
> +		return NULL;
> +
> +	block->id = id;
> +	block->count = count;
> +
> +	INIT_LIST_HEAD(&block->list);
> +	list_add_tail(&block->list, block_list);
> +
> +	return block;
> +}
> +
> +/**
> + * azfs_block_free - remove block from a list and free it back in cache
> + * @block: block to be removed
> + */
> +static inline void
> +azfs_block_free(struct azfs_block *block)
> +{
> +	list_del(&block->list);
> +	kmem_cache_free(azfs_block_cache, block);
> +}
> +
> +/**
> + * azfs_block_move - move block to another list
> + * @block: block to be moved
> + * @block_list: destination list
> + */
> +static inline void
> +azfs_block_move(struct azfs_block *block, struct list_head *block_list)
> +{
> +	list_move_tail(&block->list, block_list);
> +}
> +
> +/**
> + * azfs_block_find - get a block id of a part of a file
> + * @inode: inode
> + * @from: offset for read/write operation
> + * @size: pointer to a value of the amount of data to be read/written
> + */
> +static unsigned long
> +azfs_block_find(struct inode *inode, unsigned long from, unsigned long *size)
> +{
> +	struct azfs_super *super;
> +	struct azfs_znode *znode;
> +	struct azfs_block *block;
> +	unsigned long block_id, west, east;
> +
> +	super = I2S(inode);
> +	znode = I2Z(inode);
> +
> +	read_lock(&znode->lock);
> +
> +	while (from + *size > znode->size) {
> +		read_unlock(&znode->lock);
> +		i_size_write(inode, from + *size);
> +		inode->i_op->truncate(inode);
> +		read_lock(&znode->lock);
> +	}
> +
> +	if (list_empty(&znode->block_list)) {
> +		read_unlock(&znode->lock);
> +		*size = 0;
> +		return 0;
> +	}
> +
> +	block_id = from >> super->block_shift;
> +
> +	for_each_block(block, &znode->block_list) {
> +		if (block->count > block_id)
> +			break;
> +		block_id -= block->count;
> +	}
> +
> +	west = from % super->block_size;
> +	east = ((block->count - block_id) << super->block_shift) - west;
> +
> +	if (*size > east)
> +		*size = east;
> +
> +	block_id = ((block->id + block_id) << super->block_shift) + west;
> +
> +	read_unlock(&znode->lock);
> +
> +	return block_id;
> +}
> +
> +static struct inode*
> +azfs_new_inode(struct super_block *, struct inode *, int, dev_t);
> +
> +/**
> + * azfs_mknod - mknod() method for inode_operations
> + * @dir, @dentry, @mode, @dev: see inode_operations methods
> + */
> +static int
> +azfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
> +{
> +	struct inode *inode;
> +
> +	inode = azfs_new_inode(dir->i_sb, dir, mode, dev);
> +	if (!inode)
> +		return -ENOSPC;
> +
> +	if (S_ISREG(mode))
> +		I2Z(inode)->size = 0;
> +
> +	dget(dentry);
> +	d_instantiate(dentry, inode);
> +
> +	return 0;
> +}
> +
> +/**
> + * azfs_create - create() method for inode_operations
> + * @dir, @dentry, @mode, @nd: see inode_operations methods
> + */
> +static int
> +azfs_create(struct inode *dir, struct dentry *dentry, int mode,
> +	    struct nameidata *nd)
> +{
> +	return azfs_mknod(dir, dentry, mode | S_IFREG, 0);
> +}
> +
> +/**
> + * azfs_mkdir - mkdir() method for inode_operations
> + * @dir, @dentry, @mode: see inode_operations methods
> + */
> +static int
> +azfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
> +{
> +	int rc;
> +
> +	rc = azfs_mknod(dir, dentry, mode | S_IFDIR, 0);
> +	if (!rc)
> +		inc_nlink(dir);
> +
> +	return rc;
> +}
> +
> +/**
> + * azfs_symlink - symlink() method for inode_operations
> + * @dir, @dentry, @name: see inode_operations methods
> + */
> +static int
> +azfs_symlink(struct inode *dir, struct dentry *dentry, const char *name)
> +{
> +	struct inode *inode;
> +	int rc;
> +
> +	inode = azfs_new_inode(dir->i_sb, dir, S_IFLNK | S_IRWXUGO, 0);
> +	if (!inode)
> +		return -ENOSPC;
> +
> +	rc = page_symlink(inode, name, strlen(name) + 1);
> +	if (rc) {
> +		iput(inode);
> +		return rc;
> +	}
> +
> +	dget(dentry);
> +	d_instantiate(dentry, inode);
> +
> +	return 0;
> +}
> +
> +/**
> + * azfs_aio_read - aio_read() method for file_operations
> + * @iocb, @iov, @nr_segs, @pos: see file_operations methods
> + */
> +static ssize_t
> +azfs_aio_read(struct kiocb *iocb, const struct iovec *iov,
> +	      unsigned long nr_segs, loff_t pos)
> +{
> +	struct azfs_super *super;
> +	struct inode *inode;
> +	void *target;
> +	unsigned long pin;
> +	unsigned long size, todo, step;
> +	ssize_t rc;
> +
> +	inode = iocb->ki_filp->f_mapping->host;
> +	super = I2S(inode);
> +
> +	mutex_lock(&inode->i_mutex);
> +
> +	if (pos >= i_size_read(inode)) {
> +		rc = 0;
> +		goto out;
> +	}
> +
> +	target = iov->iov_base;
> +	todo = min((loff_t) iov->iov_len, i_size_read(inode) - pos);
> +
> +	for (step = todo; step; step -= size) {
> +		size = step;
> +		pin = azfs_block_find(inode, pos, &size);
> +		if (!size) {
> +			rc = -ENOSPC;
> +			goto out;
> +		}
> +		pin += super->io_addr;
> +		/*
> +		 * FIXME: pin is actually an __iomem pointer, is
> +		 * that safe? -arnd
> +		 */
> +		if (copy_to_user(target, (void*) pin, size)) {
> +			rc = -EFAULT;
> +			goto out;
> +		}
> +
> +		iocb->ki_pos += size;
> +		pos += size;
> +		target += size;
> +	}
> +
> +	rc = todo;
> +
> +out:
> +	mutex_unlock(&inode->i_mutex);
> +
> +	return rc;
> +}
> +
> +/**
> + * azfs_aio_write - aio_write() method for file_operations
> + * @iocb, @iov, @nr_segs, @pos: see file_operations methods
> + */
> +static ssize_t
> +azfs_aio_write(struct kiocb *iocb, const struct iovec *iov,
> +	       unsigned long nr_segs, loff_t pos)
> +{
> +	struct azfs_super *super;
> +	struct inode *inode;
> +	void *source;
> +	unsigned long pin;
> +	unsigned long size, todo, step;
> +	ssize_t rc;
> +
> +	inode = iocb->ki_filp->f_mapping->host;
> +	super = I2S(inode);
> +
> +	source = iov->iov_base;
> +	todo = iov->iov_len;
> +
> +	mutex_lock(&inode->i_mutex);
> +
> +	for (step = todo; step; step -= size) {
> +		size = step;
> +		pin = azfs_block_find(inode, pos, &size);
> +		if (!size) {
> +			rc = -ENOSPC;
> +			goto out;
> +		}
> +		pin += super->io_addr;
> +		/*
> +		 * FIXME: pin is actually an __iomem pointer, is
> +		 * that safe? -arnd
> +		 */
> +		if (copy_from_user((void*) pin, source, size)) {
> +			rc = -EFAULT;
> +			goto out;
> +		}
> +
> +		iocb->ki_pos += size;
> +		pos += size;
> +		source += size;
> +	}
> +
> +	rc = todo;
> +
> +out:
> +	mutex_unlock(&inode->i_mutex);
> +
> +	return rc;
> +}
> +
> +/**
> + * azfs_open - open() method for file_operations
> + * @inode, @file: see file_operations methods
> + */
> +static int
> +azfs_open(struct inode *inode, struct file *file)
> +{
> +	if (file->f_flags & O_TRUNC) {
> +		i_size_write(inode, 0);
> +		inode->i_op->truncate(inode);
> +	}
> +	if (file->f_flags & O_APPEND)
> +		inode->i_fop->llseek(file, 0, SEEK_END);
> +
> +	return 0;
> +}
> +
> +/**
> + * azfs_mmap - mmap() method for file_operations
> + * @file, @vm: see file_operations methods
> + */
> +static int
> +azfs_mmap(struct file *file, struct vm_area_struct *vma)
> +{
> +	struct azfs_super *super;
> +	struct azfs_znode *znode;
> +	struct inode *inode;
> +	unsigned long cursor, pin;
> +	unsigned long todo, size, vm_start;
> +	pgprot_t page_prot;
> +
> +	inode = file->f_dentry->d_inode;
> +	znode = I2Z(inode);
> +	super = I2S(inode);
> +
> +	if (super->block_size < PAGE_SIZE)
> +		return -EINVAL;
> +
> +	cursor = vma->vm_pgoff << super->block_shift;
> +	todo = vma->vm_end - vma->vm_start;
> +
> +	if (cursor + todo > i_size_read(inode))
> +		return -EINVAL;
> +
> +	page_prot = pgprot_val(vma->vm_page_prot);
> +#ifdef CONFIG_PPC
> +	page_prot |= (_PAGE_NO_CACHE | _PAGE_RW);
> +	page_prot &= ~_PAGE_GUARDED;
> +#else
> +	page_prot = pgprot_noncached(page_prot);
> +#endif
> +	vma->vm_page_prot = __pgprot(page_prot);
> +
> +	vm_start = vma->vm_start;
> +	for (size = todo; todo; todo -= size, size = todo) {
> +		pin = azfs_block_find(inode, cursor, &size);
> +		if (!size)
> +			return -EAGAIN;
> +		pin += super->ph_addr;
> +		pin >>= PAGE_SHIFT;
> +		if (remap_pfn_range(vma, vm_start, pin, size, vma->vm_page_prot))
> +			return -EAGAIN;
> +
> +		vm_start += size;
> +		cursor += size;
> +	}
> +
> +	return 0;
> +}
> +
> +/**
> + * azfs_truncate - truncate() method for inode_operations
> + * @inode: see inode_operations methods
> + */
> +static void
> +azfs_truncate(struct inode *inode)
> +{
> +	struct azfs_super *super;
> +	struct azfs_znode *znode;
> +	struct azfs_block *block, *tmp_block, *temp, *west, *east;
> +	unsigned long id, count;
> +	signed long delta;
> +
> +	super = I2S(inode);
> +	znode = I2Z(inode);
> +
> +	delta = i_size_read(inode) + (super->block_size - 1);
> +	delta >>= super->block_shift;
> +	delta -= inode->i_blocks;
> +
> +	if (delta == 0) {
> +		znode->size = i_size_read(inode);
> +		return;
> +	}
> +
> +	write_lock(&znode->lock);
> +
> +	while (delta > 0) {
> +		west = east = NULL;
> +
> +		write_lock(&super->lock);
> +
> +		if (list_empty(&super->block_list)) {
> +			write_unlock(&super->lock);
> +			break;
> +		}
> +
> +		for (count = delta; count; count--) {
> +			for_each_block(block, &super->block_list)
> +				if (block->count >= count) {
> +					east = block;
> +					break;
> +				}
> +			if (east)
> +				break;
> +		}
> +
> +		for_each_block_reverse(block, &znode->block_list) {
> +			if (block->id + block->count == east->id)
> +				west = block;
> +			break;
> +		}
> +
> +		if (east->count == count) {
> +			if (west) {
> +				west->count += east->count;
> +				azfs_block_free(east);
> +			} else {
> +				azfs_block_move(east, &znode->block_list);
> +			}
> +		} else {
> +			if (west) {
> +				west->count += count;
> +			} else {
> +				if (!azfs_block_init(&znode->block_list,
> +						east->id, count)) {
> +					write_unlock(&super->lock);
> +					break;
> +				}
> +			}
> +
> +			east->id += count;
> +			east->count -= count;
> +		}
> +
> +		write_unlock(&super->lock);
> +
> +		inode->i_blocks += count;
> +
> +		delta -= count;
> +	}
> +
> +	while (delta < 0) {
> +		for_each_block_safe_reverse(block, tmp_block, &znode->block_list) {
> +			id = block->id;
> +			count = block->count;
> +			if ((signed long) count + delta > 0) {
> +				block->count += delta;
> +				id += block->count;
> +				count -= block->count;
> +				block = NULL;
> +			}
> +
> +			west = east = NULL;
> +
> +			write_lock(&super->lock);
> +
> +			for_each_block(temp, &super->block_list) {
> +				if (!west && (temp->id + temp->count == id))
> +					west = temp;
> +				else if (!east && (id + count == temp->id))
> +					east = temp;
> +				if (west && east)
> +					break;
> +			}
> +
> +			if (west && east) {
> +				west->count += count + east->count;
> +				azfs_block_free(east);
> +				if (block)
> +					azfs_block_free(block);
> +			} else if (west) {
> +				west->count += count;
> +				if (block)
> +					azfs_block_free(block);
> +			} else if (east) {
> +				east->id -= count;
> +				east->count += count;
> +				if (block)
> +					azfs_block_free(block);
> +			} else {
> +				if (!block) {
> +					if (!azfs_block_init(&super->block_list,
> +							id, count)) {
> +						write_unlock(&super->lock);
> +						break;
> +					}
> +				} else {
> +					azfs_block_move(block, &super->block_list);
> +				}
> +			}
> +
> +			write_unlock(&super->lock);
> +
> +			inode->i_blocks -= count;
> +
> +			delta += count;
> +
> +			break;
> +		}
> +	}
> +
> +	write_unlock(&znode->lock);
> +
> +	znode->size = min(i_size_read(inode),
> +			(loff_t) inode->i_blocks << super->block_shift);
> +}
> +
> +/**
> + * azfs_getattr - getattr() method for inode_operations
> + * @mnt, @dentry, @stat: see inode_operations methods
> + */
> +static int
> +azfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
> +{
> +	struct azfs_super *super;
> +	struct inode *inode;
> +	unsigned short shift;
> +
> +	inode = dentry->d_inode;
> +	super = I2S(inode);
> +
> +	generic_fillattr(inode, stat);
> +	stat->blocks = inode->i_blocks;
> +	shift = super->block_shift - super->sector_shift;
> +	if (shift)
> +		stat->blocks <<= shift;
> +
> +	return 0;
> +}
> +
> +static const struct address_space_operations azfs_aops = {
> +	.write_begin	= simple_write_begin,
> +	.write_end	= simple_write_end
> +};
> +
> +static struct backing_dev_info azfs_bdi = {
> +	.ra_pages	= 0,
> +	.capabilities	= AZFS_BDI_CAPABILITIES
> +};
> +
> +static struct inode_operations azfs_dir_iops = {
> +	.create		= azfs_create,
> +	.lookup		= simple_lookup,
> +	.link		= simple_link,
> +	.unlink		= simple_unlink,
> +	.symlink	= azfs_symlink,
> +	.mkdir		= azfs_mkdir,
> +	.rmdir		= simple_rmdir,
> +	.mknod		= azfs_mknod,
> +	.rename		= simple_rename
> +};
> +
> +static const struct file_operations azfs_reg_fops = {
> +	.llseek		= generic_file_llseek,
> +	.aio_read	= azfs_aio_read,
> +	.aio_write	= azfs_aio_write,
> +	.open		= azfs_open,
> +	.mmap		= azfs_mmap,
> +	.fsync		= simple_sync_file,
> +};
> +
> +static struct inode_operations azfs_reg_iops = {
> +	.truncate	= azfs_truncate,
> +	.getattr	= azfs_getattr
> +};
> +
> +/**
> + * azfs_new_inode - cook a new inode
> + * @sb: super-block
> + * @dir: parent directory
> + * @mode: file mode
> + * @dev: to be forwarded to init_special_inode()
> + */
> +static struct inode*
> +azfs_new_inode(struct super_block *sb, struct inode *dir, int mode, dev_t dev)
> +{
> +	struct azfs_super *super;
> +	struct inode *inode;
> +
> +	inode = new_inode(sb);
> +	if (!inode)
> +		return NULL;
> +
> +	inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
> +
> +	inode->i_mode = mode;
> +	if (dir) {
> +		dir->i_mtime = dir->i_ctime = inode->i_mtime;
> +		inode->i_uid = current->fsuid;
> +		if (dir->i_mode & S_ISGID) {
> +			if (S_ISDIR(mode))
> +				inode->i_mode |= S_ISGID;
> +			inode->i_gid = dir->i_gid;
> +		} else {
> +			inode->i_gid = current->fsgid;
> +		}
> +	} else {
> +		super = sb->s_fs_info;
> +		inode->i_uid = super->uid;
> +		inode->i_gid = super->gid;
> +	}
> +
> +	inode->i_blocks = 0;
> +	inode->i_mapping->a_ops = &azfs_aops;
> +	inode->i_mapping->backing_dev_info = &azfs_bdi;
> +
> +	switch (mode & S_IFMT) {
> +	case S_IFDIR:
> +		inode->i_op = &azfs_dir_iops;
> +		inode->i_fop = &simple_dir_operations;
> +		inc_nlink(inode);
> +		break;
> +
> +	case S_IFREG:
> +		inode->i_op = &azfs_reg_iops;
> +		inode->i_fop = &azfs_reg_fops;
> +		break;
> +
> +	case S_IFLNK:
> +		inode->i_op = &page_symlink_inode_operations;
> +		break;
> +
> +	default:
> +		init_special_inode(inode, mode, dev);
> +		break;
> +	}
> +
> +	return inode;
> +}
> +
> +/**
> + * azfs_alloc_inode - alloc_inode() method for super_operations
> + * @sb: see super_operations methods
> + */
> +static struct inode*
> +azfs_alloc_inode(struct super_block *sb)
> +{
> +	struct azfs_znode *znode;
> +
> +	znode = kmem_cache_alloc(azfs_znode_cache, GFP_KERNEL);
> +	if (znode) {
> +		INIT_LIST_HEAD(&znode->block_list);
> +		rwlock_init(&znode->lock);
> +
> +		inode_init_once(&znode->vfs_inode);
> +
> +		return &znode->vfs_inode;
> +	}
> +
> +	return NULL;
> +}
> +
> +/**
> + * azfs_destroy_inode - destroy_inode() method for super_operations
> + * @inode: see super_operations methods
> + */
> +static void
> +azfs_destroy_inode(struct inode *inode)
> +{
> +	kmem_cache_free(azfs_znode_cache, I2Z(inode));
> +}
> +
> +/**
> + * azfs_delete_inode - delete_inode() method for super_operations
> + * @inode: see super_operations methods
> + */
> +static void
> +azfs_delete_inode(struct inode *inode)
> +{
> +	if (S_ISREG(inode->i_mode)) {
> +		i_size_write(inode, 0);
> +		azfs_truncate(inode);
> +	}
> +	truncate_inode_pages(&inode->i_data, 0);
> +	clear_inode(inode);
> +}
> +
> +/**
> + * azfs_statfs - statfs() method for super_operations
> + * @dentry, @stat: see super_operations methods
> + */
> +static int
> +azfs_statfs(struct dentry *dentry, struct kstatfs *stat)
> +{
> +	struct super_block *sb;
> +	struct azfs_super *super;
> +	struct inode *inode;
> +	unsigned long inodes, blocks;
> +
> +	sb = dentry->d_sb;
> +	super = sb->s_fs_info;
> +
> +	inodes = blocks = 0;
> +	mutex_lock(&sb->s_lock);
> +	list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
> +		inodes++;
> +		blocks += inode->i_blocks;
> +	}
> +	mutex_unlock(&sb->s_lock);
> +
> +	stat->f_type = AZFS_SUPERBLOCK_MAGIC;
> +	stat->f_bsize = super->block_size;
> +	stat->f_blocks = super->media_size >> super->block_shift;
> +	stat->f_bfree = stat->f_blocks - blocks;
> +	stat->f_bavail = stat->f_blocks - blocks;
> +	stat->f_files = inodes + blocks;
> +	stat->f_ffree = blocks + 1;
> +	stat->f_namelen = NAME_MAX;
> +
> +	return 0;
> +}
> +
> +static struct super_operations azfs_ops = {
> +	.alloc_inode	= azfs_alloc_inode,
> +	.destroy_inode	= azfs_destroy_inode,
> +	.drop_inode	= generic_delete_inode,
> +	.delete_inode	= azfs_delete_inode,
> +	.statfs		= azfs_statfs
> +};
> +
> +enum {
> +	Opt_blocksize_short,
> +	Opt_blocksize_long,
> +	Opt_uid,
> +	Opt_gid,
> +	Opt_err
> +};
> +
> +static match_table_t tokens = {
> +	{Opt_blocksize_short, "bs=%u"},
> +	{Opt_blocksize_long, "blocksize=%u"},
> +	{Opt_uid, "uid=%u"},
> +	{Opt_gid, "gid=%u"},
> +	{Opt_err, NULL}
> +};
> +
> +/**
> + * azfs_parse_mount_parameters - parse options given to mount with -o
> + * @super: azfs super block extension
> + * @options: comma separated options
> + */
> +static int
> +azfs_parse_mount_parameters(struct azfs_super *super, char *options)
> +{
> +	char *option;
> +	int token, value;
> +	substring_t args[MAX_OPT_ARGS];
> +
> +	if (!options)
> +		return 1;
> +
> +	while ((option = strsep(&options, ",")) != NULL) {
> +		if (!*option)
> +			continue;
> +
> +		token = match_token(option, tokens, args);
> +		switch (token) {
> +		case Opt_blocksize_short:
> +		case Opt_blocksize_long:
> +			if (match_int(&args[0], &value))
> +				goto syntax_error;
> +			super->block_size = value;
> +			break;
> +
> +		case Opt_uid:
> +			if (match_int(&args[0], &value))
> +				goto syntax_error;
> +			super->uid = value;
> +			break;
> +
> +		case Opt_gid:
> +			if (match_int(&args[0], &value))
> +				goto syntax_error;
> +			super->gid = value;
> +			break;
> +
> +		default:
> +			goto syntax_error;
> +		}
> +	}
> +
> +	return 1;
> +
> +syntax_error:
> +	printk(KERN_ERR "%s: invalid mount option\n",
> +			AZFS_FILESYSTEM_NAME);
> +
> +	return 0;
> +}
> +
> +/**
> + * azfs_fill_super - fill_super routine for get_sb
> + * @sb, @data, @silent: see file_system_type methods
> + */
> +static int
> +azfs_fill_super(struct super_block *sb, void *data, int silent)
> +{
> +	struct gendisk *disk;
> +	struct azfs_super *super = NULL, *tmp_super;
> +	struct azfs_block *block = NULL;
> +	struct inode *inode = NULL;
> +	void *kaddr;
> +	unsigned long pfn;
> +	int rc;
> +
> +	BUG_ON(!sb->s_bdev);
> +
> +	disk = sb->s_bdev->bd_disk;
> +
> +	BUG_ON(!disk || !disk->queue);
> +
> +	if (!disk->fops->direct_access) {
> +		printk(KERN_ERR "%s needs a block device with a "
> +				"direct_access() method\n",
> +				AZFS_FILESYSTEM_NAME);
> +		return -ENOSYS;
> +	}
> +
> +	get_device(disk->driverfs_dev);
> +
> +	sb->s_magic = AZFS_SUPERBLOCK_MAGIC;
> +	sb->s_flags = AZFS_SUPERBLOCK_FLAGS;
> +	sb->s_op = &azfs_ops;
> +	sb->s_maxbytes = get_capacity(disk) * disk->queue->hardsect_size;
> +	sb->s_time_gran = 1;
> +
> +	spin_lock(&super_list.lock);
> +	list_for_each_entry(tmp_super, &super_list.head, list)
> +		if (tmp_super->blkdev == sb->s_bdev) {
> +			super = tmp_super;
> +			break;
> +		}
> +	spin_unlock(&super_list.lock);
> +
> +	if (super) {
> +		if (data && strlen((char*) data))
> +			printk(KERN_WARNING "/dev/%s was already mounted with "
> +					"%s before, it will be mounted with "
> +					"mount options used last time, "
> +					"options just given would be ignored\n",
> +					disk->disk_name, AZFS_FILESYSTEM_NAME);
> +		sb->s_fs_info = super;
> +	} else {
> +		super = kzalloc(sizeof(struct azfs_super), GFP_KERNEL);
> +		if (!super) {
> +			rc = -ENOMEM;
> +			goto failed;
> +		}
> +		sb->s_fs_info = super;
> +
> +		if (!azfs_parse_mount_parameters(super, (char*) data)) {
> +			rc = -EINVAL;
> +			goto failed;
> +		}
> +
> +		inode = azfs_new_inode(sb, NULL, S_IFDIR | S_IRWXUGO, 0);
> +		if (!inode) {
> +			rc = -ENOMEM;
> +			goto failed;
> +		}
> +
> +		super->root = d_alloc_root(inode);
> +		if (!super->root) {
> +			rc = -ENOMEM;
> +			goto failed;
> +		}
> +		dget(super->root);
> +
> +		INIT_LIST_HEAD(&super->list);
> +		INIT_LIST_HEAD(&super->block_list);
> +		rwlock_init(&super->lock);
> +
> +		super->media_size = sb->s_maxbytes;
> +
> +		if (!super->block_size)
> +			super->block_size = sb->s_blocksize;
> +		super->block_shift = blksize_bits(super->block_size);
> +
> +		super->sector_size = disk->queue->hardsect_size;
> +		super->sector_shift = blksize_bits(super->sector_size);
> +
> +		super->blkdev = sb->s_bdev;
> +
> +		block = azfs_block_init(&super->block_list,
> +				0, super->media_size >> super->block_shift);
> +		if (!block) {
> +			rc = -ENOMEM;
> +			goto failed;
> +		}
> +
> +		rc = disk->fops->direct_access(super->blkdev, 0, &kaddr, &pfn);
> +		if (rc < 0) {
> +			rc = -EFAULT;
> +			goto failed;
> +		}
> +		super->ph_addr = (unsigned long) kaddr;
> +
> +		super->io_addr = (unsigned long) ioremap_flags(
> +				super->ph_addr, super->media_size, _PAGE_NO_CACHE);
> +		if (!super->io_addr) {
> +			rc = -EFAULT;
> +			goto failed;
> +		}
> +
> +		spin_lock(&super_list.lock);
> +		list_add(&super->list, &super_list.head);
> +		spin_unlock(&super_list.lock);
> +	}
> +
> +	sb->s_root = super->root;
> +	disk->driverfs_dev->driver_data = super;
> +	disk->driverfs_dev->platform_data = sb;
> +
> +	if (super->block_size < PAGE_SIZE)
> +		printk(KERN_INFO "Block size on %s is smaller then system "
> +				"page size: mmap() would not be supported\n",
> +				disk->disk_name);
> +
> +	return 0;
> +
> +failed:
> +	if (super) {
> +		sb->s_root = NULL;
> +		sb->s_fs_info = NULL;
> +		if (block)
> +			azfs_block_free(block);
> +		if (super->root)
> +			dput(super->root);
> +		if (inode)
> +			iput(inode);
> +		disk->driverfs_dev->driver_data = NULL;
> +		kfree(super);
> +		disk->driverfs_dev->platform_data = NULL;
> +		put_device(disk->driverfs_dev);
> +	}
> +
> +	return rc;
> +}
> +
> +/**
> + * azfs_get_sb - get_sb() method for file_system_type
> + * @fs_type, @flags, @dev_name, @data, @mount: see file_system_type methods
> + */
> +static int
> +azfs_get_sb(struct file_system_type *fs_type, int flags,
> +	    const char *dev_name, void *data, struct vfsmount *mount)
> +{
> +	return get_sb_bdev(fs_type, flags,
> +			dev_name, data, azfs_fill_super, mount);
> +}
> +
> +/**
> + * azfs_kill_sb - kill_sb() method for file_system_type
> + * @sb: see file_system_type methods
> + */
> +static void
> +azfs_kill_sb(struct super_block *sb)
> +{
> +	sb->s_root = NULL;
> +	kill_block_super(sb);
> +}
> +
> +static struct file_system_type azfs_fs = {
> +	.owner		= THIS_MODULE,
> +	.name		= AZFS_FILESYSTEM_NAME,
> +	.get_sb		= azfs_get_sb,
> +	.kill_sb	= azfs_kill_sb,
> +	.fs_flags	= AZFS_FILESYSTEM_FLAGS
> +};
> +
> +/**
> + * azfs_init
> + */
> +static int __init
> +azfs_init(void)
> +{
> +	int rc;
> +
> +	INIT_LIST_HEAD(&super_list.head);
> +	spin_lock_init(&super_list.lock);
> +
> +	azfs_znode_cache = kmem_cache_create("azfs_znode_cache",
> +			sizeof(struct azfs_znode), 0, AZFS_CACHE_FLAGS, NULL);
> +	if (!azfs_znode_cache) {
> +		printk(KERN_ERR "Could not allocate inode cache for %s\n",
> +				AZFS_FILESYSTEM_NAME);
> +		rc = -ENOMEM;
> +		goto failed;
> +	}
> +
> +	azfs_block_cache = kmem_cache_create("azfs_block_cache",
> +			sizeof(struct azfs_block), 0, AZFS_CACHE_FLAGS, NULL);
> +	if (!azfs_block_cache) {
> +		printk(KERN_ERR "Could not allocate block cache for %s\n",
> +				AZFS_FILESYSTEM_NAME);
> +		rc = -ENOMEM;
> +		goto failed;
> +	}
> +
> +	rc = register_filesystem(&azfs_fs);
> +	if (rc != 0) {
> +		printk(KERN_ERR "Could not register %s\n",
> +				AZFS_FILESYSTEM_NAME);
> +		goto failed;
> +	}
> +
> +	return 0;
> +
> +failed:
> +	if (azfs_block_cache)
> +		kmem_cache_destroy(azfs_block_cache);
> +
> +	if (azfs_znode_cache)
> +		kmem_cache_destroy(azfs_znode_cache);
> +
> +	return rc;
> +}
> +
> +/**
> + * azfs_exit
> + */
> +static void __exit
> +azfs_exit(void)
> +{
> +	struct azfs_super *super, *tmp_super;
> +	struct azfs_block *block, *tmp_block;
> +	struct gendisk *disk;
> +
> +	spin_lock(&super_list.lock);
> +	list_for_each_entry_safe(super, tmp_super, &super_list.head, list) {
> +		disk = super->blkdev->bd_disk;
> +		list_del(&super->list);
> +		iounmap((void*) super->io_addr);
> +		write_lock(&super->lock);
> +		for_each_block_safe(block, tmp_block, &super->block_list)
> +			azfs_block_free(block);
> +		write_unlock(&super->lock);
> +		disk->driverfs_dev->driver_data = NULL;
> +		disk->driverfs_dev->platform_data = NULL;
> +		kfree(super);
> +		put_device(disk->driverfs_dev);
> +	}
> +	spin_unlock(&super_list.lock);
> +
> +	unregister_filesystem(&azfs_fs);
> +
> +	kmem_cache_destroy(azfs_block_cache);
> +	kmem_cache_destroy(azfs_znode_cache);
> +}
> +
> +module_init(azfs_init);
> +module_exit(azfs_exit);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("Maxim Shchetynin <maxim@de.ibm.com>");
> +MODULE_DESCRIPTION("Non-buffered file system for IO devices");
> -- 
> 1.5.4.3
> 

^ permalink raw reply

* Re: [Cbe-oss-dev] [patch 9/9] powerpc/cell: Add DMA_ATTR_STRONG_ORDERING dma attribute and use in IOMMU code
From: Benjamin Herrenschmidt @ 2008-07-17  6:20 UTC (permalink / raw)
  To: Arnd Bergmann; +Cc: linuxppc-dev, Roland Dreier, cbe-oss-dev
In-Reply-To: <200807160954.03633.arnd@arndb.de>

On Wed, 2008-07-16 at 09:54 +0200, Arnd Bergmann wrote:
> On Wednesday 16 July 2008, Roland Dreier wrote:
> >  > Strong ordering is only active when both the bridge and the IOMMU enable
> >  > it, but for correctly written drivers, this only results in a slowdown.
> > 
> > So when would someone use this dma attribute?  As a hack to fix drivers
> > where the real fix is too complicated?
> 
> This is used in the Axon PCIe endpoint drivers, e.g. in the Roadrunner
> machine. The reason was to improve roundtrip latency by doing only
> mmio stores, not loads, on each side of the PCIe connection, which
> turn into posted DMA operations on the other end. With relaxed ordering,
> the posted writes may be observed out of order. Strong ordering makes
> sure they arrive in-order without having to do a non-posted mmio read
> or eieio operation on the receiver side.

I don't think it's legal for writes from a given initiator to arrive to
memory out of order.

Some drivers, notably network drivers, for example, rely on the "OWN"
bit being written last in memory when writing back ring buffer status.

If the bit arrives before the actual data, then data corruption will
occur.

Ben.

^ permalink raw reply

* Re: powerpc.git merge status
From: Benjamin Herrenschmidt @ 2008-07-17  6:30 UTC (permalink / raw)
  To: avorontsov; +Cc: linuxppc-dev list
In-Reply-To: <20080715113943.GA28229@polina.dev.rtsoft.ru>

On Tue, 2008-07-15 at 15:39 +0400, Anton Vorontsov wrote:
> On Tue, Jul 15, 2008 at 04:02:09PM +1000, Benjamin Herrenschmidt wrote:
> [...]
> > If you believe I've missed something, now is time to be vocal about
> > it :-)
> 
> Yes, this one is lost:
> 
> [OF] of_gpio: should use new <linux/gpio.h> header
> http://patchwork.ozlabs.org/linuxppc/patch?id=18750

Is that supposed to go via the powerpc tree or is there a GPIO tree ? Is
there a GPIO maintainer that should ack it first ?

I know it's a trivial patch but I don't want to start maintainer clashes
right away :-)

Cheers,
Ben.

^ permalink raw reply

* Re: [PATCH] elf loader support for auxvec base platform string
From: Benjamin Herrenschmidt @ 2008-07-17  6:35 UTC (permalink / raw)
  To: Linus Torvalds, Andrew Morton
  Cc: linuxppc-dev, Nathan Lynch, linux-kernel, roland
In-Reply-To: <1216166331-14810-2-git-send-email-ntl@pobox.com>

Hi Linus, Andrew !

Should I seek somebody's ack before merging a patch like the one below ?

I'm a bit reluctant to merge via the powerpc.git tree some changes to
generic files without at least an ack from somebody else :-)

There have been some debate on whether this AT_BASE_PLATFORM is the
right approach, though I haven't seen them reach any useful conclusion
and our toolchain people internally are screaming for it...

Cheers,
Ben.

On Tue, 2008-07-15 at 18:58 -0500, Nathan Lynch wrote:
> Some IBM POWER-based platforms have the ability to run in a
> mode which mostly appears to the OS as a different processor from the
> actual hardware.  For example, a Power6 system may appear to be a
> Power5+, which makes the AT_PLATFORM value "power5+".  This means that
> programs are restricted to the ISA supported by Power5+;
> Power6-specific instructions are treated as illegal.
> 
> However, some applications (virtual machines, optimized libraries) can
> benefit from knowledge of the underlying CPU model.  A new aux vector
> entry, AT_BASE_PLATFORM, will denote the actual hardware.  For
> example, on a Power6 system in Power5+ compatibility mode, AT_PLATFORM
> will be "power5+" and AT_BASE_PLATFORM will be "power6".  The idea is
> that AT_PLATFORM indicates the instruction set supported, while
> AT_BASE_PLATFORM indicates the underlying microarchitecture.
> 
> If the architecture has defined ELF_BASE_PLATFORM, copy that value to
> the user stack in the same manner as ELF_PLATFORM.
> 
> Signed-off-by: Nathan Lynch <ntl@pobox.com>
> ---
>  fs/binfmt_elf.c        |   23 +++++++++++++++++++++++
>  include/linux/auxvec.h |    5 ++++-
>  2 files changed, 27 insertions(+), 1 deletions(-)
> 
> diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
> index d48ff5f..834c2c4 100644
> --- a/fs/binfmt_elf.c
> +++ b/fs/binfmt_elf.c
> @@ -131,6 +131,10 @@ static int padzero(unsigned long elf_bss)
>  #define STACK_ALLOC(sp, len) ({ sp -= len ; sp; })
>  #endif
>  
> +#ifndef ELF_BASE_PLATFORM
> +#define ELF_BASE_PLATFORM NULL
> +#endif
> +
>  static int
>  create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec,
>  		unsigned long load_addr, unsigned long interp_load_addr)
> @@ -142,7 +146,9 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec,
>  	elf_addr_t __user *envp;
>  	elf_addr_t __user *sp;
>  	elf_addr_t __user *u_platform;
> +	elf_addr_t __user *u_base_platform;
>  	const char *k_platform = ELF_PLATFORM;
> +	const char *k_base_platform = ELF_BASE_PLATFORM;
>  	int items;
>  	elf_addr_t *elf_info;
>  	int ei_index = 0;
> @@ -172,6 +178,19 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec,
>  			return -EFAULT;
>  	}
>  
> +	/*
> +	 * If this architecture has a "base" platform capability
> +	 * string, copy it to userspace.
> +	 */
> +	u_base_platform = NULL;
> +	if (k_base_platform) {
> +		size_t len = strlen(k_base_platform) + 1;
> +
> +		u_base_platform = (elf_addr_t __user *)STACK_ALLOC(p, len);
> +		if (__copy_to_user(u_base_platform, k_base_platform, len))
> +			return -EFAULT;
> +	}
> +
>  	/* Create the ELF interpreter info */
>  	elf_info = (elf_addr_t *)current->mm->saved_auxv;
>  	/* update AT_VECTOR_SIZE_BASE if the number of NEW_AUX_ENT() changes */
> @@ -208,6 +227,10 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec,
>  		NEW_AUX_ENT(AT_PLATFORM,
>  			    (elf_addr_t)(unsigned long)u_platform);
>  	}
> +	if (k_base_platform) {
> +		NEW_AUX_ENT(AT_BASE_PLATFORM,
> +			    (elf_addr_t)(unsigned long)u_base_platform);
> +	}
>  	if (bprm->interp_flags & BINPRM_FLAGS_EXECFD) {
>  		NEW_AUX_ENT(AT_EXECFD, bprm->interp_data);
>  	}
> diff --git a/include/linux/auxvec.h b/include/linux/auxvec.h
> index ad89545..1adc61d 100644
> --- a/include/linux/auxvec.h
> +++ b/include/linux/auxvec.h
> @@ -26,8 +26,11 @@
>  
>  #define AT_SECURE 23   /* secure mode boolean */
>  
> +#define AT_BASE_PLATFORM 38	/* string identifying real platform, may
> +				 * differ from AT_PLATFORM. */
> +
>  #ifdef __KERNEL__
> -#define AT_VECTOR_SIZE_BASE (14 + 2) /* NEW_AUX_ENT entries in auxiliary table */
> +#define AT_VECTOR_SIZE_BASE (14 + 3) /* NEW_AUX_ENT entries in auxiliary table */
>  #endif
>  
>  #endif /* _LINUX_AUXVEC_H */

^ permalink raw reply

* Re: PS3 patches for 2.6.27
From: Benjamin Herrenschmidt @ 2008-07-17  6:43 UTC (permalink / raw)
  To: Geoff Levand; +Cc: linuxppc-dev@ozlabs.org
In-Reply-To: <487E6683.9000001@am.sony.com>

On Wed, 2008-07-16 at 14:22 -0700, Geoff Levand wrote:
> Hi Ben,
> 
> Here are two more PS3 patches for 2.6.27.  Please apply.

Thanks, they'll be in my next batch (hopefully tomorrow).

Cheers,
Ben.

^ permalink raw reply

* Re: [PATCH] powerpc: Introduce local (non-broadcast) forms of tlb invalidates
From: Benjamin Herrenschmidt @ 2008-07-17  6:48 UTC (permalink / raw)
  To: Kumar Gala; +Cc: linuxppc-dev
In-Reply-To: <Pine.LNX.4.64.0807151627020.29665@blarg.am.freescale.net>

On Tue, 2008-07-15 at 16:27 -0500, Kumar Gala wrote:
> Introduced a new set of low level tlb invalidate functions that do not
> broadcast invalidates on the bus:
> 
> _tlbil_all - invalidate all
> _tlbil_pid - invalidate based on process id (or mm context)
> _tlbil_va  - invalidate based on virtual address (ea + pid)
> 
> On non-SMP configs _tlbil_all should be functionally equivalent to _tlbia and
> _tlbil_va should be functionally equivalent to _tlbie.
> 
> The intent of this change is to handle SMP based invalidates via IPIs instead
> of broadcasts as the mechanism scales better for larger number of cores.
> 
> On e500 (fsl-booke mmu) based cores move to using MMUCSR for invalidate alls
> and tlbsx/tlbwe for invalidate virtual address.
> 
> Signed-off-by: Kumar Gala <galak@kernel.crashing.org>

Any reason why we have to continue doing those in asm .S files ?

mfspr/mtspr in C work fine and inline asm statements for the
tlbilx instructions proper too :-)

Cheers,
Ben.

> ---
>  arch/powerpc/kernel/misc_32.S   |   53 +++++++++++++++++++++++++++++++++++++++
>  arch/powerpc/kernel/ppc_ksyms.c |    1 +
>  include/asm-powerpc/reg_booke.h |    7 +++++
>  include/asm-powerpc/tlbflush.h  |   13 ++++++---
>  4 files changed, 69 insertions(+), 5 deletions(-)
> 
> diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S
> index 6321ae3..9245b75 100644
> --- a/arch/powerpc/kernel/misc_32.S
> +++ b/arch/powerpc/kernel/misc_32.S
> @@ -274,6 +274,9 @@ _GLOBAL(real_writeb)
>  /*
>   * Flush MMU TLB
>   */
> +#ifndef CONFIG_FSL_BOOKE
> +_GLOBAL(_tlbil_all)
> +#endif
>  _GLOBAL(_tlbia)
>  #if defined(CONFIG_40x)
>  	sync			/* Flush to memory before changing mapping */
> @@ -344,6 +347,9 @@ _GLOBAL(_tlbia)
>  /*
>   * Flush MMU TLB for a particular address
>   */
> +#ifndef CONFIG_FSL_BOOKE
> +_GLOBAL(_tlbil_va)
> +#endif
>  _GLOBAL(_tlbie)
>  #if defined(CONFIG_40x)
>  	/* We run the search with interrupts disabled because we have to change
> @@ -436,6 +442,53 @@ _GLOBAL(_tlbie)
>  #endif /* ! CONFIG_40x */
>  	blr
> 
> +#if defined(CONFIG_FSL_BOOKE)
> +/*
> + * Flush MMU TLB, but only on the local processor (no broadcast)
> + */
> +_GLOBAL(_tlbil_all)
> +#define MMUCSR0_TLBFI	(MMUCSR0_TLB0FI | MMUCSR0_TLB1FI | \
> +			 MMUCSR0_TLB2FI | MMUCSR0_TLB3FI)
> +	li	r3,(MMUCSR0_TLBFI)@l
> +	mtspr	SPRN_MMUCSR0, r3
> +1:
> +	mfspr	r3,SPRN_MMUCSR0
> +	andi.	r3,r3,MMUCSR0_TLBFI@l
> +	bne	1b
> +	blr
> +
> +/*
> + * Flush MMU TLB for a particular process id, but only on the local processor
> + * (no broadcast)
> + */
> +_GLOBAL(_tlbil_pid)
> +	li	r3,(MMUCSR0_TLBFI)@l
> +	mtspr	SPRN_MMUCSR0, r3
> +1:
> +	mfspr	r3,SPRN_MMUCSR0
> +	andi.	r1,r2,MMUCSR0_TLBFI@l
> +	bne	1b
> +	blr
> +
> +/*
> + * Flush MMU TLB for a particular address, but only on the local processor
> + * (no broadcast)
> + */
> +_GLOBAL(_tlbil_va)
> +	slwi	r4,r4,16
> +	mtspr	SPRN_MAS6,r4		/* assume AS=0 for now */
> +	tlbsx	0,r3
> +	mfspr	r4,SPRN_MAS1		/* check valid */
> +	andis.	r3,r4,MAS1_VALID@h
> +	beq	1f
> +	rlwinm	r4,r4,0,1,31
> +	mtspr	SPRN_MAS1,r4
> +	tlbwe
> +1:
> +	blr
> +#endif /* CONFIG_FSL_BOOKE */
> +
> +
>  /*
>   * Flush instruction cache.
>   * This is a no-op on the 601.
> diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c
> index 958ecb9..b7e4ff0 100644
> --- a/arch/powerpc/kernel/ppc_ksyms.c
> +++ b/arch/powerpc/kernel/ppc_ksyms.c
> @@ -114,6 +114,7 @@ EXPORT_SYMBOL(flush_instruction_cache);
>  EXPORT_SYMBOL(flush_tlb_kernel_range);
>  EXPORT_SYMBOL(flush_tlb_page);
>  EXPORT_SYMBOL(_tlbie);
> +EXPORT_SYMBOL(_tlbil_va);
>  #endif
>  EXPORT_SYMBOL(__flush_icache_range);
>  EXPORT_SYMBOL(flush_dcache_range);
> diff --git a/include/asm-powerpc/reg_booke.h b/include/asm-powerpc/reg_booke.h
> index be980f4..6745376 100644
> --- a/include/asm-powerpc/reg_booke.h
> +++ b/include/asm-powerpc/reg_booke.h
> @@ -109,6 +109,7 @@
>  #define SPRN_EVPR	0x3D6	/* Exception Vector Prefix Register */
>  #define SPRN_L1CSR0	0x3F2	/* L1 Cache Control and Status Register 0 */
>  #define SPRN_L1CSR1	0x3F3	/* L1 Cache Control and Status Register 1 */
> +#define SPRN_MMUCSR0	0x3F4	/* MMU Control and Status Register 0 */
>  #define SPRN_PIT	0x3DB	/* Programmable Interval Timer */
>  #define SPRN_BUCSR	0x3F5	/* Branch Unit Control and Status */
>  #define SPRN_L2CSR0	0x3F9	/* L2 Data Cache Control and Status Register 0 */
> @@ -410,6 +411,12 @@
>  #define L2CSR0_L2LOA	0x00000080	/* L2 Cache Lock Overflow Allocate */
>  #define L2CSR0_L2LO	0x00000020	/* L2 Cache Lock Overflow */
> 
> +/* Bit definitions for MMUCSR0 */
> +#define MMUCSR0_TLB1FI	0x00000002	/* TLB1 Flash invalidate */
> +#define MMUCSR0_TLB0FI	0x00000004	/* TLB0 Flash invalidate */
> +#define MMUCSR0_TLB2FI	0x00000040	/* TLB2 Flash invalidate */
> +#define MMUCSR0_TLB3FI	0x00000020	/* TLB3 Flash invalidate */
> +
>  /* Bit definitions for SGR. */
>  #define SGR_NORMAL	0		/* Speculative fetching allowed. */
>  #define SGR_GUARDED	1		/* Speculative fetching disallowed. */
> diff --git a/include/asm-powerpc/tlbflush.h b/include/asm-powerpc/tlbflush.h
> index 5c91081..29da561 100644
> --- a/include/asm-powerpc/tlbflush.h
> +++ b/include/asm-powerpc/tlbflush.h
> @@ -29,6 +29,9 @@
>  #include <linux/mm.h>
> 
>  extern void _tlbie(unsigned long address, unsigned int pid);
> +extern void _tlbil_all(void);
> +extern void _tlbil_pid(unsigned int pid);
> +extern void _tlbil_va(unsigned long address, unsigned int pid);
> 
>  #if defined(CONFIG_40x) || defined(CONFIG_8xx)
>  #define _tlbia()	asm volatile ("tlbia; sync" : : : "memory")
> @@ -38,31 +41,31 @@ extern void _tlbia(void);
> 
>  static inline void flush_tlb_mm(struct mm_struct *mm)
>  {
> -	_tlbia();
> +	_tlbil_all();
>  }
> 
>  static inline void flush_tlb_page(struct vm_area_struct *vma,
>  				  unsigned long vmaddr)
>  {
> -	_tlbie(vmaddr, vma ? vma->vm_mm->context.id : 0);
> +	_tlbil_va(vmaddr, vma ? vma->vm_mm->context.id : 0);
>  }
> 
>  static inline void flush_tlb_page_nohash(struct vm_area_struct *vma,
>  					 unsigned long vmaddr)
>  {
> -	_tlbie(vmaddr, vma ? vma->vm_mm->context.id : 0);
> +	flush_tlb_page(vma, vmaddr);
>  }
> 
>  static inline void flush_tlb_range(struct vm_area_struct *vma,
>  				   unsigned long start, unsigned long end)
>  {
> -	_tlbia();
> +	_tlbil_all();
>  }
> 
>  static inline void flush_tlb_kernel_range(unsigned long start,
>  					  unsigned long end)
>  {
> -	_tlbia();
> +	_tlbil_all();
>  }
> 
>  #elif defined(CONFIG_PPC32)

^ 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