LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH v2] [ALSA] Add ASoC drivers for the Freescale MPC8610 SoC
From: Grant Likely @ 2008-01-10 23:02 UTC (permalink / raw)
  To: Timur Tabi; +Cc: olof, linuxppc-dev, alsa-devel, david
In-Reply-To: <12000050682718-git-send-email-timur@freescale.com>

On 1/10/08, Timur Tabi <timur@freescale.com> wrote:
> Add the ASoC drivers for the Freescale MPC8610 SoC and the MPC8610 HPCD
> reference board.
>
> Signed-off-by: Timur Tabi <timur@freescale.com>

This is a very big patch, but I'm going to keep my nose out of the
ALSA stuff.  I've got no problem against it being merged, but I do
have a concern about access to shared registers (see below)

> diff --git a/sound/soc/fsl/mpc8610_hpcd.c b/sound/soc/fsl/mpc8610_hpcd.c
> new file mode 100644
> index 0000000..f26c4b2
> --- /dev/null
> +++ b/sound/soc/fsl/mpc8610_hpcd.c
> +/**
> + * mpc8610_hpcd_probe: OF probe function for the fabric driver
> + *
> + * This function gets called when an SSI node is found in the device tree.
> + *
> + * Although this is a fabric driver, the SSI node is the "master" node with
> + * respect to audio hardware connections.  Therefore, we create a new ASoC
> + * device for each new SSI node that has a codec attached.
> + *
> + * FIXME: Currently, we only support one DMA controller, so if there are
> + * multiple SSI nodes with codecs, only the first will be supported.
> + *
> + * FIXME: Even if we did support multiple DMA controllers, we have no
> + * mechanism for assigning DMA controllers and channels to the individual
> + * SSI devices.  We also probably aren't compatible with the generic Elo DMA
> + * device driver.
> + */
> +static int mpc8610_hpcd_probe(struct of_device *ofdev,
> +       const struct of_device_id *match)
> +{
<snip>
> +       /* Map the global utilities registers. */
> +       guts_np = of_find_compatible_node(NULL, NULL, "fsl,mpc8610-guts");
> +       if (!guts_np) {
> +               dev_err(&ofdev->dev, "could not obtain address of GUTS\n");
> +               ret = -EINVAL;
> +               goto error;
> +       }

This...

> +       /* Find the DMA channels to use.  For now, we always use the first DMA
> +          controller. */
> +       for_each_compatible_node(dma_np, NULL, "fsl,mpc8610-dma") {
> +               iprop = of_get_property(dma_np, "cell-index", NULL);
> +               if (iprop && (*iprop == 0)) {
> +                       of_node_put(dma_np);
> +                       break;
> +               }
> +       }

and this...

Does the driver access the DMA and GUTS registers directly?  If so,
what do you have to protect against race conditions of other drivers
accessing them also.

Cheers,
g.

-- 
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

^ permalink raw reply

* Re: [PATCH 3/5] Warp Base Platform
From: Sean MacLennan @ 2008-01-11  0:04 UTC (permalink / raw)
  To: linuxppc-dev
In-Reply-To: <20080110024926.GD17816@localhost.localdomain>

David Gibson wrote:
>
> Fold all this into cuboot-warp.c, unless you actually anticipate
> adding another wrapper for another firmware which will also use the
> functions in warp.c.
>
>   
Done.

Signed-off-by: Sean MacLennan <smaclennan@pikatech.com>
---
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 66a3d8c..b3e4c35 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -469,7 +469,7 @@ config MCA
 config PCI
 	bool "PCI support" if 40x || CPM2 || PPC_83xx || PPC_85xx || PPC_86xx \
 		|| PPC_MPC52xx || (EMBEDDED && (PPC_PSERIES || PPC_ISERIES)) \
-		|| PPC_PS3
+		|| PPC_PS3 || 44x
 	default y if !40x && !CPM2 && !8xx && !PPC_83xx \
 		&& !PPC_85xx && !PPC_86xx
 	default PCI_PERMEDIA if !4xx && !CPM2 && !8xx
diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile
index d1e625c..cd83c4f 100644
--- a/arch/powerpc/boot/Makefile
+++ b/arch/powerpc/boot/Makefile
@@ -62,7 +62,7 @@ src-plat := of.c cuboot-52xx.c cuboot-83xx.c cuboot-85xx.c holly.c \
 		ps3-head.S ps3-hvcall.S ps3.c treeboot-bamboo.c cuboot-8xx.c \
 		cuboot-pq2.c cuboot-sequoia.c treeboot-walnut.c cuboot-bamboo.c \
 		fixed-head.S ep88xc.c cuboot-hpc2.c ep405.c cuboot-taishan.c \
-		cuboot-katmai.c cuboot-rainier.c
+		cuboot-katmai.c cuboot-rainier.c cuboot-warp.c
 src-boot := $(src-wlib) $(src-plat) empty.c
 
 src-boot := $(addprefix $(obj)/, $(src-boot))
@@ -206,6 +206,7 @@ image-$(CONFIG_RAINIER)			+= cuImage.rainier
 image-$(CONFIG_WALNUT)			+= treeImage.walnut
 image-$(CONFIG_TAISHAN)			+= cuImage.taishan
 image-$(CONFIG_KATMAI)			+= cuImage.katmai
+image-$(CONFIG_WARP)			+= cuImage.warp
 endif
 
 # For 32-bit powermacs, build the COFF and miboot images
--- /dev/null	2005-11-20 22:22:37.000000000 -0500
+++ arch/powerpc/boot/cuboot-warp.c	2008-01-10 15:28:30.000000000 -0500
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2008 PIKA Technologies
+ *   Sean MacLennan <smaclennan@pikatech.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include "ops.h"
+#include "4xx.h"
+#include "cuboot.h"
+
+#define TARGET_44x
+#include "ppcboot.h"
+
+static bd_t bd;
+
+static void warp_fixups(void)
+{
+	unsigned long sysclk = 66000000;
+
+	ibm440ep_fixup_clocks(sysclk, 11059200, 50000000);
+	ibm4xx_sdram_fixup_memsize();
+	dt_fixup_mac_addresses(&bd.bi_enetaddr);
+}
+
+
+void platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+		   unsigned long r6, unsigned long r7)
+{
+	CUBOOT_INIT();
+
+	platform_ops.fixups = warp_fixups;
+	platform_ops.exit = ibm44x_dbcr_reset;
+	fdt_init(_dtb_start);
+	serial_console_init();
+}

^ permalink raw reply related

* Re: [alsa-devel] [PATCH v2] [ALSA] Add ASoC drivers for the Freescale MPC8610 SoC
From: Timur Tabi @ 2008-01-10 23:12 UTC (permalink / raw)
  To: Grant Likely; +Cc: olof, linuxppc-dev, alsa-devel, david
In-Reply-To: <fa686aa40801101502v264d8caw6faf935d71b15c9@mail.gmail.com>

Grant Likely wrote:

> Does the driver access the DMA and GUTS registers directly?  If so,
> what do you have to protect against race conditions of other drivers
> accessing them also.

I don't have any more protection than any other driver that accesses SOC 
registers directly.  Last I heard, Zhang's DMA driver was in limbo, and that 
driver would be the best place to arbitrate DMA register access.  I was planning 
on adding arbitration support to that driver after both drivers were applied.

As for the GUTS driver, well, I just program a few registers at startup, and I 
don't think any other driver touches them.

-- 
Timur Tabi
Linux kernel developer at Freescale

^ permalink raw reply

* Re: [alsa-devel] [PATCH v2] [ALSA] Add ASoC drivers for the Freescale MPC8610 SoC
From: Grant Likely @ 2008-01-10 23:17 UTC (permalink / raw)
  To: Timur Tabi; +Cc: olof, linuxppc-dev, alsa-devel, david
In-Reply-To: <4786A650.2080107@freescale.com>

On 1/10/08, Timur Tabi <timur@freescale.com> wrote:
> Grant Likely wrote:
>
> > Does the driver access the DMA and GUTS registers directly?  If so,
> > what do you have to protect against race conditions of other drivers
> > accessing them also.
>
> I don't have any more protection than any other driver that accesses SOC
> registers directly.  Last I heard, Zhang's DMA driver was in limbo, and that
> driver would be the best place to arbitrate DMA register access.  I was planning
> on adding arbitration support to that driver after both drivers were applied.

That sounds appropriate

>
> As for the GUTS driver, well, I just program a few registers at startup, and I
> don't think any other driver touches them.

Okay; at some point in the future they'll need to be accessed from a
common routine too.

g.

-- 
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

^ permalink raw reply

* Re: [alsa-devel] [PATCH v2] [ALSA] Add ASoC drivers for the Freescale MPC8610 SoC
From: Timur Tabi @ 2008-01-10 23:19 UTC (permalink / raw)
  To: Grant Likely; +Cc: olof, linuxppc-dev, alsa-devel, david
In-Reply-To: <fa686aa40801101517q2d4e6673l995ef4123f0d0ad4@mail.gmail.com>

Grant Likely wrote:

>> As for the GUTS driver, well, I just program a few registers at startup, and I
>> don't think any other driver touches them.
> 
> Okay; at some point in the future they'll need to be accessed from a
> common routine too.

I'll add that to my to-do list.

-- 
Timur Tabi
Linux kernel developer at Freescale

^ permalink raw reply

* [patch 4/4 v4] PS3: Add logical performance monitor driver support
From: Geoff Levand @ 2008-01-10 23:39 UTC (permalink / raw)
  To: paulus; +Cc: linuxppc-dev, Takashi Yamamoto
In-Reply-To: <47856E80.2080209@am.sony.com>


From: Takashi Yamamoto <TakashiA.Yamamoto@jp.sony.com>

Add PS3 logical performance monitor (lpm) device driver.

The PS3's LV1 hypervisor provides a Logical Performance Monitor that
abstracts the Cell processor's performance monitor features for use
by guest operating systems.

Signed-off-by: Takashi Yamamoto <TakashiA.Yamamoto@jp.sony.com>
Signed-off-by: Geoff Levand <geoffrey.levand@am.sony.com>
---
v2: o Correct Yamamoto-san's mail addr.
    o Text cleanups.
    o Added more comments explaining lpm operation.
    o Split SRPN_BKMK into separate patch.
    o Use get_hard_smp_processor_id() in ps3_get_hw_thread_id().
    o Split ps3_copy_trace_buffer() into ps3_lpm_copy_tb() and ps3_lpm_copy_tb_to_user().
    o Replace mutex with atomic_t in ps3_lpm_open()/ps3_lpm_close().
    o General cleanup of ps3_lpm_open()/ps3_lpm_close().
v3: o Add BE node_id to struct lpm_priv.
    o Change some dev_err() to dev_dbg().
    o Fix kzalloc() bug.
    o Text fix s/lost/loss/.
    o Use lpm_priv->node_id with lv1_construct_lpm().
v4: o Text fix s/whos/whose/.

 arch/powerpc/platforms/ps3/Kconfig |   13 
 drivers/ps3/Makefile               |    1 
 drivers/ps3/ps3-lpm.c              | 1248 +++++++++++++++++++++++++++++++++++++
 include/asm-powerpc/ps3.h          |   62 +
 4 files changed, 1324 insertions(+)
 create mode 100644 arch/powerpc/platforms/ps3/ps3-lpm.c

--- a/arch/powerpc/platforms/ps3/Kconfig
+++ b/arch/powerpc/platforms/ps3/Kconfig
@@ -138,4 +138,17 @@ config PS3_FLASH
 	  be disabled on the kernel command line using "ps3flash=off", to
 	  not allocate this fixed buffer.
 
+config PS3_LPM
+	tristate "PS3 Logical Performance Monitor support"
+	depends on PPC_PS3
+	help
+	  Include support for the PS3 Logical Performance Monitor.
+
+	  This support is required to use the logical performance monitor
+	  of the PS3's LV1 hypervisor.
+
+	  If you intend to use the advanced performance monitoring and
+	  profiling support of the Cell processor with programs like
+	  oprofile and perfmon2, then say Y or M, otherwise say N.
+
 endmenu
--- a/drivers/ps3/Makefile
+++ b/drivers/ps3/Makefile
@@ -4,3 +4,4 @@ ps3av_mod-objs		+= ps3av.o ps3av_cmd.o
 obj-$(CONFIG_PPC_PS3) += sys-manager-core.o
 obj-$(CONFIG_PS3_SYS_MANAGER) += ps3-sys-manager.o
 obj-$(CONFIG_PS3_STORAGE) += ps3stor_lib.o
+obj-$(CONFIG_PS3_LPM) += ps3-lpm.o
--- /dev/null
+++ b/drivers/ps3/ps3-lpm.c
@@ -0,0 +1,1248 @@
+/*
+ * PS3 Logical Performance Monitor.
+ *
+ *  Copyright (C) 2007 Sony Computer Entertainment Inc.
+ *  Copyright 2007 Sony Corp.
+ *
+ *  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; version 2 of the License.
+ *
+ *  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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/uaccess.h>
+#include <asm/ps3.h>
+#include <asm/lv1call.h>
+#include <asm/cell-pmu.h>
+
+
+/* BOOKMARK tag macros */
+#define PS3_PM_BOOKMARK_START                    0x8000000000000000ULL
+#define PS3_PM_BOOKMARK_STOP                     0x4000000000000000ULL
+#define PS3_PM_BOOKMARK_TAG_KERNEL               0x1000000000000000ULL
+#define PS3_PM_BOOKMARK_TAG_USER                 0x3000000000000000ULL
+#define PS3_PM_BOOKMARK_TAG_MASK_HI              0xF000000000000000ULL
+#define PS3_PM_BOOKMARK_TAG_MASK_LO              0x0F00000000000000ULL
+
+/* CBE PM CONTROL register macros */
+#define PS3_PM_CONTROL_PPU_TH0_BOOKMARK          0x00001000
+#define PS3_PM_CONTROL_PPU_TH1_BOOKMARK          0x00000800
+#define PS3_PM_CONTROL_PPU_COUNT_MODE_MASK       0x000C0000
+#define PS3_PM_CONTROL_PPU_COUNT_MODE_PROBLEM    0x00080000
+#define PS3_WRITE_PM_MASK                        0xFFFFFFFFFFFFFFFFULL
+
+/* CBE PM START STOP register macros */
+#define PS3_PM_START_STOP_PPU_TH0_BOOKMARK_START 0x02000000
+#define PS3_PM_START_STOP_PPU_TH1_BOOKMARK_START 0x01000000
+#define PS3_PM_START_STOP_PPU_TH0_BOOKMARK_STOP  0x00020000
+#define PS3_PM_START_STOP_PPU_TH1_BOOKMARK_STOP  0x00010000
+#define PS3_PM_START_STOP_START_MASK             0xFF000000
+#define PS3_PM_START_STOP_STOP_MASK              0x00FF0000
+
+/* CBE PM COUNTER register macres */
+#define PS3_PM_COUNTER_MASK_HI                   0xFFFFFFFF00000000ULL
+#define PS3_PM_COUNTER_MASK_LO                   0x00000000FFFFFFFFULL
+
+/* BASE SIGNAL GROUP NUMBER macros */
+#define PM_ISLAND2_BASE_SIGNAL_GROUP_NUMBER  0
+#define PM_ISLAND2_SIGNAL_GROUP_NUMBER1      6
+#define PM_ISLAND2_SIGNAL_GROUP_NUMBER2      7
+#define PM_ISLAND3_BASE_SIGNAL_GROUP_NUMBER  7
+#define PM_ISLAND4_BASE_SIGNAL_GROUP_NUMBER  15
+#define PM_SPU_TRIGGER_SIGNAL_GROUP_NUMBER   17
+#define PM_SPU_EVENT_SIGNAL_GROUP_NUMBER     18
+#define PM_ISLAND5_BASE_SIGNAL_GROUP_NUMBER  18
+#define PM_ISLAND6_BASE_SIGNAL_GROUP_NUMBER  24
+#define PM_ISLAND7_BASE_SIGNAL_GROUP_NUMBER  49
+#define PM_ISLAND8_BASE_SIGNAL_GROUP_NUMBER  52
+#define PM_SIG_GROUP_SPU                     41
+#define PM_SIG_GROUP_SPU_TRIGGER             42
+#define PM_SIG_GROUP_SPU_EVENT               43
+#define PM_SIG_GROUP_MFC_MAX                 60
+
+/**
+ * struct ps3_lpm_shadow_regs - Performance monitor shadow registers.
+ *
+ * @pm_control: Shadow of the processor's pm_control register.
+ * @pm_start_stop: Shadow of the processor's pm_start_stop register.
+ * @pm_interval: Shadow of the processor's pm_interval register.
+ * @group_control: Shadow of the processor's group_control register.
+ * @debug_bus_control: Shadow of the processor's debug_bus_control register.
+ *
+ * The logical performance monitor provides a write-only interface to
+ * these processor registers.  These shadow variables cache the processor
+ * register values for reading.
+ *
+ * The initial value of the shadow registers at lpm creation is
+ * PS3_LPM_SHADOW_REG_INIT.
+ */
+
+struct ps3_lpm_shadow_regs {
+	u64 pm_control;
+	u64 pm_start_stop;
+	u64 pm_interval;
+	u64 group_control;
+	u64 debug_bus_control;
+};
+
+#define PS3_LPM_SHADOW_REG_INIT 0xFFFFFFFF00000000ULL
+
+/**
+ * struct ps3_lpm_priv - Private lpm device data.
+ *
+ * @open: An atomic variable indicating the lpm driver has been opened.
+ * @rights: The lpm rigths granted by the system policy module.  A logical
+ *  OR of enum ps3_lpm_rights.
+ * @node_id: The node id of a BE prosessor whose performance monitor this
+ *  lpar has the right to use.
+ * @pu_id: The lv1 id of the logical PU.
+ * @lpm_id: The lv1 id of this lpm instance.
+ * @outlet_id: The outlet created by lv1 for this lpm instance.
+ * @tb_count: The number of bytes of data held in the lv1 trace buffer.
+ * @tb_cache: Kernel buffer to receive the data from the lv1 trace buffer.
+ *  Must be 128 byte aligned.
+ * @tb_cache_size: Size of the kernel @tb_cache buffer.  Must be 128 byte
+ *  aligned.
+ * @tb_cache_internal: An unaligned buffer allocated by this driver to be
+ *  used for the trace buffer cache when ps3_lpm_open() is called with a
+ *  NULL tb_cache argument.  Otherwise unused.
+ * @shadow: Processor register shadow of type struct ps3_lpm_shadow_regs.
+ * @sbd: The struct ps3_system_bus_device attached to this driver.
+ *
+ * The trace buffer is a buffer allocated and used internally to the lv1
+ * hypervisor to collect trace data.  The trace buffer cache is a guest
+ * buffer that accepts the trace data from the trace buffer.
+ */
+
+struct ps3_lpm_priv {
+	atomic_t open;
+	u64 rights;
+	u64 node_id;
+	u64 pu_id;
+	u64 lpm_id;
+	u64 outlet_id;
+	u64 tb_count;
+	void *tb_cache;
+	u64 tb_cache_size;
+	void *tb_cache_internal;
+	struct ps3_lpm_shadow_regs shadow;
+	struct ps3_system_bus_device *sbd;
+};
+
+enum {
+	PS3_LPM_DEFAULT_TB_CACHE_SIZE = 0x4000,
+};
+
+/**
+ * lpm_priv - Static instance of the lpm data.
+ *
+ * Since the exported routines don't support the notion of a device
+ * instance we need to hold the instance in this static variable
+ * and then only allow at most one instance at a time to be created.
+ */
+
+static struct ps3_lpm_priv *lpm_priv;
+
+static struct device *sbd_core(void)
+{
+	BUG_ON(!lpm_priv || !lpm_priv->sbd);
+	return &lpm_priv->sbd->core;
+}
+
+/**
+ * use_start_stop_bookmark - Enable the PPU bookmark trace.
+ *
+ * And it enables PPU bookmark triggers ONLY if the other triggers are not set.
+ * The start/stop bookmarks are inserted at ps3_enable_pm() and ps3_disable_pm()
+ * to start/stop LPM.
+ *
+ * Used to get good quality of the performance counter.
+ */
+
+enum {use_start_stop_bookmark = 1,};
+
+void ps3_set_bookmark(u64 bookmark)
+{
+	/*
+	 * As per the PPE book IV, to avoid bookmark loss there must
+	 * not be a traced branch within 10 cycles of setting the
+	 * SPRN_BKMK register.  The actual text is unclear if 'within'
+	 * includes cycles before the call.
+	 */
+
+	asm volatile("or 29, 29, 29;"); /* db10cyc */
+	mtspr(SPRN_BKMK, bookmark);
+	asm volatile("or 29, 29, 29;"); /* db10cyc */
+}
+EXPORT_SYMBOL_GPL(ps3_set_bookmark);
+
+void ps3_set_pm_bookmark(u64 tag, u64 incident, u64 th_id)
+{
+	u64 bookmark;
+
+	bookmark = (get_tb() & 0x00000000FFFFFFFFULL) |
+		PS3_PM_BOOKMARK_TAG_KERNEL;
+	bookmark = ((tag << 56) & PS3_PM_BOOKMARK_TAG_MASK_LO) |
+		(incident << 48) | (th_id << 32) | bookmark;
+	ps3_set_bookmark(bookmark);
+}
+EXPORT_SYMBOL_GPL(ps3_set_pm_bookmark);
+
+/**
+ * ps3_read_phys_ctr - Read physical counter registers.
+ *
+ * Each physical counter can act as one 32 bit counter or as two 16 bit
+ * counters.
+ */
+
+u32 ps3_read_phys_ctr(u32 cpu, u32 phys_ctr)
+{
+	int result;
+	u64 counter0415;
+	u64 counter2637;
+
+	if (phys_ctr >= NR_PHYS_CTRS) {
+		dev_dbg(sbd_core(), "%s:%u: phys_ctr too big: %u\n", __func__,
+			__LINE__, phys_ctr);
+		return 0;
+	}
+
+	result = lv1_set_lpm_counter(lpm_priv->lpm_id, 0, 0, 0, 0, &counter0415,
+				     &counter2637);
+	if (result) {
+		dev_err(sbd_core(), "%s:%u: lv1_set_lpm_counter failed: "
+			"phys_ctr %u, %s\n", __func__, __LINE__, phys_ctr,
+			ps3_result(result));
+		return 0;
+	}
+
+	switch (phys_ctr) {
+	case 0:
+		return counter0415 >> 32;
+	case 1:
+		return counter0415 & PS3_PM_COUNTER_MASK_LO;
+	case 2:
+		return counter2637 >> 32;
+	case 3:
+		return counter2637 & PS3_PM_COUNTER_MASK_LO;
+	default:
+		BUG();
+	}
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ps3_read_phys_ctr);
+
+/**
+ * ps3_write_phys_ctr - Write physical counter registers.
+ *
+ * Each physical counter can act as one 32 bit counter or as two 16 bit
+ * counters.
+ */
+
+void ps3_write_phys_ctr(u32 cpu, u32 phys_ctr, u32 val)
+{
+	u64 counter0415;
+	u64 counter0415_mask;
+	u64 counter2637;
+	u64 counter2637_mask;
+	int result;
+
+	if (phys_ctr >= NR_PHYS_CTRS) {
+		dev_dbg(sbd_core(), "%s:%u: phys_ctr too big: %u\n", __func__,
+			__LINE__, phys_ctr);
+		return;
+	}
+
+	switch (phys_ctr) {
+	case 0:
+		counter0415 = (u64)val << 32;
+		counter0415_mask = PS3_PM_COUNTER_MASK_HI;
+		counter2637 = 0x0;
+		counter2637_mask = 0x0;
+		break;
+	case 1:
+		counter0415 = (u64)val;
+		counter0415_mask = PS3_PM_COUNTER_MASK_LO;
+		counter2637 = 0x0;
+		counter2637_mask = 0x0;
+		break;
+	case 2:
+		counter0415 = 0x0;
+		counter0415_mask = 0x0;
+		counter2637 = (u64)val << 32;
+		counter2637_mask = PS3_PM_COUNTER_MASK_HI;
+		break;
+	case 3:
+		counter0415 = 0x0;
+		counter0415_mask = 0x0;
+		counter2637 = (u64)val;
+		counter2637_mask = PS3_PM_COUNTER_MASK_LO;
+		break;
+	default:
+		BUG();
+	}
+
+	result = lv1_set_lpm_counter(lpm_priv->lpm_id,
+				     counter0415, counter0415_mask,
+				     counter2637, counter2637_mask,
+				     &counter0415, &counter2637);
+	if (result)
+		dev_err(sbd_core(), "%s:%u: lv1_set_lpm_counter failed: "
+			"phys_ctr %u, val %u, %s\n", __func__, __LINE__,
+			phys_ctr, val, ps3_result(result));
+}
+EXPORT_SYMBOL_GPL(ps3_write_phys_ctr);
+
+/**
+ * ps3_read_ctr - Read counter.
+ *
+ * Read 16 or 32 bits depending on the current size of the counter.
+ * Counters 4, 5, 6 & 7 are always 16 bit.
+ */
+
+u32 ps3_read_ctr(u32 cpu, u32 ctr)
+{
+	u32 val;
+	u32 phys_ctr = ctr & (NR_PHYS_CTRS - 1);
+
+	val = ps3_read_phys_ctr(cpu, phys_ctr);
+
+	if (ps3_get_ctr_size(cpu, phys_ctr) == 16)
+		val = (ctr < NR_PHYS_CTRS) ? (val >> 16) : (val & 0xffff);
+
+	return val;
+}
+EXPORT_SYMBOL_GPL(ps3_read_ctr);
+
+/**
+ * ps3_write_ctr - Write counter.
+ *
+ * Write 16 or 32 bits depending on the current size of the counter.
+ * Counters 4, 5, 6 & 7 are always 16 bit.
+ */
+
+void ps3_write_ctr(u32 cpu, u32 ctr, u32 val)
+{
+	u32 phys_ctr;
+	u32 phys_val;
+
+	phys_ctr = ctr & (NR_PHYS_CTRS - 1);
+
+	if (ps3_get_ctr_size(cpu, phys_ctr) == 16) {
+		phys_val = ps3_read_phys_ctr(cpu, phys_ctr);
+
+		if (ctr < NR_PHYS_CTRS)
+			val = (val << 16) | (phys_val & 0xffff);
+		else
+			val = (val & 0xffff) | (phys_val & 0xffff0000);
+	}
+
+	ps3_write_phys_ctr(cpu, phys_ctr, val);
+}
+EXPORT_SYMBOL_GPL(ps3_write_ctr);
+
+/**
+ * ps3_read_pm07_control - Read counter control registers.
+ *
+ * Each logical counter has a corresponding control register.
+ */
+
+u32 ps3_read_pm07_control(u32 cpu, u32 ctr)
+{
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ps3_read_pm07_control);
+
+/**
+ * ps3_write_pm07_control - Write counter control registers.
+ *
+ * Each logical counter has a corresponding control register.
+ */
+
+void ps3_write_pm07_control(u32 cpu, u32 ctr, u32 val)
+{
+	int result;
+	static const u64 mask = 0xFFFFFFFFFFFFFFFFULL;
+	u64 old_value;
+
+	if (ctr >= NR_CTRS) {
+		dev_dbg(sbd_core(), "%s:%u: ctr too big: %u\n", __func__,
+			__LINE__, ctr);
+		return;
+	}
+
+	result = lv1_set_lpm_counter_control(lpm_priv->lpm_id, ctr, val, mask,
+					     &old_value);
+	if (result)
+		dev_err(sbd_core(), "%s:%u: lv1_set_lpm_counter_control "
+			"failed: ctr %u, %s\n", __func__, __LINE__, ctr,
+			ps3_result(result));
+}
+EXPORT_SYMBOL_GPL(ps3_write_pm07_control);
+
+/**
+ * ps3_read_pm - Read Other LPM control registers.
+ */
+
+u32 ps3_read_pm(u32 cpu, enum pm_reg_name reg)
+{
+	int result = 0;
+	u64 val = 0;
+
+	switch (reg) {
+	case pm_control:
+		return lpm_priv->shadow.pm_control;
+	case trace_address:
+		return CBE_PM_TRACE_BUF_EMPTY;
+	case pm_start_stop:
+		return lpm_priv->shadow.pm_start_stop;
+	case pm_interval:
+		return lpm_priv->shadow.pm_interval;
+	case group_control:
+		return lpm_priv->shadow.group_control;
+	case debug_bus_control:
+		return lpm_priv->shadow.debug_bus_control;
+	case pm_status:
+		result = lv1_get_lpm_interrupt_status(lpm_priv->lpm_id,
+						      &val);
+		if (result) {
+			val = 0;
+			dev_dbg(sbd_core(), "%s:%u: lv1 get_lpm_status failed: "
+				"reg %u, %s\n", __func__, __LINE__, reg,
+				ps3_result(result));
+		}
+		return (u32)val;
+	case ext_tr_timer:
+		return 0;
+	default:
+		dev_dbg(sbd_core(), "%s:%u: unknown reg: %d\n", __func__,
+			__LINE__, reg);
+		BUG();
+		break;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ps3_read_pm);
+
+/**
+ * ps3_write_pm - Write Other LPM control registers.
+ */
+
+void ps3_write_pm(u32 cpu, enum pm_reg_name reg, u32 val)
+{
+	int result = 0;
+	u64 dummy;
+
+	switch (reg) {
+	case group_control:
+		if (val != lpm_priv->shadow.group_control)
+			result = lv1_set_lpm_group_control(lpm_priv->lpm_id,
+							   val,
+							   PS3_WRITE_PM_MASK,
+							   &dummy);
+		lpm_priv->shadow.group_control = val;
+		break;
+	case debug_bus_control:
+		if (val != lpm_priv->shadow.debug_bus_control)
+			result = lv1_set_lpm_debug_bus_control(lpm_priv->lpm_id,
+							      val,
+							      PS3_WRITE_PM_MASK,
+							      &dummy);
+		lpm_priv->shadow.debug_bus_control = val;
+		break;
+	case pm_control:
+		if (use_start_stop_bookmark)
+			val |= (PS3_PM_CONTROL_PPU_TH0_BOOKMARK |
+				PS3_PM_CONTROL_PPU_TH1_BOOKMARK);
+		if (val != lpm_priv->shadow.pm_control)
+			result = lv1_set_lpm_general_control(lpm_priv->lpm_id,
+							     val,
+							     PS3_WRITE_PM_MASK,
+							     0, 0, &dummy,
+							     &dummy);
+		lpm_priv->shadow.pm_control = val;
+		break;
+	case pm_interval:
+		if (val != lpm_priv->shadow.pm_interval)
+			result = lv1_set_lpm_interval(lpm_priv->lpm_id, val,
+						   PS3_WRITE_PM_MASK, &dummy);
+		lpm_priv->shadow.pm_interval = val;
+		break;
+	case pm_start_stop:
+		if (val != lpm_priv->shadow.pm_start_stop)
+			result = lv1_set_lpm_trigger_control(lpm_priv->lpm_id,
+							     val,
+							     PS3_WRITE_PM_MASK,
+							     &dummy);
+		lpm_priv->shadow.pm_start_stop = val;
+		break;
+	case trace_address:
+	case ext_tr_timer:
+	case pm_status:
+		break;
+	default:
+		dev_dbg(sbd_core(), "%s:%u: unknown reg: %d\n", __func__,
+			__LINE__, reg);
+		BUG();
+		break;
+	}
+
+	if (result)
+		dev_err(sbd_core(), "%s:%u: lv1 set_control failed: "
+			"reg %u, %s\n", __func__, __LINE__, reg,
+			ps3_result(result));
+}
+EXPORT_SYMBOL_GPL(ps3_write_pm);
+
+/**
+ * ps3_get_ctr_size - Get the size of a physical counter.
+ *
+ * Returns either 16 or 32.
+ */
+
+u32 ps3_get_ctr_size(u32 cpu, u32 phys_ctr)
+{
+	u32 pm_ctrl;
+
+	if (phys_ctr >= NR_PHYS_CTRS) {
+		dev_dbg(sbd_core(), "%s:%u: phys_ctr too big: %u\n", __func__,
+			__LINE__, phys_ctr);
+		return 0;
+	}
+
+	pm_ctrl = ps3_read_pm(cpu, pm_control);
+	return (pm_ctrl & CBE_PM_16BIT_CTR(phys_ctr)) ? 16 : 32;
+}
+EXPORT_SYMBOL_GPL(ps3_get_ctr_size);
+
+/**
+ * ps3_set_ctr_size - Set the size of a physical counter to 16 or 32 bits.
+ */
+
+void ps3_set_ctr_size(u32 cpu, u32 phys_ctr, u32 ctr_size)
+{
+	u32 pm_ctrl;
+
+	if (phys_ctr >= NR_PHYS_CTRS) {
+		dev_dbg(sbd_core(), "%s:%u: phys_ctr too big: %u\n", __func__,
+			__LINE__, phys_ctr);
+		return;
+	}
+
+	pm_ctrl = ps3_read_pm(cpu, pm_control);
+
+	switch (ctr_size) {
+	case 16:
+		pm_ctrl |= CBE_PM_16BIT_CTR(phys_ctr);
+		ps3_write_pm(cpu, pm_control, pm_ctrl);
+		break;
+
+	case 32:
+		pm_ctrl &= ~CBE_PM_16BIT_CTR(phys_ctr);
+		ps3_write_pm(cpu, pm_control, pm_ctrl);
+		break;
+	default:
+		BUG();
+	}
+}
+EXPORT_SYMBOL_GPL(ps3_set_ctr_size);
+
+static u64 pm_translate_signal_group_number_on_island2(u64 subgroup)
+{
+
+	if (subgroup == 2)
+		subgroup = 3;
+
+	if (subgroup <= 6)
+		return PM_ISLAND2_BASE_SIGNAL_GROUP_NUMBER + subgroup;
+	else if (subgroup == 7)
+		return PM_ISLAND2_SIGNAL_GROUP_NUMBER1;
+	else
+		return PM_ISLAND2_SIGNAL_GROUP_NUMBER2;
+}
+
+static u64 pm_translate_signal_group_number_on_island3(u64 subgroup)
+{
+
+	switch (subgroup) {
+	case 2:
+	case 3:
+	case 4:
+		subgroup += 2;
+		break;
+	case 5:
+		subgroup = 8;
+		break;
+	default:
+		break;
+	}
+	return PM_ISLAND3_BASE_SIGNAL_GROUP_NUMBER + subgroup;
+}
+
+static u64 pm_translate_signal_group_number_on_island4(u64 subgroup)
+{
+	return PM_ISLAND4_BASE_SIGNAL_GROUP_NUMBER + subgroup;
+}
+
+static u64 pm_translate_signal_group_number_on_island5(u64 subgroup)
+{
+
+	switch (subgroup) {
+	case 3:
+		subgroup = 4;
+		break;
+	case 4:
+		subgroup = 6;
+		break;
+	default:
+		break;
+	}
+	return PM_ISLAND5_BASE_SIGNAL_GROUP_NUMBER + subgroup;
+}
+
+static u64 pm_translate_signal_group_number_on_island6(u64 subgroup,
+						       u64 subsubgroup)
+{
+	switch (subgroup) {
+	case 3:
+	case 4:
+	case 5:
+		subgroup += 1;
+		break;
+	default:
+		break;
+	}
+
+	switch (subsubgroup) {
+	case 4:
+	case 5:
+	case 6:
+		subsubgroup += 2;
+		break;
+	case 7:
+	case 8:
+	case 9:
+	case 10:
+		subsubgroup += 4;
+		break;
+	case 11:
+	case 12:
+	case 13:
+		subsubgroup += 5;
+		break;
+	default:
+		break;
+	}
+
+	if (subgroup <= 5)
+		return (PM_ISLAND6_BASE_SIGNAL_GROUP_NUMBER + subgroup);
+	else
+		return (PM_ISLAND6_BASE_SIGNAL_GROUP_NUMBER + subgroup
+			+ subsubgroup - 1);
+}
+
+static u64 pm_translate_signal_group_number_on_island7(u64 subgroup)
+{
+	return PM_ISLAND7_BASE_SIGNAL_GROUP_NUMBER + subgroup;
+}
+
+static u64 pm_translate_signal_group_number_on_island8(u64 subgroup)
+{
+	return PM_ISLAND8_BASE_SIGNAL_GROUP_NUMBER + subgroup;
+}
+
+static u64 pm_signal_group_to_ps3_lv1_signal_group(u64 group)
+{
+	u64 island;
+	u64 subgroup;
+	u64 subsubgroup;
+
+	subgroup = 0;
+	subsubgroup = 0;
+	island = 0;
+	if (group < 1000) {
+		if (group < 100) {
+			if (20 <= group && group < 30) {
+				island = 2;
+				subgroup = group - 20;
+			} else if (30 <= group && group < 40) {
+				island = 3;
+				subgroup = group - 30;
+			} else if (40 <= group && group < 50) {
+				island = 4;
+				subgroup = group - 40;
+			} else if (50 <= group && group < 60) {
+				island = 5;
+				subgroup = group - 50;
+			} else if (60 <= group && group < 70) {
+				island = 6;
+				subgroup = group - 60;
+			} else if (70 <= group && group < 80) {
+				island = 7;
+				subgroup = group - 70;
+			} else if (80 <= group && group < 90) {
+				island = 8;
+				subgroup = group - 80;
+			}
+		} else if (200 <= group && group < 300) {
+			island = 2;
+			subgroup = group - 200;
+		} else if (600 <= group && group < 700) {
+			island = 6;
+			subgroup = 5;
+			subsubgroup = group - 650;
+		}
+	} else if (6000 <= group && group < 7000) {
+		island = 6;
+		subgroup = 5;
+		subsubgroup = group - 6500;
+	}
+
+	switch (island) {
+	case 2:
+		return pm_translate_signal_group_number_on_island2(subgroup);
+	case 3:
+		return pm_translate_signal_group_number_on_island3(subgroup);
+	case 4:
+		return pm_translate_signal_group_number_on_island4(subgroup);
+	case 5:
+		return pm_translate_signal_group_number_on_island5(subgroup);
+	case 6:
+		return pm_translate_signal_group_number_on_island6(subgroup,
+								   subsubgroup);
+	case 7:
+		return pm_translate_signal_group_number_on_island7(subgroup);
+	case 8:
+		return pm_translate_signal_group_number_on_island8(subgroup);
+	default:
+		dev_dbg(sbd_core(), "%s:%u: island not found: %lu\n", __func__,
+			__LINE__, group);
+		BUG();
+		break;
+	}
+	return 0;
+}
+
+static u64 pm_bus_word_to_ps3_lv1_bus_word(u8 word)
+{
+
+	switch (word) {
+	case 1:
+		return 0xF000;
+	case 2:
+		return 0x0F00;
+	case 4:
+		return 0x00F0;
+	case 8:
+	default:
+		return 0x000F;
+	}
+}
+
+static int __ps3_set_signal(u64 lv1_signal_group, u64 bus_select,
+			    u64 signal_select, u64 attr1, u64 attr2, u64 attr3)
+{
+	int ret;
+
+	ret = lv1_set_lpm_signal(lpm_priv->lpm_id, lv1_signal_group, bus_select,
+				 signal_select, attr1, attr2, attr3);
+	if (ret)
+		dev_err(sbd_core(),
+			"%s:%u: error:%d 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx\n",
+			__func__, __LINE__, ret, lv1_signal_group, bus_select,
+			signal_select, attr1, attr2, attr3);
+
+	return ret;
+}
+
+int ps3_set_signal(u64 signal_group, u8 signal_bit, u16 sub_unit,
+		   u8 bus_word)
+{
+	int ret;
+	u64 lv1_signal_group;
+	u64 bus_select;
+	u64 signal_select;
+	u64 attr1, attr2, attr3;
+
+	if (signal_group == 0)
+		return __ps3_set_signal(0, 0, 0, 0, 0, 0);
+
+	lv1_signal_group =
+		pm_signal_group_to_ps3_lv1_signal_group(signal_group);
+	bus_select = pm_bus_word_to_ps3_lv1_bus_word(bus_word);
+
+	switch (signal_group) {
+	case PM_SIG_GROUP_SPU_TRIGGER:
+		signal_select = 1;
+		signal_select = signal_select << (63 - signal_bit);
+		break;
+	case PM_SIG_GROUP_SPU_EVENT:
+		signal_select = 1;
+		signal_select = (signal_select << (63 - signal_bit)) | 0x3;
+		break;
+	default:
+		signal_select = 0;
+		break;
+	}
+
+	/*
+	 * 0: physical object.
+	 * 1: logical object.
+	 * This parameter is only used for the PPE and SPE signals.
+	 */
+	attr1 = 1;
+
+	/*
+	 * This parameter is used to specify the target physical/logical
+	 * PPE/SPE object.
+	 */
+	if (PM_SIG_GROUP_SPU <= signal_group &&
+		signal_group < PM_SIG_GROUP_MFC_MAX)
+		attr2 = sub_unit;
+	else
+		attr2 = lpm_priv->pu_id;
+
+	/*
+	 * This parameter is only used for setting the SPE signal.
+	 */
+	attr3 = 0;
+
+	ret = __ps3_set_signal(lv1_signal_group, bus_select, signal_select,
+			       attr1, attr2, attr3);
+	if (ret)
+		dev_err(sbd_core(), "%s:%u: __ps3_set_signal failed: %d\n",
+			__func__, __LINE__, ret);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(ps3_set_signal);
+
+u32 ps3_get_hw_thread_id(int cpu)
+{
+	return get_hard_smp_processor_id(cpu);
+}
+EXPORT_SYMBOL_GPL(ps3_get_hw_thread_id);
+
+/**
+ * ps3_enable_pm - Enable the entire performance monitoring unit.
+ *
+ * When we enable the LPM, all pending writes to counters get committed.
+ */
+
+void ps3_enable_pm(u32 cpu)
+{
+	int result;
+	u64 tmp;
+	int insert_bookmark = 0;
+
+	lpm_priv->tb_count = 0;
+
+	if (use_start_stop_bookmark) {
+		if (!(lpm_priv->shadow.pm_start_stop &
+			(PS3_PM_START_STOP_START_MASK
+			| PS3_PM_START_STOP_STOP_MASK))) {
+			result = lv1_set_lpm_trigger_control(lpm_priv->lpm_id,
+				(PS3_PM_START_STOP_PPU_TH0_BOOKMARK_START |
+				PS3_PM_START_STOP_PPU_TH1_BOOKMARK_START |
+				PS3_PM_START_STOP_PPU_TH0_BOOKMARK_STOP |
+				PS3_PM_START_STOP_PPU_TH1_BOOKMARK_STOP),
+				0xFFFFFFFFFFFFFFFFULL, &tmp);
+
+			if (result)
+				dev_err(sbd_core(), "%s:%u: "
+					"lv1_set_lpm_trigger_control failed: "
+					"%s\n", __func__, __LINE__,
+					ps3_result(result));
+
+			insert_bookmark = !result;
+		}
+	}
+
+	result = lv1_start_lpm(lpm_priv->lpm_id);
+
+	if (result)
+		dev_err(sbd_core(), "%s:%u: lv1_start_lpm failed: %s\n",
+			__func__, __LINE__, ps3_result(result));
+
+	if (use_start_stop_bookmark && !result && insert_bookmark)
+		ps3_set_bookmark(get_tb() | PS3_PM_BOOKMARK_START);
+}
+EXPORT_SYMBOL_GPL(ps3_enable_pm);
+
+/**
+ * ps3_disable_pm - Disable the entire performance monitoring unit.
+ */
+
+void ps3_disable_pm(u32 cpu)
+{
+	int result;
+	u64 tmp;
+
+	ps3_set_bookmark(get_tb() | PS3_PM_BOOKMARK_STOP);
+
+	result = lv1_stop_lpm(lpm_priv->lpm_id, &tmp);
+
+	if (result) {
+		if(result != LV1_WRONG_STATE)
+			dev_err(sbd_core(), "%s:%u: lv1_stop_lpm failed: %s\n",
+				__func__, __LINE__, ps3_result(result));
+		return;
+	}
+
+	lpm_priv->tb_count = tmp;
+
+	dev_dbg(sbd_core(), "%s:%u: tb_count %lu (%lxh)\n", __func__, __LINE__,
+		lpm_priv->tb_count, lpm_priv->tb_count);
+}
+EXPORT_SYMBOL_GPL(ps3_disable_pm);
+
+/**
+ * ps3_lpm_copy_tb - Copy data from the trace buffer to a kernel buffer.
+ * @offset: Offset in bytes from the start of the trace buffer.
+ * @buf: Copy destination.
+ * @count: Maximum count of bytes to copy.
+ * @bytes_copied: Pointer to a variable that will recieve the number of
+ *  bytes copied to @buf.
+ *
+ * On error @buf will contain any successfully copied trace buffer data
+ * and bytes_copied will be set to the number of bytes successfully copied.
+ */
+
+int ps3_lpm_copy_tb(unsigned long offset, void *buf, unsigned long count,
+		    unsigned long *bytes_copied)
+{
+	int result;
+
+	*bytes_copied = 0;
+
+	if (!lpm_priv->tb_cache)
+		return -EPERM;
+
+	if (offset >= lpm_priv->tb_count)
+		return 0;
+
+	count = min(count, lpm_priv->tb_count - offset);
+
+	while (*bytes_copied < count) {
+		const unsigned long request = count - *bytes_copied;
+		u64 tmp;
+
+		result = lv1_copy_lpm_trace_buffer(lpm_priv->lpm_id, offset,
+						   request, &tmp);
+		if (result) {
+			dev_dbg(sbd_core(), "%s:%u: 0x%lx bytes at 0x%lx\n",
+				__func__, __LINE__, request, offset);
+
+			dev_err(sbd_core(), "%s:%u: lv1_copy_lpm_trace_buffer "
+				"failed: %s\n", __func__, __LINE__,
+				ps3_result(result));
+			return result == LV1_WRONG_STATE ? -EBUSY : -EINVAL;
+		}
+
+		memcpy(buf, lpm_priv->tb_cache, tmp);
+		buf += tmp;
+		*bytes_copied += tmp;
+		offset += tmp;
+	}
+	dev_dbg(sbd_core(), "%s:%u: copied %lxh bytes\n", __func__, __LINE__,
+		*bytes_copied);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ps3_lpm_copy_tb);
+
+/**
+ * ps3_lpm_copy_tb_to_user - Copy data from the trace buffer to a user buffer.
+ * @offset: Offset in bytes from the start of the trace buffer.
+ * @buf: A __user copy destination.
+ * @count: Maximum count of bytes to copy.
+ * @bytes_copied: Pointer to a variable that will recieve the number of
+ *  bytes copied to @buf.
+ *
+ * On error @buf will contain any successfully copied trace buffer data
+ * and bytes_copied will be set to the number of bytes successfully copied.
+ */
+
+int ps3_lpm_copy_tb_to_user(unsigned long offset, void __user *buf,
+			    unsigned long count, unsigned long *bytes_copied)
+{
+	int result;
+
+	*bytes_copied = 0;
+
+	if (!lpm_priv->tb_cache)
+		return -EPERM;
+
+	if (offset >= lpm_priv->tb_count)
+		return 0;
+
+	count = min(count, lpm_priv->tb_count - offset);
+
+	while (*bytes_copied < count) {
+		const unsigned long request = count - *bytes_copied;
+		u64 tmp;
+
+		result = lv1_copy_lpm_trace_buffer(lpm_priv->lpm_id, offset,
+						   request, &tmp);
+		if (result) {
+			dev_dbg(sbd_core(), "%s:%u: 0x%lx bytes at 0x%lx\n",
+				__func__, __LINE__, request, offset);
+			dev_err(sbd_core(), "%s:%u: lv1_copy_lpm_trace_buffer "
+				"failed: %s\n", __func__, __LINE__,
+				ps3_result(result));
+			return result == LV1_WRONG_STATE ? -EBUSY : -EINVAL;
+		}
+
+		result = copy_to_user(buf, lpm_priv->tb_cache, tmp);
+
+		if (result) {
+			dev_dbg(sbd_core(), "%s:%u: 0x%lx bytes at 0x%p\n",
+				__func__, __LINE__, tmp, buf);
+			dev_err(sbd_core(), "%s:%u: copy_to_user failed: %d\n",
+				__func__, __LINE__, result);
+			return -EFAULT;
+		}
+
+		buf += tmp;
+		*bytes_copied += tmp;
+		offset += tmp;
+	}
+	dev_dbg(sbd_core(), "%s:%u: copied %lxh bytes\n", __func__, __LINE__,
+		*bytes_copied);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ps3_lpm_copy_tb_to_user);
+
+/**
+ * ps3_get_and_clear_pm_interrupts -
+ *
+ * Clearing interrupts for the entire performance monitoring unit.
+ * Reading pm_status clears the interrupt bits.
+ */
+
+u32 ps3_get_and_clear_pm_interrupts(u32 cpu)
+{
+	return ps3_read_pm(cpu, pm_status);
+}
+EXPORT_SYMBOL_GPL(ps3_get_and_clear_pm_interrupts);
+
+/**
+ * ps3_enable_pm_interrupts -
+ *
+ * Enabling interrupts for the entire performance monitoring unit.
+ * Enables the interrupt bits in the pm_status register.
+ */
+
+void ps3_enable_pm_interrupts(u32 cpu, u32 thread, u32 mask)
+{
+	if (mask)
+		ps3_write_pm(cpu, pm_status, mask);
+}
+EXPORT_SYMBOL_GPL(ps3_enable_pm_interrupts);
+
+/**
+ * ps3_enable_pm_interrupts -
+ *
+ * Disabling interrupts for the entire performance monitoring unit.
+ */
+
+void ps3_disable_pm_interrupts(u32 cpu)
+{
+	ps3_get_and_clear_pm_interrupts(cpu);
+	ps3_write_pm(cpu, pm_status, 0);
+}
+EXPORT_SYMBOL_GPL(ps3_disable_pm_interrupts);
+
+/**
+ * ps3_lpm_open - Open the logical performance monitor device.
+ * @tb_type: Specifies the type of trace buffer lv1 sould use for this lpm
+ *  instance, specified by one of enum ps3_lpm_tb_type.
+ * @tb_cache: Optional user supplied buffer to use as the trace buffer cache.
+ *  If NULL, the driver will allocate and manage an internal buffer.
+ *  Unused when when @tb_type is PS3_LPM_TB_TYPE_NONE.
+ * @tb_cache_size: The size in bytes of the user supplied @tb_cache buffer.
+ *  Unused when @tb_cache is NULL or @tb_type is PS3_LPM_TB_TYPE_NONE.
+ */
+
+int ps3_lpm_open(enum ps3_lpm_tb_type tb_type, void *tb_cache,
+	u64 tb_cache_size)
+{
+	int result;
+	u64 tb_size;
+
+	BUG_ON(!lpm_priv);
+	BUG_ON(tb_type != PS3_LPM_TB_TYPE_NONE
+		&& tb_type != PS3_LPM_TB_TYPE_INTERNAL);
+
+	if (tb_type == PS3_LPM_TB_TYPE_NONE && tb_cache)
+		dev_dbg(sbd_core(), "%s:%u: bad in vals\n", __func__, __LINE__);
+
+	if (!atomic_add_unless(&lpm_priv->open, 1, 1)) {
+		dev_dbg(sbd_core(), "%s:%u: busy\n", __func__, __LINE__);
+		return -EBUSY;
+	}
+
+	/* Note tb_cache needs 128 byte alignment. */
+
+	if (tb_type == PS3_LPM_TB_TYPE_NONE) {
+		lpm_priv->tb_cache_size = 0;
+		lpm_priv->tb_cache_internal = NULL;
+		lpm_priv->tb_cache = NULL;
+	} else if (tb_cache) {
+		if (tb_cache != (void *)_ALIGN_UP((unsigned long)tb_cache, 128)
+			|| tb_cache_size != _ALIGN_UP(tb_cache_size, 128)) {
+			dev_err(sbd_core(), "%s:%u: unaligned tb_cache\n",
+				__func__, __LINE__);
+			result = -EINVAL;
+			goto fail_align;
+		}
+		lpm_priv->tb_cache_size = tb_cache_size;
+		lpm_priv->tb_cache_internal = NULL;
+		lpm_priv->tb_cache = tb_cache;
+	} else {
+		lpm_priv->tb_cache_size = PS3_LPM_DEFAULT_TB_CACHE_SIZE;
+		lpm_priv->tb_cache_internal = kzalloc(
+			lpm_priv->tb_cache_size + 127, GFP_KERNEL);
+		if (!lpm_priv->tb_cache_internal) {
+			dev_err(sbd_core(), "%s:%u: alloc internal tb_cache "
+				"failed\n", __func__, __LINE__);
+			result = -ENOMEM;
+			goto fail_malloc;
+		}
+		lpm_priv->tb_cache = (void *)_ALIGN_UP(
+			(unsigned long)lpm_priv->tb_cache_internal, 128);
+	}
+
+	result = lv1_construct_lpm(lpm_priv->node_id, tb_type, 0, 0,
+				ps3_mm_phys_to_lpar(__pa(lpm_priv->tb_cache)),
+				lpm_priv->tb_cache_size, &lpm_priv->lpm_id,
+				&lpm_priv->outlet_id, &tb_size);
+
+	if (result) {
+		dev_err(sbd_core(), "%s:%u: lv1_construct_lpm failed: %s\n",
+			__func__, __LINE__, ps3_result(result));
+		result = -EINVAL;
+		goto fail_construct;
+	}
+
+	lpm_priv->shadow.pm_control = PS3_LPM_SHADOW_REG_INIT;
+	lpm_priv->shadow.pm_start_stop = PS3_LPM_SHADOW_REG_INIT;
+	lpm_priv->shadow.pm_interval = PS3_LPM_SHADOW_REG_INIT;
+	lpm_priv->shadow.group_control = PS3_LPM_SHADOW_REG_INIT;
+	lpm_priv->shadow.debug_bus_control = PS3_LPM_SHADOW_REG_INIT;
+
+	dev_dbg(sbd_core(), "%s:%u: lpm_id 0x%lx, outlet_id 0x%lx, "
+		"tb_size 0x%lx\n", __func__, __LINE__, lpm_priv->lpm_id,
+		lpm_priv->outlet_id, tb_size);
+
+	return 0;
+
+fail_construct:
+	kfree(lpm_priv->tb_cache_internal);
+	lpm_priv->tb_cache_internal = NULL;
+fail_malloc:
+fail_align:
+	atomic_dec(&lpm_priv->open);
+	return result;
+}
+EXPORT_SYMBOL_GPL(ps3_lpm_open);
+
+/**
+ * ps3_lpm_close - Close the lpm device.
+ *
+ */
+
+int ps3_lpm_close(void)
+{
+	dev_dbg(sbd_core(), "%s:%u\n", __func__, __LINE__);
+
+	lv1_destruct_lpm(lpm_priv->lpm_id);
+	lpm_priv->lpm_id = 0;
+
+	kfree(lpm_priv->tb_cache_internal);
+	lpm_priv->tb_cache_internal = NULL;
+
+	atomic_dec(&lpm_priv->open);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ps3_lpm_close);
+
+static int __devinit ps3_lpm_probe(struct ps3_system_bus_device *dev)
+{
+	dev_dbg(&dev->core, " -> %s:%u\n", __func__, __LINE__);
+
+	if (lpm_priv) {
+		dev_info(&dev->core, "%s:%u: called twice\n",
+			__func__, __LINE__);
+		return -EBUSY;
+	}
+
+	lpm_priv = kzalloc(sizeof(*lpm_priv), GFP_KERNEL);
+
+	if (!lpm_priv)
+		return -ENOMEM;
+
+	lpm_priv->sbd = dev;
+	lpm_priv->node_id = dev->lpm.node_id;
+	lpm_priv->pu_id = dev->lpm.pu_id;
+	lpm_priv->rights = dev->lpm.rights;
+
+	dev_info(&dev->core, " <- %s:%u:\n", __func__, __LINE__);
+
+	return 0;
+}
+
+static int ps3_lpm_remove(struct ps3_system_bus_device *dev)
+{
+	dev_dbg(&dev->core, " -> %s:%u:\n", __func__, __LINE__);
+
+	ps3_lpm_close();
+
+	kfree(lpm_priv);
+	lpm_priv = NULL;
+
+	dev_info(&dev->core, " <- %s:%u:\n", __func__, __LINE__);
+	return 0;
+}
+
+static struct ps3_system_bus_driver ps3_lpm_driver = {
+	.match_id = PS3_MATCH_ID_LPM,
+	.core.name	= "ps3-lpm",
+	.core.owner	= THIS_MODULE,
+	.probe		= ps3_lpm_probe,
+	.remove		= ps3_lpm_remove,
+	.shutdown	= ps3_lpm_remove,
+};
+
+static int __init ps3_lpm_init(void)
+{
+	pr_debug("%s:%d:\n", __func__, __LINE__);
+	return ps3_system_bus_driver_register(&ps3_lpm_driver);
+}
+
+static void __exit ps3_lpm_exit(void)
+{
+	pr_debug("%s:%d:\n", __func__, __LINE__);
+	ps3_system_bus_driver_unregister(&ps3_lpm_driver);
+}
+
+module_init(ps3_lpm_init);
+module_exit(ps3_lpm_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("PS3 Logical Performance Monitor Driver");
+MODULE_AUTHOR("Sony Corporation");
+MODULE_ALIAS(PS3_MODULE_ALIAS_LPM);
--- a/include/asm-powerpc/ps3.h
+++ b/include/asm-powerpc/ps3.h
@@ -24,6 +24,7 @@
 #include <linux/init.h>
 #include <linux/types.h>
 #include <linux/device.h>
+#include "cell-pmu.h"
 
 union ps3_firmware_version {
 	u64 raw;
@@ -446,5 +447,66 @@ struct ps3_prealloc {
 extern struct ps3_prealloc ps3fb_videomemory;
 extern struct ps3_prealloc ps3flash_bounce_buffer;
 
+/* logical performance monitor */
+
+/**
+ * enum ps3_lpm_rights - Rigths granted by the system policy module.
+ *
+ * @PS3_LPM_RIGHTS_USE_LPM: The right to use the lpm.
+ * @PS3_LPM_RIGHTS_USE_TB: The right to use the internal trace buffer.
+ */
+
+enum ps3_lpm_rights {
+	PS3_LPM_RIGHTS_USE_LPM = 0x001,
+	PS3_LPM_RIGHTS_USE_TB = 0x100,
+};
+
+/**
+ * enum ps3_lpm_tb_type - Type of trace buffer lv1 should use.
+ *
+ * @PS3_LPM_TB_TYPE_NONE: Do not use a trace buffer.
+ * @PS3_LPM_RIGHTS_USE_TB: Use the lv1 internal trace buffer.  Must have
+ *  rights @PS3_LPM_RIGHTS_USE_TB.
+ */
+
+enum ps3_lpm_tb_type {
+	PS3_LPM_TB_TYPE_NONE = 0,
+	PS3_LPM_TB_TYPE_INTERNAL = 1,
+};
+
+int ps3_lpm_open(enum ps3_lpm_tb_type tb_type, void *tb_cache,
+	u64 tb_cache_size);
+int ps3_lpm_close(void);
+int ps3_lpm_copy_tb(unsigned long offset, void *buf, unsigned long count,
+	unsigned long *bytes_copied);
+int ps3_lpm_copy_tb_to_user(unsigned long offset, void __user *buf,
+	unsigned long count, unsigned long *bytes_copied);
+void ps3_set_bookmark(u64 bookmark);
+void ps3_set_pm_bookmark(u64 tag, u64 incident, u64 th_id);
+int ps3_set_signal(u64 rtas_signal_group, u8 signal_bit, u16 sub_unit,
+	u8 bus_word);
+
+u32 ps3_read_phys_ctr(u32 cpu, u32 phys_ctr);
+void ps3_write_phys_ctr(u32 cpu, u32 phys_ctr, u32 val);
+u32 ps3_read_ctr(u32 cpu, u32 ctr);
+void ps3_write_ctr(u32 cpu, u32 ctr, u32 val);
+
+u32 ps3_read_pm07_control(u32 cpu, u32 ctr);
+void ps3_write_pm07_control(u32 cpu, u32 ctr, u32 val);
+u32 ps3_read_pm(u32 cpu, enum pm_reg_name reg);
+void ps3_write_pm(u32 cpu, enum pm_reg_name reg, u32 val);
+
+u32 ps3_get_ctr_size(u32 cpu, u32 phys_ctr);
+void ps3_set_ctr_size(u32 cpu, u32 phys_ctr, u32 ctr_size);
+
+void ps3_enable_pm(u32 cpu);
+void ps3_disable_pm(u32 cpu);
+void ps3_enable_pm_interrupts(u32 cpu, u32 thread, u32 mask);
+void ps3_disable_pm_interrupts(u32 cpu);
+
+u32 ps3_get_and_clear_pm_interrupts(u32 cpu);
+void ps3_sync_irq(int node);
+u32 ps3_get_hw_thread_id(int cpu);
+u64 ps3_get_spe_id(void *arg);
 
 #endif

^ permalink raw reply

* Re: [PATCH V3] [POWERPC] Add common clock setting routine mpc52xx_psc_set_clkdiv()
From: Stephen Rothwell @ 2008-01-10 23:41 UTC (permalink / raw)
  To: Grant Likely; +Cc: linuxppc-dev, dragos.carp
In-Reply-To: <fa686aa40801100701q7454d8d0o8542ce9cc10f3bfb@mail.gmail.com>

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

On Thu, 10 Jan 2008 08:01:09 -0700 "Grant Likely" <grant.likely@secretlab.ca> wrote:
>
> On 1/10/08, Stephen Rothwell <sfr@canb.auug.org.au> wrote:
> > Hi Grant,
> >
> > On Wed, 09 Jan 2008 22:26:30 -0700 Grant Likely <grant.likely@secretlab.ca> wrote:
> > >
> > > +mpc52xx_map_common_devices(void)
> > >  {
> >
> > > +     /* Clock Distribution Module, used by PSC clock setting function */
> > > +     np = of_find_matching_node(NULL, mpc52xx_cdm_ids);
> >
> > What happens if we find no node?
> 
> Both of_iomap and of_put fail gracefully if np is NULL.  IIRC that was
> done on purpose so this exact thing could be done.
> 
> Users of mpc52xx_cdm (and the others done in this style) all check for
> mpc52xx_cdm being NULL before dereferencing.

Excellent, thanks.

-- 
Cheers,
Stephen Rothwell                    sfr@canb.auug.org.au
http://www.canb.auug.org.au/~sfr/

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply

* Re: [PATCH v3] [POWERPC] Update MPC8610 HPCD to support audio drivers
From: Scott Wood @ 2008-01-10 23:00 UTC (permalink / raw)
  To: Grant Likely; +Cc: olof, linuxppc-dev, alsa-devel, Timur Tabi, david
In-Reply-To: <fa686aa40801101452q608907f3rf6f98a5d091d09d9@mail.gmail.com>

Grant Likely wrote:
>> +                dma@21300 {
>> +                        #address-cells = <1>;
>> +                        #size-cells = <1>;
>> +                        compatible = "fsl,mpc8610-dma", "fsl,eloplus-dma";
>> +                        cell-index = <0>;
>> +                        reg = <21300 4>; /* DMA general status register */
>> +                        ranges = <0 21100 200>;
>> +
>> +                        dma-channel@0 {
>> +                               compatible = "fsl,mpc8610-dma-channel",
>> +                                       "fsl,eloplus-dma-channel";
> 
> Nit: you probably don't need the compatible property for these channel
> nodes since they are 100% dependent on the parent for describing the
> behaviour.

The compatible property in the child nodes gives the driver the option 
of matching the channel rather than the whole thing.

-Scott

^ permalink raw reply

* RE: Help with device tree binding for SMC serial
From: Rune Torgersen @ 2008-01-11  0:07 UTC (permalink / raw)
  To: Scott Wood; +Cc: linuxppc-dev
In-Reply-To: <47866FDE.5070307@freescale.com>

> From: Scott Wood [
> Rune Torgersen wrote:
> > Not sure what was wrong. We took a step back, and redid=20
> some stuff, and
> > now we have serial output from the boot-wrapper.
> > THe checkstop came from the wrapper grying to access the=20
> bcsr and doing
> > the chip select fixup. We don';t have a bcsr on our board,=20
> and the cs
> > layout is different.
>=20
> There's no bcsr access in the upstream bootwrapper (the=20
> mention of bcsr=20
> in cuboot-pq2.c is just one reason why some boards require us=20
> to do the=20
> CS programming), and the CS programming is chip-level, not=20
> board-level=20
> (it just requires that the device tree have a correct=20
> localbus node for=20
> the board).

Finally got it (sort-of) working.
Turned out that for some reason the console init is setting the baudrate
to 9600
the options string passed in to the console init fuunction is NULL.

Any idea oon how this should be passed in from u-boot?

^ permalink raw reply

* Re: [alsa-devel] [PATCH v2] [ALSA] Add ASoC drivers for the Freescale MPC8610 SoC
From: Olof Johansson @ 2008-01-11  0:24 UTC (permalink / raw)
  To: Timur Tabi; +Cc: linuxppc-dev, alsa-devel, david
In-Reply-To: <4786A650.2080107@freescale.com>

On Thu, Jan 10, 2008 at 05:12:16PM -0600, Timur Tabi wrote:
> Grant Likely wrote:
> 
> > Does the driver access the DMA and GUTS registers directly?  If so,
> > what do you have to protect against race conditions of other drivers
> > accessing them also.
> 
> I don't have any more protection than any other driver that accesses SOC 
> registers directly.  Last I heard, Zhang's DMA driver was in limbo, and that 
> driver would be the best place to arbitrate DMA register access.  I was planning 
> on adding arbitration support to that driver after both drivers were applied.

Having been in a similar situation myself (needing to share resources
between DMA, ethernet and function offload), I recommend creating a
separate small library that all those drivers use, instead of making
some sort of dependency between drivers in completely different parts
of the kernel.


-Olof

^ permalink raw reply

* Re: [PATCH 2/5] Warp Base Platform - dts
From: David Gibson @ 2008-01-11  0:20 UTC (permalink / raw)
  To: Sean MacLennan; +Cc: linuxppc-dev
In-Reply-To: <4786B147.5070206@pikatech.com>

On Thu, Jan 10, 2008 at 06:59:03PM -0500, Sean MacLennan wrote:
> New version with recommended changes. Device types removed. FPGA
> moved to correct bus.

[snip]
> +				fpga@2,0 {
> +					compatible = "pika,fpga";
> +			   		reg = <0 80000000 2200>;

Your reg property doesn't match your node name here...

> +					interrupts = <18 8>;
> +					interrupt-parent = <&UIC0>;
> +				};

-- 
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

* [PATCH] Fix CPU hotplug when using the SLB shadow buffer
From: Michael Neuling @ 2008-01-11  0:47 UTC (permalink / raw)
  To: paulus; +Cc: linuxppc-dev, Nathan Lynch
In-Reply-To: <26792.1199949114@neuling.org>

Before we register the SLB shadow buffer, we need to invalidate the
entries in the buffer otherwise we can end up stale entries from when we
offlined the CPU.

This patch does this invalidate as well as unregistering the buffer with
PHYP before we offline the cpu.  Tested and fixes crashes seen on 970MP
(thanks to tonyb) and POWER5.

Signed-off-by: Michael Neuling <mikey@neuling.org>
---
Updates for offline comments from paulus

 arch/powerpc/mm/slb.c                        |    8 ++++++++
 arch/powerpc/platforms/pseries/hotplug-cpu.c |    2 ++
 arch/powerpc/platforms/pseries/lpar.c        |    1 +
 include/asm-powerpc/mmu-hash64.h             |    1 +
 4 files changed, 12 insertions(+)

Index: linux-2.6-ozlabs/arch/powerpc/mm/slb.c
===================================================================
--- linux-2.6-ozlabs.orig/arch/powerpc/mm/slb.c
+++ linux-2.6-ozlabs/arch/powerpc/mm/slb.c
@@ -82,6 +82,14 @@ static inline void slb_shadow_clear(unsi
 	get_slb_shadow()->save_area[entry].esid = 0;
 }
 
+void slb_shadow_clear_all(void)
+{
+	int i;
+
+	for (i = 0; i < SLB_NUM_BOLTED; i++)
+		slb_shadow_clear(i);
+}
+
 static inline void create_shadowed_slbe(unsigned long ea, int ssize,
 					unsigned long flags,
 					unsigned long entry)
Index: linux-2.6-ozlabs/arch/powerpc/platforms/pseries/hotplug-cpu.c
===================================================================
--- linux-2.6-ozlabs.orig/arch/powerpc/platforms/pseries/hotplug-cpu.c
+++ linux-2.6-ozlabs/arch/powerpc/platforms/pseries/hotplug-cpu.c
@@ -29,6 +29,7 @@
 #include <asm/vdso_datapage.h>
 #include <asm/pSeries_reconfig.h>
 #include "xics.h"
+#include "plpar_wrappers.h"
 
 /* This version can't take the spinlock, because it never returns */
 static struct rtas_args rtas_stop_self_args = {
@@ -58,6 +59,7 @@ static void pseries_mach_cpu_die(void)
 	local_irq_disable();
 	idle_task_exit();
 	xics_teardown_cpu(0);
+	unregister_slb_shadow(smp_processor_id(), __pa(get_slb_shadow()));
 	rtas_stop_self();
 	/* Should never get here... */
 	BUG();
Index: linux-2.6-ozlabs/arch/powerpc/platforms/pseries/lpar.c
===================================================================
--- linux-2.6-ozlabs.orig/arch/powerpc/platforms/pseries/lpar.c
+++ linux-2.6-ozlabs/arch/powerpc/platforms/pseries/lpar.c
@@ -272,6 +272,7 @@ void vpa_init(int cpu)
 	 */
 	addr = __pa(&slb_shadow[cpu]);
 	if (firmware_has_feature(FW_FEATURE_SPLPAR)) {
+		slb_shadow_clear_all();
 		ret = register_slb_shadow(hwcpu, addr);
 		if (ret)
 			printk(KERN_ERR
Index: linux-2.6-ozlabs/include/asm-powerpc/mmu-hash64.h
===================================================================
--- linux-2.6-ozlabs.orig/include/asm-powerpc/mmu-hash64.h
+++ linux-2.6-ozlabs/include/asm-powerpc/mmu-hash64.h
@@ -286,6 +286,7 @@ extern void hpte_init_iSeries(void);
 extern void hpte_init_beat(void);
 extern void hpte_init_beat_v3(void);
 
+extern void slb_shadow_clear_all(void);
 extern void stabs_alloc(void);
 extern void slb_initialize(void);
 extern void slb_flush_and_rebolt(void);

^ permalink raw reply

* Re: [PATCH] Fix CPU hotplug when using the SLB shadow buffer
From: Nathan Lynch @ 2008-01-11  1:12 UTC (permalink / raw)
  To: Michael Neuling; +Cc: linuxppc-dev, paulus
In-Reply-To: <28640.1200012427@neuling.org>

Michael Neuling wrote:
> @@ -58,6 +59,7 @@ static void pseries_mach_cpu_die(void)
>  	local_irq_disable();
>  	idle_task_exit();
>  	xics_teardown_cpu(0);
> +	unregister_slb_shadow(smp_processor_id(), __pa(get_slb_shadow()));
                                     ^
Should that not be hard_smp_processor_id()?

(sorry for not commenting earlier)

^ permalink raw reply

* Re: [PATCH 1/8] pseries: phyp dump: Docmentation
From: Nathan Lynch @ 2008-01-11  1:26 UTC (permalink / raw)
  To: Mike Strosaker
  Cc: linuxppc-dev, lkessler, mahuja, Olof Johansson, linasvepstas,
	strosake
In-Reply-To: <4786923E.9090902@austin.ibm.com>

Mike Strosaker wrote:
> 
> At the risk of repeating what others have already said, the PHYP-assistance 
> method provides some advantages that the kexec method cannot:
>  - Availability of the system for production use before the dump data is 
> collected.  As was mentioned before, some production systems may choose not 
> to operate with the limited memory initially available after the reboot, 
> but it sure is nice to provide the option.

I'm more concerned that this design encourages the user to resume a
workload *which is almost certainly known to result in a system crash*
before collection of crash data is complete.  Maybe the gamble will
pay off most of the time, but I wouldn't want to be working support
when it doesn't.

^ permalink raw reply

* Re: [PATCH] Fix CPU hotplug when using the SLB shadow buffer
From: Michael Neuling @ 2008-01-11  2:59 UTC (permalink / raw)
  To: Nathan Lynch; +Cc: linuxppc-dev, paulus
In-Reply-To: <20080111011221.GW14201@localdomain>

> > @@ -58,6 +59,7 @@ static void pseries_mach_cpu_die(void)
> >  	local_irq_disable();
> >  	idle_task_exit();
> >  	xics_teardown_cpu(0);
> > +	unregister_slb_shadow(smp_processor_id(), __pa(get_slb_shadow()));
>                                      ^
> Should that not be hard_smp_processor_id()?

Thanks.. I think you're right since we register each CPU with a
get_hard_smp_processor_id(cpu).  

I'll update.

Mikey

^ permalink raw reply

* [PATCH] Fix CPU hotplug when using the SLB shadow buffer
From: Michael Neuling @ 2008-01-11  3:02 UTC (permalink / raw)
  To: paulus; +Cc: linuxppc-dev, Nathan Lynch
In-Reply-To: <20080111011221.GW14201@localdomain>

Before we register the SLB shadow buffer, we need to invalidate the
entries in the buffer otherwise we can end up stale entries from when we
offlined the CPU.

This patch does this invalidate as well as unregistering the buffer with
PHYP before we offline the cpu.  Tested and fixes crashes seen on 970MP
(thanks to tonyb) and POWER5.

Signed-off-by: Michael Neuling <mikey@neuling.org>
---
Updated based on comment from ntl

 arch/powerpc/mm/slb.c                        |    8 ++++++++
 arch/powerpc/platforms/pseries/hotplug-cpu.c |    2 ++
 arch/powerpc/platforms/pseries/lpar.c        |    1 +
 include/asm-powerpc/mmu-hash64.h             |    1 +
 4 files changed, 12 insertions(+)

Index: linux-2.6-ozlabs/arch/powerpc/mm/slb.c
===================================================================
--- linux-2.6-ozlabs.orig/arch/powerpc/mm/slb.c
+++ linux-2.6-ozlabs/arch/powerpc/mm/slb.c
@@ -82,6 +82,14 @@ static inline void slb_shadow_clear(unsi
 	get_slb_shadow()->save_area[entry].esid = 0;
 }
 
+void slb_shadow_clear_all(void)
+{
+	int i;
+
+	for (i = 0; i < SLB_NUM_BOLTED; i++)
+		slb_shadow_clear(i);
+}
+
 static inline void create_shadowed_slbe(unsigned long ea, int ssize,
 					unsigned long flags,
 					unsigned long entry)
Index: linux-2.6-ozlabs/arch/powerpc/platforms/pseries/hotplug-cpu.c
===================================================================
--- linux-2.6-ozlabs.orig/arch/powerpc/platforms/pseries/hotplug-cpu.c
+++ linux-2.6-ozlabs/arch/powerpc/platforms/pseries/hotplug-cpu.c
@@ -29,6 +29,7 @@
 #include <asm/vdso_datapage.h>
 #include <asm/pSeries_reconfig.h>
 #include "xics.h"
+#include "plpar_wrappers.h"
 
 /* This version can't take the spinlock, because it never returns */
 static struct rtas_args rtas_stop_self_args = {
@@ -58,6 +59,7 @@ static void pseries_mach_cpu_die(void)
 	local_irq_disable();
 	idle_task_exit();
 	xics_teardown_cpu(0);
+	unregister_slb_shadow(hard_smp_processor_id(), __pa(get_slb_shadow()));
 	rtas_stop_self();
 	/* Should never get here... */
 	BUG();
Index: linux-2.6-ozlabs/arch/powerpc/platforms/pseries/lpar.c
===================================================================
--- linux-2.6-ozlabs.orig/arch/powerpc/platforms/pseries/lpar.c
+++ linux-2.6-ozlabs/arch/powerpc/platforms/pseries/lpar.c
@@ -272,6 +272,7 @@ void vpa_init(int cpu)
 	 */
 	addr = __pa(&slb_shadow[cpu]);
 	if (firmware_has_feature(FW_FEATURE_SPLPAR)) {
+		slb_shadow_clear_all();
 		ret = register_slb_shadow(hwcpu, addr);
 		if (ret)
 			printk(KERN_ERR
Index: linux-2.6-ozlabs/include/asm-powerpc/mmu-hash64.h
===================================================================
--- linux-2.6-ozlabs.orig/include/asm-powerpc/mmu-hash64.h
+++ linux-2.6-ozlabs/include/asm-powerpc/mmu-hash64.h
@@ -286,6 +286,7 @@ extern void hpte_init_iSeries(void);
 extern void hpte_init_beat(void);
 extern void hpte_init_beat_v3(void);
 
+extern void slb_shadow_clear_all(void);
 extern void stabs_alloc(void);
 extern void slb_initialize(void);
 extern void slb_flush_and_rebolt(void);

^ permalink raw reply

* Enable RTC for Ebony and Walnut (v2)
From: David Gibson @ 2008-01-11  3:25 UTC (permalink / raw)
  To: Josh Boyer, Paul Mackerras; +Cc: linuxppc-dev
In-Reply-To: <20071221022130.GI2665@localhost.localdomain>

This patch extends the Ebony and Walnut platform code to instantiate
the existing ds1742 RTC class driver for the DS1743 RTC/NVRAM chip
found on both those boards.  The patch uses a helper function to scan
the device tree and instantiate the appropriate platform_device based
on it, so it should be easy to extend for other boards which have mmio
mapped RTC chips.

Along with this, the device tree binding for the ds1743 chips is
tweaked, based on the existing DS1385 OF binding found at:
	http://playground.sun.com/1275/proposals/Closed/Remanded/Accepted/346-it.txt
Although that document covers the NVRAM portion of the chip, whereas
here we're interested in the RTC portion, so it's not entirely clear
if that's a good model.

This implements only RTC class driver support - that is /dev/rtc0, not
/dev/rtc, and the low-level get/set time callbacks remain
unimplemented.  That means in order to get at the clock you will
either need a modified version of hwclock which will look at
/dev/rtc0, or you'll need to configure udev to symlink rtc0 to rtc.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---

Updated for kernel changes and feedback.

Index: working-2.6/arch/powerpc/boot/dts/ebony.dts
===================================================================
--- working-2.6.orig/arch/powerpc/boot/dts/ebony.dts	2008-01-11 11:45:27.000000000 +1100
+++ working-2.6/arch/powerpc/boot/dts/ebony.dts	2008-01-11 14:17:03.000000000 +1100
@@ -158,9 +158,10 @@
 					};
 				};
 
-				ds1743@1,0 {
+				nvram@1,0 {
 					/* NVRAM & RTC */
-					compatible = "ds1743";
+					compatible = "ds1743-nvram";
+					#bytes = <2000>;
 					reg = <1 0 2000>;
 				};
 
Index: working-2.6/arch/powerpc/platforms/44x/ebony.c
===================================================================
--- working-2.6.orig/arch/powerpc/platforms/44x/ebony.c	2008-01-11 11:45:27.000000000 +1100
+++ working-2.6/arch/powerpc/platforms/44x/ebony.c	2008-01-11 14:17:03.000000000 +1100
@@ -18,6 +18,7 @@
 
 #include <linux/init.h>
 #include <linux/of_platform.h>
+#include <linux/rtc.h>
 
 #include <asm/machdep.h>
 #include <asm/prom.h>
@@ -38,6 +39,7 @@ static __initdata struct of_device_id eb
 static int __init ebony_device_probe(void)
 {
 	of_platform_bus_probe(NULL, ebony_of_bus, NULL);
+	of_instantiate_rtc();
 
 	return 0;
 }
Index: working-2.6/arch/powerpc/platforms/Kconfig
===================================================================
--- working-2.6.orig/arch/powerpc/platforms/Kconfig	2007-12-10 10:52:44.000000000 +1100
+++ working-2.6/arch/powerpc/platforms/Kconfig	2008-01-11 14:17:03.000000000 +1100
@@ -315,6 +315,12 @@ config FSL_ULI1575
 config CPM
 	bool
 
+config OF_RTC
+	bool
+	help
+	  Uses information from the OF or flattened device tree to instatiate
+	  platform devices for direct mapped RTC chips like the DS1742 or DS1743.
+
 source "arch/powerpc/sysdev/bestcomm/Kconfig"
 
 endmenu
Index: working-2.6/arch/powerpc/sysdev/Makefile
===================================================================
--- working-2.6.orig/arch/powerpc/sysdev/Makefile	2008-01-11 11:45:27.000000000 +1100
+++ working-2.6/arch/powerpc/sysdev/Makefile	2008-01-11 14:17:03.000000000 +1100
@@ -27,6 +27,7 @@ obj-$(CONFIG_PPC_I8259)		+= i8259.o
 obj-$(CONFIG_PPC_83xx)		+= ipic.o
 obj-$(CONFIG_4xx)		+= uic.o
 obj-$(CONFIG_XILINX_VIRTEX)	+= xilinx_intc.o
+obj-$(CONFIG_OF_RTC)		+= of_rtc.o
 ifeq ($(CONFIG_PCI),y)
 obj-$(CONFIG_4xx)		+= ppc4xx_pci.o
 endif
Index: working-2.6/arch/powerpc/sysdev/of_rtc.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ working-2.6/arch/powerpc/sysdev/of_rtc.c	2008-01-11 14:17:03.000000000 +1100
@@ -0,0 +1,59 @@
+/*
+ * Instantiate mmio-mapped RTC chips based on device tree information
+ *
+ * Copyright 2007 David Gibson <dwg@au1.ibm.com>, IBM Corporation.
+ *
+ * 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 of the  License, or (at your
+ * option) any later version.
+ */
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/init.h>
+#include <linux/of_platform.h>
+
+static __initdata struct {
+	const char *compatible;
+	char *plat_name;
+} of_rtc_table[] = {
+	{ "ds1743-nvram", "rtc-ds1742" },
+};
+
+void __init of_instantiate_rtc(void)
+{
+	struct device_node *node;
+	int err;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(of_rtc_table); i++) {
+		char *plat_name = of_rtc_table[i].plat_name;
+
+		for_each_compatible_node(node, NULL,
+					 of_rtc_table[i].compatible) {
+			struct resource *res;
+
+			res = kmalloc(sizeof(*res), GFP_KERNEL);
+			if (!res) {
+				printk(KERN_ERR "OF RTC: Out of memory "
+				       "allocating resource structure for %s\n",
+				       node->full_name);
+				continue;
+			}
+
+			err = of_address_to_resource(node, 0, res);
+			if (err) {
+				printk(KERN_ERR "OF RTC: Error "
+				       "translating resources for %s\n",
+				       node->full_name);
+				continue;
+			}
+
+			printk(KERN_INFO "OF_RTC: %s is a %s @ 0x%llx-0x%llx\n",
+			       node->full_name, plat_name,
+			       (unsigned long long)res->start,
+			       (unsigned long long)res->end);
+			platform_device_register_simple(plat_name, -1, res, 1);
+		}
+	}
+}
Index: working-2.6/arch/powerpc/platforms/44x/Kconfig
===================================================================
--- working-2.6.orig/arch/powerpc/platforms/44x/Kconfig	2008-01-11 11:45:27.000000000 +1100
+++ working-2.6/arch/powerpc/platforms/44x/Kconfig	2008-01-11 14:17:03.000000000 +1100
@@ -13,6 +13,7 @@ config EBONY
 	default y
 	select 440GP
 	select PCI
+	select OF_RTC
 	help
 	  This option enables support for the IBM PPC440GP evaluation board.
 
Index: working-2.6/include/asm-powerpc/of_platform.h
===================================================================
--- working-2.6.orig/include/asm-powerpc/of_platform.h	2008-01-11 11:45:29.000000000 +1100
+++ working-2.6/include/asm-powerpc/of_platform.h	2008-01-11 14:17:03.000000000 +1100
@@ -37,4 +37,6 @@ extern int of_platform_bus_probe(struct 
 
 extern struct of_device *of_find_device_by_phandle(phandle ph);
 
+extern void of_instantiate_rtc(void);
+
 #endif	/* _ASM_POWERPC_OF_PLATFORM_H */
Index: working-2.6/arch/powerpc/boot/dts/walnut.dts
===================================================================
--- working-2.6.orig/arch/powerpc/boot/dts/walnut.dts	2008-01-11 11:45:27.000000000 +1100
+++ working-2.6/arch/powerpc/boot/dts/walnut.dts	2008-01-11 14:17:03.000000000 +1100
@@ -175,9 +175,10 @@
 				};
 			};
 
-			ds1743@1,0 {
+			nvram@1,0 {
 				/* NVRAM and RTC */
-				compatible = "ds1743";
+				compatible = "ds1743-nvram";
+				#bytes = <2000>;
 				reg = <1 0 2000>;
 			};
 
Index: working-2.6/arch/powerpc/platforms/40x/walnut.c
===================================================================
--- working-2.6.orig/arch/powerpc/platforms/40x/walnut.c	2008-01-11 11:45:27.000000000 +1100
+++ working-2.6/arch/powerpc/platforms/40x/walnut.c	2008-01-11 14:17:03.000000000 +1100
@@ -36,6 +36,7 @@ static __initdata struct of_device_id wa
 static int __init walnut_device_probe(void)
 {
 	of_platform_bus_probe(NULL, walnut_of_bus, NULL);
+	of_instantiate_rtc();
 
 	return 0;
 }

-- 
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

* libfdt: Add fdt_set_name() function
From: David Gibson @ 2008-01-11  3:55 UTC (permalink / raw)
  To: Jon Loeliger; +Cc: linuxppc-dev

This patch adds an fdt_set_name() function to libfdt, mirroring
fdt_get_name().  This is a r/w function which alters the name of a
given device tree node.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>

Index: dtc/libfdt/libfdt.h
===================================================================
--- dtc.orig/libfdt/libfdt.h	2007-12-19 10:52:12.000000000 +1100
+++ dtc/libfdt/libfdt.h	2008-01-11 14:53:27.000000000 +1100
@@ -846,6 +846,32 @@ int fdt_add_mem_rsv(void *fdt, uint64_t 
 int fdt_del_mem_rsv(void *fdt, int n);
 
 /**
+ * fdt_set_name - change the name of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: structure block offset of a node
+ * @name: name to give the node
+ *
+ * fdt_set_name() replaces the name (including unit address, if any)
+ * of the given node with the given string.  NOTE: this function can't
+ * efficiently check if the new name is unique amongst the given
+ * node's siblings; results are undefined if this function is invoked
+ * with a name equal to one of the given node's siblings.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob
+ *		to contain the new name
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE, standard meanings
+ */
+int fdt_set_name(void *fdt, int nodeoffset, const char *name);
+
+/**
  * fdt_setprop - create or change a property
  * @fdt: pointer to the device tree blob
  * @nodeoffset: offset of the node whose property to change
Index: dtc/libfdt/fdt_rw.c
===================================================================
--- dtc.orig/libfdt/fdt_rw.c	2007-12-19 10:52:12.000000000 +1100
+++ dtc/libfdt/fdt_rw.c	2008-01-11 14:45:27.000000000 +1100
@@ -252,6 +252,30 @@ static int _add_property(void *fdt, int 
 	return 0;
 }
 
+int fdt_set_name(void *fdt, int nodeoffset, const char *name)
+{
+	char *namep;
+	int oldlen, newlen;
+	int err;
+
+	if ((err = rw_check_header(fdt)))
+		return err;
+
+	namep = (char *)fdt_get_name(fdt, nodeoffset, &oldlen);
+	if (!namep)
+		return oldlen;
+
+	newlen = strlen(name);
+
+	err = _blob_splice_struct(fdt, namep, ALIGN(oldlen+1, FDT_TAGSIZE),
+				  ALIGN(newlen+1, FDT_TAGSIZE));
+	if (err)
+		return err;
+
+	memcpy(namep, name, newlen+1);
+	return 0;
+}
+
 int fdt_setprop(void *fdt, int nodeoffset, const char *name,
 		const void *val, int len)
 {
Index: dtc/tests/Makefile.tests
===================================================================
--- dtc.orig/tests/Makefile.tests	2007-12-19 16:50:09.000000000 +1100
+++ dtc/tests/Makefile.tests	2008-01-11 14:34:11.000000000 +1100
@@ -8,7 +8,7 @@ LIB_TESTS_L = get_mem_rsv \
 	setprop_inplace nop_property nop_node \
 	sw_tree1 \
 	move_and_save mangle-layout \
-	open_pack rw_tree1 setprop del_property del_node \
+	open_pack rw_tree1 set_name setprop del_property del_node \
 	string_escapes references path-references \
 	dtbs_equal_ordered
 LIB_TESTS = $(LIB_TESTS_L:%=$(TESTS_PREFIX)%)
Index: dtc/tests/set_name.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ dtc/tests/set_name.c	2008-01-11 14:52:17.000000000 +1100
@@ -0,0 +1,91 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ *	Testcase for fdt_set_name()
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#include "tests.h"
+#include "testdata.h"
+
+void check_set_name(void *fdt, const char *path, const char *newname)
+{
+	int offset;
+	const char *getname, *oldname;
+	int len, err;
+
+	oldname = strrchr(path, '/');
+	if (!oldname)
+		TEST_BUG();
+	oldname += 1;
+
+	offset = fdt_path_offset(fdt, path);
+	if (offset < 0)
+		FAIL("Couldn't find %s", path);
+
+	getname = fdt_get_name(fdt, offset, &len);
+	verbose_printf("fdt_get_name(%d) returns \"%s\" (len=%d)\n",
+		       offset, getname, len);
+	if (!getname)
+		FAIL("fdt_get_name(%d): %s", offset, fdt_strerror(len));
+
+	if (strcmp(getname, oldname) != 0)
+		FAIL("fdt_get_name(%s) returned \"%s\" instead of \"%s\"",
+		     path, getname, oldname);
+
+	if (len != strlen(getname))
+		FAIL("fdt_get_name(%s) returned length %d instead of %zd",
+		     path, len, strlen(getname));
+
+	err = fdt_set_name(fdt, offset, newname);
+	if (err)
+		FAIL("fdt_set_name(%d, \"%s\"): %s", offset, newname,
+		     fdt_strerror(err));
+
+	getname = fdt_get_name(fdt, offset, &len);
+	if (!getname)
+		FAIL("fdt_get_name(%d): %s", offset, fdt_strerror(len));
+
+	if (strcmp(getname, newname) != 0)
+		FAIL("fdt_get_name(%s) returned \"%s\" instead of \"%s\"",
+		     path, getname, newname);
+
+	if (len != strlen(getname))
+		FAIL("fdt_get_name(%s) returned length %d instead of %zd",
+		     path, len, strlen(getname));
+}
+
+int main(int argc, char *argv[])
+{
+	void *fdt;
+
+	test_init(argc, argv);
+	fdt = load_blob_arg(argc, argv);
+	fdt = open_blob_rw(fdt);
+
+	check_set_name(fdt, "/subnode@1", "subnode@17");
+	check_set_name(fdt, "/subnode@2/subsubnode@0", "fred@0");
+	check_set_name(fdt, "/subnode@17/subsubnode", "something@0");
+
+	PASS();
+}
Index: dtc/tests/run_tests.sh
===================================================================
--- dtc.orig/tests/run_tests.sh	2008-01-11 14:43:28.000000000 +1100
+++ dtc/tests/run_tests.sh	2008-01-11 14:43:35.000000000 +1100
@@ -69,6 +69,7 @@ tree1_tests_rw () {
     TREE=$1
 
     # Read-write tests
+    run_test set_name $TREE
     run_test setprop $TREE
     run_test del_property $TREE
     run_test del_node $TREE

-- 
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

* [PATCH] ps3: vuart: semaphore to mutex
From: Daniel Walker @ 2008-01-11  4:21 UTC (permalink / raw)
  To: geoffrey.levand; +Cc: linuxppc-dev, mingo

This probe_mutex conforms to the new struct mutex type.
This patch converts it from the old semaphore to the new struct mutex.

Signed-off-by: Daniel Walker <dwalker@mvista.com>

---
 drivers/ps3/ps3-vuart.c |   23 ++++++++++++-----------
 1 file changed, 12 insertions(+), 11 deletions(-)

Index: linux-2.6.23/drivers/ps3/ps3-vuart.c
===================================================================
--- linux-2.6.23.orig/drivers/ps3/ps3-vuart.c
+++ linux-2.6.23/drivers/ps3/ps3-vuart.c
@@ -23,6 +23,7 @@
 #include <linux/interrupt.h>
 #include <linux/workqueue.h>
 #include <linux/bitops.h>
+#include <linux/mutex.h>
 #include <asm/ps3.h>
 
 #include <asm/firmware.h>
@@ -877,7 +878,7 @@ static int ps3_vuart_handle_port_interru
 struct vuart_bus_priv {
 	struct ports_bmp *bmp;
 	unsigned int virq;
-	struct semaphore probe_mutex;
+	struct mutex probe_mutex;
 	int use_count;
 	struct ps3_system_bus_device *devices[PORT_COUNT];
 } static vuart_bus_priv;
@@ -1015,7 +1016,7 @@ static int ps3_vuart_probe(struct ps3_sy
 		return -EINVAL;
 	}
 
-	down(&vuart_bus_priv.probe_mutex);
+	mutex_lock(&vuart_bus_priv.probe_mutex);
 
 	result = ps3_vuart_bus_interrupt_get();
 
@@ -1075,7 +1076,7 @@ static int ps3_vuart_probe(struct ps3_sy
 		goto fail_probe;
 	}
 
-	up(&vuart_bus_priv.probe_mutex);
+	mutex_unlock(&vuart_bus_priv.probe_mutex);
 
 	return result;
 
@@ -1088,7 +1089,7 @@ fail_dev_malloc:
 fail_busy:
 	ps3_vuart_bus_interrupt_put();
 fail_setup_interrupt:
-	up(&vuart_bus_priv.probe_mutex);
+	mutex_unlock(&vuart_bus_priv.probe_mutex);
 	dev_dbg(&dev->core, "%s:%d: failed\n", __func__, __LINE__);
 	return result;
 }
@@ -1127,7 +1128,7 @@ static int ps3_vuart_remove(struct ps3_s
 
 	BUG_ON(!dev);
 
-	down(&vuart_bus_priv.probe_mutex);
+	mutex_lock(&vuart_bus_priv.probe_mutex);
 
 	dev_dbg(&dev->core, " -> %s:%d: match_id %d\n", __func__, __LINE__,
 		dev->match_id);
@@ -1135,7 +1136,7 @@ static int ps3_vuart_remove(struct ps3_s
 	if (!dev->core.driver) {
 		dev_dbg(&dev->core, "%s:%d: no driver bound\n", __func__,
 			__LINE__);
-		up(&vuart_bus_priv.probe_mutex);
+		mutex_unlock(&vuart_bus_priv.probe_mutex);
 		return 0;
 	}
 
@@ -1158,7 +1159,7 @@ static int ps3_vuart_remove(struct ps3_s
 	priv = NULL;
 
 	dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__);
-	up(&vuart_bus_priv.probe_mutex);
+	mutex_unlock(&vuart_bus_priv.probe_mutex);
 	return 0;
 }
 
@@ -1178,7 +1179,7 @@ static int ps3_vuart_shutdown(struct ps3
 
 	BUG_ON(!dev);
 
-	down(&vuart_bus_priv.probe_mutex);
+	mutex_lock(&vuart_bus_priv.probe_mutex);
 
 	dev_dbg(&dev->core, " -> %s:%d: match_id %d\n", __func__, __LINE__,
 		dev->match_id);
@@ -1186,7 +1187,7 @@ static int ps3_vuart_shutdown(struct ps3
 	if (!dev->core.driver) {
 		dev_dbg(&dev->core, "%s:%d: no driver bound\n", __func__,
 			__LINE__);
-		up(&vuart_bus_priv.probe_mutex);
+		mutex_unlock(&vuart_bus_priv.probe_mutex);
 		return 0;
 	}
 
@@ -1210,7 +1211,7 @@ static int ps3_vuart_shutdown(struct ps3
 
 	dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__);
 
-	up(&vuart_bus_priv.probe_mutex);
+	mutex_unlock(&vuart_bus_priv.probe_mutex);
 	return 0;
 }
 
@@ -1221,7 +1222,7 @@ static int __init ps3_vuart_bus_init(voi
 	if (!firmware_has_feature(FW_FEATURE_PS3_LV1))
 		return -ENODEV;
 
-	init_MUTEX(&vuart_bus_priv.probe_mutex);
+	mutex_init(&vuart_bus_priv.probe_mutex);
 
 	return 0;
 }
-- 

-- 

^ permalink raw reply

* RE:  [PATCH 0/3] UCC TDM driver for MPC83xx platforms
From: Aggrwal Poonam @ 2008-01-11  4:58 UTC (permalink / raw)
  To: linuxppc-dev
In-Reply-To: <FBA61160C48B8D438F3323FEFB4EF2C26E765F@zin33exm24.fsl.freescale.net>

=20
Hello  All

I am waiting for more feedback on the patches.

If there are no objections please consider them for 2.6.25.

With Regards
Poonam=20
=20
=20

-----Original Message-----
From: netdev-owner@vger.kernel.org [mailto:netdev-owner@vger.kernel.org]
On Behalf Of Aggrwal Poonam
Sent: Monday, December 10, 2007 5:23 PM
To: rubini@vision.unipv.it; linux-ppcdev@ozlabs.kernel.org;
netdev@vger.kernel.org; linux-kernel@vger.kernel.org; Gala Kumar
Cc: Barkowski Michael; Phillips Kim; Kalra Ashish; Cutler Richard
Subject: [PATCH 0/3] UCC TDM driver for MPC83xx platforms=20

There are three patches
[PATCH 1/3] drivers/misc : UCC TDM driver for mpc83xx platforms. This
driver is usable in VoIP iind of applications to interface with SLIC
kind of devices to exchange TDM voice samples.

[PATCH 2/3] arch/ : Platform changes
- device tree entries for UCC TDM driver for MPC8323ERDB platform.
- QE changes related to TDM , like,
	 1) Modified ucc_fast_init so that it can be used by fast UCC
based TDM driver. Mainly changes have been made to configure TDM clocks
and Fsyncs.

	2) Modified get_brg_clk so that it can return the input frequncy
and input source of any BRG by reading the corresponding entries from
device tree.

	3) Added new nodes brg and clocks in the device tree which
represent input clocks for different BRGs.

	4) Modified qe_setbrg accordingly.
- new device tree entries added for "clocks" and "brg"

[PATCH 3/3] Documentation
- Modified Documentation to explain the device tree entries related to
UCC TDM driver and the new nodes added("clocks" and "brg")

The patch applies over a merge of galak's for-2.6.25 plus for-2.6.24
plus of_doc_update branches.
In brief the steps were
git clone
git://git.kernel.org/pub/scm/linux/kernel/git/galak/powerpc.git
powerpc-galak git checkout -b for-2.6.25 origin/for-2.6.25 git checkout
-b for-2.6.24 origin/for-2.6.24 git checkout -b of_doc_update
origin/of_doc_update
git pull . for-2.6.24    # merge the other two
git pull . for-2.6.25=20
git checkout -b tdm      # clean slate for tdm rebase work

Also after applying the patches changes have to be made corresponding to
Tabi's patch "qe: add function qe_clock_source".

The driver has been tested with a VoIP stack and application on
MPC8323ERDB.

With Regards
Poonam=20
=20
=20
--
To unsubscribe from this list: send the line "unsubscribe netdev" in the
body of a message to majordomo@vger.kernel.org More majordomo info at
http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH 2/5] Warp Base Platform - dts
From: Sean MacLennan @ 2008-01-11  5:21 UTC (permalink / raw)
  To: linuxppc-dev
In-Reply-To: <20080111002037.GB23402@localhost.localdomain>

David Gibson wrote:
> On Thu, Jan 10, 2008 at 06:59:03PM -0500, Sean MacLennan wrote:
>   
>> New version with recommended changes. Device types removed. FPGA
>> moved to correct bus.
>>     
>
> [snip]
>   
>> +				fpga@2,0 {
>> +					compatible = "pika,fpga";
>> +			   		reg = <0 80000000 2200>;
>>     
>
> Your reg property doesn't match your node name here...
>   
Is the following correct?

				fpga@2,0 {
					compatible = "pika,fpga";
			   		reg = <2 80000000 2200>;
					interrupts = <18 8>;
					interrupt-parent = <&UIC0>;
				};


Cheers,
   Sean

^ permalink raw reply

* Re: [PATCH 2/5] Warp Base Platform - dts
From: David Gibson @ 2008-01-11  5:32 UTC (permalink / raw)
  To: Sean MacLennan; +Cc: linuxppc-dev
In-Reply-To: <4786FCD0.5020100@pikatech.com>

On Fri, Jan 11, 2008 at 12:21:20AM -0500, Sean MacLennan wrote:
> David Gibson wrote:
> > On Thu, Jan 10, 2008 at 06:59:03PM -0500, Sean MacLennan wrote:
> >   
> >> New version with recommended changes. Device types removed. FPGA
> >> moved to correct bus.
> >>     
> >
> > [snip]
> >   
> >> +				fpga@2,0 {
> >> +					compatible = "pika,fpga";
> >> +			   		reg = <0 80000000 2200>;
> >>     
> >
> > Your reg property doesn't match your node name here...
> >   
> Is the following correct?
> 
> 				fpga@2,0 {
> 					compatible = "pika,fpga";
> 			   		reg = <2 80000000 2200>;
> 					interrupts = <18 8>;
> 					interrupt-parent = <&UIC0>;
> 				};

No.  You'd need
	fpga@2,80000000 {
		reg = <2 80000000 2200>;
		...
	};

If, indeed, the fpga really has 32 bit address lines and requires the
high one to be 1...

Or possibly what you actually want is:
	fpga@2,0 {
		reg = <2 0 2200>;
		...
	};

-- 
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

* Re: ibm4xx_quiesce_eth?
From: Stefan Roese @ 2008-01-11  6:14 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Sean MacLennan
In-Reply-To: <20080110122427.59102355@zod.rchland.ibm.com>

On Thursday 10 January 2008, Josh Boyer wrote:
> On Thu, 10 Jan 2008 13:38:12 -0500
>
> Sean MacLennan <smaclennan@pikatech.com> wrote:
> > What exactly does this function do?
> >
> >     /* Quiesce the MAL and EMAC(s) since PIBS/OpenBIOS don't
> >      * do this for us
> >      */
> >
> > On the taco, with the 440EP, it doesn't seem to make any difference if I
> > call this or not. Since I am using u-boot, is it not needed?
>
> There are firmwares that do not reset the EMAC and MAL before passing
> control to the client program (Linux in our case).  This can cause
> weird things to happen, like spurious interrupts or DMAs from the
> hardware overwriting kernel memory.  So we quiesce the hardware really
> early on those.
>
> I don't believe U-Boot has that problem.  If it does, it should be
> fixed :)

No, U-Boot doesn't have this problem.

Best regards,
Stefan

=====================================================================
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: +49-8142-66989-0 Fax: +49-8142-66989-80  Email: office@denx.de
=====================================================================

^ permalink raw reply

* Re: [PATCH 2/5] Warp Base Platform - dts
From: Sean MacLennan @ 2008-01-11  6:15 UTC (permalink / raw)
  To: Sean MacLennan, linuxppc-dev
In-Reply-To: <20080111053231.GC25055@localhost.localdomain>

David Gibson wrote:
> Or possibly what you actually want is:
> 	fpga@2,0 {
> 		reg = <2 0 2200>;
> 		...
> 	};
>   
That is what I want. I was missing a call to 
ibm4xx_fixup_ebc_ranges("/plb/opb/ebc"); (see updated patch3/5 to follow.

Signed-off-by: Sean MacLennan <smaclennan@pikatech.com>
---
--- /dev/null	2005-11-20 22:22:37.000000000 -0500
+++ arch/powerpc/boot/dts/warp.dts	2008-01-11 00:57:34.000000000 -0500
@@ -0,0 +1,229 @@
+/*
+ * Device Tree Source for PIKA Warp
+ *
+ * Copyright (c) 2008 PIKA Technologies
+ *   Sean MacLennan <smaclennan@pikatech.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without
+ * any warranty of any kind, whether express or implied.
+ */
+
+/ {
+	#address-cells = <2>;
+	#size-cells = <1>;
+	model = "pika,warp";
+	compatible = "pika,warp";
+	dcr-parent = <&/cpus/cpu@0>;
+
+	aliases {
+		ethernet0 = &EMAC0;
+		serial0 = &UART0;
+	};
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		cpu@0 {
+			device_type = "cpu";
+			model = "PowerPC,440EP";
+			reg = <0>;
+			clock-frequency = <0>; /* Filled in by zImage */
+			timebase-frequency = <0>; /* Filled in by zImage */
+			i-cache-line-size = <20>;
+			d-cache-line-size = <20>;
+			i-cache-size = <8000>;
+			d-cache-size = <8000>;
+			dcr-controller;
+			dcr-access-method = "native";
+		};
+	};
+
+	memory {
+		device_type = "memory";
+		reg = <0 0 0>; /* Filled in by zImage */
+	};
+
+	UIC0: interrupt-controller0 {
+		compatible = "ibm,uic-440ep","ibm,uic";
+		interrupt-controller;
+		cell-index = <0>;
+		dcr-reg = <0c0 009>;
+		#address-cells = <0>;
+		#size-cells = <0>;
+		#interrupt-cells = <2>;
+	};
+
+	UIC1: interrupt-controller1 {
+		compatible = "ibm,uic-440ep","ibm,uic";
+		interrupt-controller;
+		cell-index = <1>;
+		dcr-reg = <0d0 009>;
+		#address-cells = <0>;
+		#size-cells = <0>;
+		#interrupt-cells = <2>;
+		interrupts = <1e 4 1f 4>; /* cascade */
+		interrupt-parent = <&UIC0>;
+	};
+
+	SDR0: sdr {
+		compatible = "ibm,sdr-440ep";
+		dcr-reg = <00e 002>;
+	};
+
+	CPR0: cpr {
+		compatible = "ibm,cpr-440ep";
+		dcr-reg = <00c 002>;
+	};
+
+	plb {
+		compatible = "ibm,plb-440ep", "ibm,plb-440gp", "ibm,plb4";
+		#address-cells = <2>;
+		#size-cells = <1>;
+		ranges;
+		clock-frequency = <0>; /* Filled in by zImage */
+
+		SDRAM0: sdram {
+			compatible = "ibm,sdram-440ep", "ibm,sdram-405gp";
+			dcr-reg = <010 2>;
+		};
+
+		DMA0: dma {
+			compatible = "ibm,dma-440ep", "ibm,dma-440gp";
+			dcr-reg = <100 027>;
+		};
+
+		MAL0: mcmal {
+			compatible = "ibm,mcmal-440ep", "ibm,mcmal-440gp", "ibm,mcmal";
+			dcr-reg = <180 62>;
+			num-tx-chans = <4>;
+			num-rx-chans = <2>;
+			interrupt-parent = <&MAL0>;
+			interrupts = <0 1 2 3 4>;
+			#interrupt-cells = <1>;
+			#address-cells = <0>;
+			#size-cells = <0>;
+			interrupt-map = </*TXEOB*/ 0 &UIC0 a 4
+					/*RXEOB*/ 1 &UIC0 b 4
+					/*SERR*/  2 &UIC1 0 4
+					/*TXDE*/  3 &UIC1 1 4
+					/*RXDE*/  4 &UIC1 2 4>;
+		};
+
+		POB0: opb {
+		  	compatible = "ibm,opb-440ep", "ibm,opb-440gp", "ibm,opb";
+			#address-cells = <1>;
+			#size-cells = <1>;
+		  	ranges = <00000000 0 00000000 80000000
+			          80000000 0 80000000 80000000>;
+		  	interrupt-parent = <&UIC1>;
+		  	interrupts = <7 4>;
+		  	clock-frequency = <0>; /* Filled in by zImage */
+
+			EBC0: ebc {
+				compatible = "ibm,ebc-440ep", "ibm,ebc-440gp", "ibm,ebc";
+				dcr-reg = <012 2>;
+				#address-cells = <2>;
+				#size-cells = <1>;
+				clock-frequency = <0>; /* Filled in by zImage */
+				interrupts = <5 1>;
+				interrupt-parent = <&UIC1>;
+
+				fpga@2,0 {
+					compatible = "pika,fpga";
+			   		reg = <2 0 2200>;
+					interrupts = <18 8>;
+					interrupt-parent = <&UIC0>;
+				};
+
+				nor_flash@0,0 {
+					compatible = "amd,s29gl512n", "cfi-flash";
+					bank-width = <2>;
+					reg = <0 0 4000000>;
+					#address-cells = <1>;
+					#size-cells = <1>;
+					partition@0 {
+						label = "kernel";
+						reg = <0 180000>;
+					};
+					partition@180000 {
+						label = "root";
+						reg = <180000 3480000>;
+					};
+					partition@3600000 {
+						label = "user";
+						reg = <3600000 900000>;
+					};
+					partition@3f00000 {
+						label = "fpga";
+						reg = <3f00000 40000>;
+					};
+					partition@3f40000 {
+						label = "env";
+						reg = <3f40000 40000>;
+					};
+					partition@3f80000 {
+						label = "u-boot";
+						reg = <3f80000 80000>;
+					};
+				};
+			};
+
+			UART0: serial@ef600300 {
+		   		device_type = "serial";
+		   		compatible = "ns16550";
+		   		reg = <ef600300 8>;
+		   		virtual-reg = <ef600300>;
+		   		clock-frequency = <0>; /* Filled in by zImage */
+		   		current-speed = <1c200>;
+		   		interrupt-parent = <&UIC0>;
+		   		interrupts = <0 4>;
+	   		};
+
+			IIC0: i2c@ef600700 {
+				compatible = "ibm,iic-440ep", "ibm,iic-440gp", "ibm,iic";
+				reg = <ef600700 14>;
+				interrupt-parent = <&UIC0>;
+				interrupts = <2 4>;
+			};
+
+			ZMII0: emac-zmii@ef600d00 {
+				compatible = "ibm,zmii-440ep", "ibm,zmii-440gp", "ibm,zmii";
+				reg = <ef600d00 c>;
+			};
+
+			EMAC0: ethernet@ef600e00 {
+				linux,network-index = <0>;
+				device_type = "network";
+				compatible = "ibm,emac-440ep", "ibm,emac-440gp", "ibm,emac";
+				interrupt-parent = <&UIC1>;
+				interrupts = <1c 4 1d 4>;
+				reg = <ef600e00 70>;
+				local-mac-address = [000000000000];
+				mal-device = <&MAL0>;
+				mal-tx-channel = <0 1>;
+				mal-rx-channel = <0>;
+				cell-index = <0>;
+				max-frame-size = <5dc>;
+				rx-fifo-size = <1000>;
+				tx-fifo-size = <800>;
+				phy-mode = "rmii";
+				phy-map = <00000000>;
+				zmii-device = <&ZMII0>;
+				zmii-channel = <0>;
+			};
+
+			usb@ef601000 {
+				compatible = "ohci-be";
+				reg = <ef601000 80>;
+				interrupts = <8 1 9 1>;
+				interrupt-parent = < &UIC1 >;
+			};
+		};
+	};
+
+	chosen {
+		linux,stdout-path = "/plb/opb/serial@ef600300";
+	};
+};

^ permalink raw reply

* Re: [PATCH 3/5] Warp Base Platform
From: Sean MacLennan @ 2008-01-11  6:17 UTC (permalink / raw)
  Cc: linuxppc-dev
In-Reply-To: <4786B295.3000501@pikatech.com>

Update based on fixes to warp.dts.

Signed-off-by: Sean MacLennan <smaclennan@pikatech.com>
---
diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile
index d1e625c..cd83c4f 100644
--- a/arch/powerpc/boot/Makefile
+++ b/arch/powerpc/boot/Makefile
@@ -62,7 +62,7 @@ src-plat := of.c cuboot-52xx.c cuboot-83xx.c cuboot-85xx.c holly.c \
 		ps3-head.S ps3-hvcall.S ps3.c treeboot-bamboo.c cuboot-8xx.c \
 		cuboot-pq2.c cuboot-sequoia.c treeboot-walnut.c cuboot-bamboo.c \
 		fixed-head.S ep88xc.c cuboot-hpc2.c ep405.c cuboot-taishan.c \
-		cuboot-katmai.c cuboot-rainier.c
+		cuboot-katmai.c cuboot-rainier.c cuboot-warp.c
 src-boot := $(src-wlib) $(src-plat) empty.c
 
 src-boot := $(addprefix $(obj)/, $(src-boot))
@@ -206,6 +206,7 @@ image-$(CONFIG_RAINIER)			+= cuImage.rainier
 image-$(CONFIG_WALNUT)			+= treeImage.walnut
 image-$(CONFIG_TAISHAN)			+= cuImage.taishan
 image-$(CONFIG_KATMAI)			+= cuImage.katmai
+image-$(CONFIG_WARP)			+= cuImage.warp
 endif
 
 # For 32-bit powermacs, build the COFF and miboot images
--- /dev/null	2005-11-20 22:22:37.000000000 -0500
+++ arch/powerpc/boot/cuboot-warp.c	2008-01-11 01:08:54.000000000 -0500
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2008 PIKA Technologies
+ *   Sean MacLennan <smaclennan@pikatech.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include "ops.h"
+#include "4xx.h"
+#include "cuboot.h"
+
+#define TARGET_44x
+#include "ppcboot.h"
+
+static bd_t bd;
+
+static void warp_fixups(void)
+{
+	unsigned long sysclk = 66000000;
+
+	ibm440ep_fixup_clocks(sysclk, 11059200, 50000000);
+	ibm4xx_sdram_fixup_memsize();
+	ibm4xx_fixup_ebc_ranges("/plb/opb/ebc");
+	dt_fixup_mac_addresses(&bd.bi_enetaddr);
+}
+
+
+void platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+		   unsigned long r6, unsigned long r7)
+{
+	CUBOOT_INIT();
+
+	platform_ops.fixups = warp_fixups;
+	platform_ops.exit = ibm44x_dbcr_reset;
+	fdt_init(_dtb_start);
+	serial_console_init();
+}

^ permalink raw reply related


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