LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [patch 3/4 v3] PS3: Add logical performance monitor device support
From: Geoff Levand @ 2008-01-10  1:01 UTC (permalink / raw)
  To: paulus; +Cc: linuxppc-dev
In-Reply-To: <47846B3F.6060003@am.sony.com>

Add PS3 logical performance monitor device support to the
PS3 system-bus and platform device registration routines.

Signed-off-by: Geoff Levand <geoffrey.levand@am.sony.com>
---
v2: o Add enum ps3_lpm_tb_type.
    o Remove redundant enclosing structure and return proper
      error codes from ps3_register_lpm_devices().
v3: o Add lpm.node_id to struct ps3_system_bus_device.
    o Cleanup repository discovery logic.

 arch/powerpc/platforms/ps3/device-init.c |   85 +++++++++++++++++++++++++++++++
 arch/powerpc/platforms/ps3/system-bus.c  |    5 +
 include/asm-powerpc/ps3.h                |    8 ++
 3 files changed, 98 insertions(+)
 create mode 100644 arch/powerpc/platforms/ps3/lpm.c

--- a/arch/powerpc/platforms/ps3/device-init.c
+++ b/arch/powerpc/platforms/ps3/device-init.c
@@ -30,6 +30,89 @@
 
 #include "platform.h"
 
+static int __init ps3_register_lpm_devices(void)
+{
+	int result;
+	u64 tmp1;
+	u64 tmp2;
+	struct ps3_system_bus_device *dev;
+
+	pr_debug(" -> %s:%d\n", __func__, __LINE__);
+
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+	if (!dev)
+		return -ENOMEM;
+
+	dev->match_id = PS3_MATCH_ID_LPM;
+	dev->dev_type = PS3_DEVICE_TYPE_LPM;
+
+	/* The current lpm driver only supports a single BE processor. */
+
+	result = ps3_repository_read_be_node_id(0, &dev->lpm.node_id);
+
+	if (result) {
+		pr_debug("%s:%d: ps3_repository_read_be_node_id failed \n",
+			__func__, __LINE__);
+		goto fail_read_repo;
+	}
+
+	result = ps3_repository_read_lpm_privileges(dev->lpm.node_id, &tmp1,
+		&dev->lpm.rights);
+
+	if (result) {
+		pr_debug("%s:%d: ps3_repository_read_lpm_privleges failed \n",
+			__func__, __LINE__);
+		goto fail_read_repo;
+	}
+
+	lv1_get_logical_partition_id(&tmp2);
+
+	if (tmp1 != tmp2) {
+		pr_debug("%s:%d: wrong lpar\n",
+			__func__, __LINE__);
+		result = -ENODEV;
+		goto fail_rights;
+	}
+
+	if (!(dev->lpm.rights & PS3_LPM_RIGHTS_USE_LPM)) {
+		pr_debug("%s:%d: don't have rights to use lpm\n",
+			__func__, __LINE__);
+		result = -EPERM;
+		goto fail_rights;
+	}
+
+	pr_debug("%s:%d: pu_id %lu, rights %lu(%lxh)\n",
+		__func__, __LINE__, dev->lpm.pu_id, dev->lpm.rights,
+		dev->lpm.rights);
+
+	result = ps3_repository_read_pu_id(0, &dev->lpm.pu_id);
+
+	if (result) {
+		pr_debug("%s:%d: ps3_repository_read_pu_id failed \n",
+			__func__, __LINE__);
+		goto fail_read_repo;
+	}
+
+	result = ps3_system_bus_device_register(dev);
+
+	if (result) {
+		pr_debug("%s:%d ps3_system_bus_device_register failed\n",
+			__func__, __LINE__);
+		goto fail_register;
+	}
+
+	pr_debug(" <- %s:%d\n", __func__, __LINE__);
+	return 0;
+
+
+fail_register:
+fail_rights:
+fail_read_repo:
+	kfree(dev);
+	pr_debug(" <- %s:%d: failed\n", __func__, __LINE__);
+	return result;
+}
+
 /**
  * ps3_setup_gelic_device - Setup and register a gelic device instance.
  *
@@ -787,6 +870,8 @@ static int __init ps3_register_devices(v
 
 	ps3_register_sound_devices();
 
+	ps3_register_lpm_devices();
+
 	pr_debug(" <- %s:%d\n", __func__, __LINE__);
 	return 0;
 }
--- a/arch/powerpc/platforms/ps3/system-bus.c
+++ b/arch/powerpc/platforms/ps3/system-bus.c
@@ -715,6 +715,7 @@ int ps3_system_bus_device_register(struc
 	static unsigned int dev_ioc0_count;
 	static unsigned int dev_sb_count;
 	static unsigned int dev_vuart_count;
+	static unsigned int dev_lpm_count;
 
 	if (!dev->core.parent)
 		dev->core.parent = &ps3_system_bus;
@@ -737,6 +738,10 @@ int ps3_system_bus_device_register(struc
 		snprintf(dev->core.bus_id, sizeof(dev->core.bus_id),
 			"vuart_%02x", ++dev_vuart_count);
 		break;
+	case PS3_DEVICE_TYPE_LPM:
+		snprintf(dev->core.bus_id, sizeof(dev->core.bus_id),
+			"lpm_%02x", ++dev_lpm_count);
+		break;
 	default:
 		BUG();
 	};
--- a/include/asm-powerpc/ps3.h
+++ b/include/asm-powerpc/ps3.h
@@ -317,6 +317,7 @@ enum ps3_match_id {
 	PS3_MATCH_ID_STOR_FLASH     = 8,
 	PS3_MATCH_ID_SOUND          = 9,
 	PS3_MATCH_ID_GRAPHICS       = 10,
+	PS3_MATCH_ID_LPM            = 11,
 };
 
 #define PS3_MODULE_ALIAS_EHCI           "ps3:1"
@@ -329,11 +330,13 @@ enum ps3_match_id {
 #define PS3_MODULE_ALIAS_STOR_FLASH     "ps3:8"
 #define PS3_MODULE_ALIAS_SOUND          "ps3:9"
 #define PS3_MODULE_ALIAS_GRAPHICS       "ps3:10"
+#define PS3_MODULE_ALIAS_LPM            "ps3:11"
 
 enum ps3_system_bus_device_type {
 	PS3_DEVICE_TYPE_IOC0 = 1,
 	PS3_DEVICE_TYPE_SB,
 	PS3_DEVICE_TYPE_VUART,
+	PS3_DEVICE_TYPE_LPM,
 };
 
 /**
@@ -350,6 +353,11 @@ struct ps3_system_bus_device {
 	struct ps3_dma_region *d_region;  /* SB, IOC0 */
 	struct ps3_mmio_region *m_region; /* SB, IOC0*/
 	unsigned int port_number;         /* VUART */
+	struct {                          /* LPM */
+		u64 node_id;
+		u64 pu_id;
+		u64 rights;
+	} lpm;
 
 /*	struct iommu_table *iommu_table; -- waiting for BenH's cleanups */
 	struct device core;

^ permalink raw reply

* [patch 4/4 v3] PS3: Add logical performance monitor driver support
From: Geoff Levand @ 2008-01-10  1:01 UTC (permalink / raw)
  To: paulus; +Cc: linuxppc-dev, Takashi Yamamoto
In-Reply-To: <47846B48.5000003@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 'lost' -> 'loss'.
   o Use lpm_priv->node_id with lv1_construct_lpm().

 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 whos 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 2/3] sbc834x: Add device tree source for Wind River SBC834x board.
From: David Gibson @ 2008-01-10  2:06 UTC (permalink / raw)
  To: Paul Gortmaker; +Cc: linuxppc-dev
In-Reply-To: <b9cda8aa586eba852f0763db2347d545a5b31be6.1199850992.git.paul.gortmaker@windriver.com>

On Wed, Jan 09, 2008 at 12:49:31AM -0500, Paul Gortmaker wrote:
> This adds the device tree source for the Wind River SBC834x board.
> It is based on the MPC834x_MDS DTS, with the biggest difference being
> the lack of BCSR and the PCI2 that the MDS gets via the PIB. That,
> and this file is also dts-v1 format.
> 
> Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
> ---
>  arch/powerpc/boot/dts/sbc8349.dts |  247 +++++++++++++++++++++++++++++++++++++
>  1 files changed, 247 insertions(+), 0 deletions(-)
> 
> diff --git a/arch/powerpc/boot/dts/sbc8349.dts b/arch/powerpc/boot/dts/sbc8349.dts

[snip]
> +		wdt@200 {
> +			device_type = "watchdog";
> +			compatible = "mpc83xx_wdt";

Grah!  Hasn't someone fixed this so that the driver doesn't need the
crap device_type?

[snip]
> +		spi@7000 {
> +			device_type = "spi";
> +			compatible = "fsl_spi";

And again here.

[snip]
> +		usb@22000 {
> +			device_type = "usb";
> +			compatible = "fsl-usb2-mph";

And here.

[snip
> +		/* May need to remove if on a part without crypto engine */
> +		crypto@30000 {
> +			device_type = "crypto";
> +			model = "SEC2";
> +			compatible = "talitos";

I'm almost certain this one was fixed, hasn't it been merged yet?

[snip]
> +		ipic: pic@700 {

By generic names best practice this should be
"interrupt-controller@700", although that's probably not your error.

-- 
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: [PATCH 2/3] [libata] pata_of_platform: OF-Platform PATA device driver
From: Stephen Rothwell @ 2008-01-10  2:17 UTC (permalink / raw)
  To: Olof Johansson; +Cc: Paul Mundt, linuxppc-dev, Jeff Garzik, linux-ide
In-Reply-To: <20080110003634.GA19966@lixom.net>

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

On Wed, 9 Jan 2008 18:36:34 -0600 Olof Johansson <olof@lixom.net> wrote:
>
> On Thu, Jan 10, 2008 at 10:40:48AM +1100, Stephen Rothwell wrote:
> > Hi Anton,
> > 
> > Juts one small trivial comment (could be fixed later).
> > 
> > On Wed, 9 Jan 2008 22:10:41 +0300 Anton Vorontsov <avorontsov@ru.mvista.com> wrote:
> > >
> > > +static struct of_device_id pata_of_platform_match[] = {
> > 
> > This could be declared const.
> 
> Good point, but let's not hold up merge based on this. Need something
> for janitors to do too, and it's good enough to merge as-is. :)

Absolutely. To me that is what "(could be fixed later)" means.  :-)

-- 
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 4/7] Device tree for MPC5121 ADS
From: David Gibson @ 2008-01-10  2:18 UTC (permalink / raw)
  To: John Rigby; +Cc: linuxppc-dev
In-Reply-To: <1199808093-15929-5-git-send-email-jrigby@freescale.com>

On Tue, Jan 08, 2008 at 09:01:30AM -0700, John Rigby wrote:
> Bare minimum tree containing only
> what is currently supported.

[snip]
> +	cpus {
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +
> +		PowerPC,5121@0 {
> +			device_type = "cpu";
> +			reg = <0>;
> +			d-cache-line-size = <20>;	// 32 bytes
> +			i-cache-line-size = <20>;	// 32 bytes
> +			d-cache-size = <8000>;		// L1, 32K
> +			i-cache-size = <8000>;		// L1, 32K
> +			ref-frequency = <3ef1480>;	// 66MHz ref clock
> +			timebase-frequency = <2f34f60>; // 49.5MHz (396MHz/8) makes time tick correctly
> +			bus-frequency = <bcd3d80>;	// 198MHz csb bus
> +			clock-frequency = <179a7b00>;	// 396MHz ppc core ??
> +			32-bit;

The "32-bit" property was only ever added by mistake.  Drop it.

[snip]
> +	cpld@82000000 {
> +		device_type = "board-control";

No device_type here.  But you should have a "compatible" property.

[snip]
> +	soc5121@80000000 {
> +		#address-cells = <1>;
> +		#size-cells = <1>;
> +		#interrupt-cells = <2>;
> +		device_type = "soc";
> +		ranges = <0 80000000 400000>;
> +		reg = <80000000 400000>;
> +		ref-frequency = <3ef1480>;	// 66MHz ref

What the hell is ref-frequency?  Unfortunately, you have to work with
existing broken practice for SoC nodes here, but the principle clock
frequency for any device should always be encoded in a property called
"clock-frequency".

[snip]
> +		ipic: pic@c00 {

Should be "interrupt-controller@c00"

> +			interrupt-controller;
> +			#address-cells = <0>;
> +			#interrupt-cells = <2>;
> +			reg = <c00 100>;
> +			built-in;
> +			device_type = "ipic";

Drop this device_type.  Should have a compatible value instead.

-- 
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: add phy-handle property for fec_mpc52xx
From: Paul Mackerras @ 2008-01-10  2:20 UTC (permalink / raw)
  To: Olaf Hering; +Cc: linuxppc-dev
In-Reply-To: <20080109140608.GA15673@aepfle.de>

Olaf Hering writes:

> --- a/arch/powerpc/kernel/prom_init.c
> +++ b/arch/powerpc/kernel/prom_init.c
> @@ -1487,6 +1487,34 @@ static void __init prom_find_mmu(void)
>  	else if (strncmp(version, "FirmWorks,3.", 12) == 0) {
>  		of_workarounds = OF_WA_CLAIM | OF_WA_LONGTRAIL;
>  		call_prom("interpret", 1, 1, "dev /memory 0 to allow-reclaim");
> +#ifdef CONFIG_PPC_MPC52xx
> +	} else if (strcmp(version, "EFIKA5K2") == 0) {

Why have you added this stuff in prom_find_mmu rather than putting it
in fixup_device_tree_efika()?

Paul.

^ permalink raw reply

* Re: add phy-handle property for fec_mpc52xx
From: Paul Mackerras @ 2008-01-10  2:21 UTC (permalink / raw)
  To: David Woodhouse; +Cc: Olaf Hering, linuxppc-dev
In-Reply-To: <1199893757.2978.73.camel@pmac.infradead.org>

David Woodhouse writes:

> It would be much better if the kernel would 'just work'. The ideal way
> of achieving that is for the firmware to be fixed -- but that's been
> promised for a long time now, and we just don't believe you any more. So
> working round it in the kernel seems to be the next best option.

Does the efika use a boot wrapper?  If so then putting the fixup in
the boot wrapper might be better.

Paul.

^ permalink raw reply

* Re: [PATCH 1/8] pseries: phyp dump: Docmentation
From: Linas Vepstas @ 2008-01-10  2:33 UTC (permalink / raw)
  To: Nathan Lynch; +Cc: mahuja, linuxppc-dev, lkessler, strosake
In-Reply-To: <20080109184437.GU14201@localdomain>

On 09/01/2008, Nathan Lynch <ntl@pobox.com> wrote:
> Hi Linas,
>
> Linas Vepstas wrote:
> >
> > As a side effect, the system is in
> > production *while* the dump is being taken;
>
> A dubious feature IMO.

Hmm.  Take it up with Ken Rozendal, this is supposed to be
one of the two main selling points of this thing.

> Seems that the design potentially trades
> reliability of first failure data capture for availability.
> E.g. system crashes, reboots, resumes processing while copying dump,
> crashes again before dump procedure is complete.  How is that handled,
> if at all?

Its handled by the hypervisor.  phyp maintains the copy of the
RMO of  first crash, until such time that the OS declares the
dump of the RMO to be complete. So you'll always have
the RMO of the first crash.

For the rest of RAM, it will come in two parts: some portion
will have been dumped already. The rest has not yet been dumped,
and it will still be there, preserved across the second crash.

So you get both RMO and all of RAM from the first crash.

> > with kdump,
> > you can't go into production until after the dump is finished,
> > and the system has been rebooted a second time.  On
> > systems with terabytes of RAM, the time difference can be
> > hours.
>
> The difference in time it takes to resume the normal workload may be
> significant, yes.  But the time it takes to get a usable dump image
> would seem to be the basically the same.

Yes.

> Since you bring up large systems... a system with terabytes of RAM is
> practically guaranteed to be a NUMA configuration with dozens of cpus.
> When processing a dump on such a system, I wonder how well we fare:
> can we successfully boot with (say) 128 cpus and 256MB of usable
> memory?  Do we have to hot-online nodes as system memory is freed up
> (and does that even work)?  We need to be able to restore the system
> to its optimal topology when the dump is finished; if the best we can
> do is a degraded configuration, the workload will suffer and the
> system admin is likely to just reboot the machine again so the kernel
> will have the right NUMA topology.

Heh. That's the elbow-grease of this thing.  The easy part is to get
the core function working. The hard part is to test these various configs,
and when they don't work, figure out what went wrong. That will take
perseverence and brains.

--linas

^ permalink raw reply

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

On Wed, Jan 09, 2008 at 03:21:07PM -0500, Sean MacLennan wrote:
> 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-08 12:04:10.000000000 -0500

[snip]
> +	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>;
> +		};
> +
> +		FPGA0: fpga {

Surely this must be off the EBC, not directly of the PLB...?

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

[snip]
> +			IIC0: i2c@ef600700 {
> +				device_type = "i2c";

Drop this device_type.

> +				compatible = "ibm,iic-440ep", "ibm,iic-440gp", "ibm,iic";
> +				reg = <ef600700 14>;
> +				interrupt-parent = <&UIC0>;
> +				interrupts = <2 4>;
> +			};
> +
> +			ZMII0: emac-zmii@ef600d00 {
> +				device_type = "zmii-interface";

And this one.

-- 
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: [PATCH 1/8] pseries: phyp dump: Docmentation
From: Linas Vepstas @ 2008-01-10  2:47 UTC (permalink / raw)
  To: michael; +Cc: mahuja, linuxppc-dev, lkessler, Nathan Lynch, strosake
In-Reply-To: <1199919545.7880.11.camel@concordia>

On 09/01/2008, Michael Ellerman <michael@ellerman.id.au> wrote:
>
> > > Only if you can get at rtas, but you can't get at rtas at that point.
>
> AFAICT you don't need to get at RTAS, you just need to look at the
> device tree to see if the property is present, and that is trivial.
>
> You probably just need to add a check in early_init_dt_scan_rtas() which
> sets a flag for the PHYP dump stuff, or add your own scan routine if you
> need.

I no longer remember the details. I do remember spending a lot of time
trying to figure out how to do this. I know I didn't want to write my own scan
routine; maybe that's what stopped me.  As it happens, we also did most
of the development on a broken phyp which simply did not even have
this property, no matter what, and so that may have brain-damaged me.

I went for the "most elegant" solution, where "most elegant" is defined
as "fewest lines of code", "least effort", etc.

Manish may need some hands-on help to extract this token during
early boot.  Hopefully, he'll let us know.

--linas

^ permalink raw reply

* Re: [PATCH 3/5] Warp Base Platform
From: David Gibson @ 2008-01-10  2:49 UTC (permalink / raw)
  To: Sean MacLennan; +Cc: linuxppc-dev
In-Reply-To: <47852D16.2070906@pikatech.com>

On Wed, Jan 09, 2008 at 03:22:46PM -0500, Sean MacLennan wrote:
> Basically the powerpc/boot directory files.

[snip]
> --- /dev/null	2005-11-20 22:22:37.000000000 -0500
> +++ arch/powerpc/boot/cuboot-warp.c	2008-01-08 12:09:39.000000000 -0500
> @@ -0,0 +1,25 @@
> +/*
> + * 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 "44x.h"
> +#include "cuboot.h"
> +
> +#define TARGET_44x
> +#include "ppcboot.h"
> +
> +static bd_t bd;
> +
> +void platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
> +				   unsigned long r6, unsigned long r7)
> +{
> +	CUBOOT_INIT();
> +
> +	warp_init(&bd.bi_enetaddr, &bd.bi_enet1addr);
> +}
> --- /dev/null	2005-11-20 22:22:37.000000000 -0500
> +++ arch/powerpc/boot/warp.c	2008-01-08 12:09:54.000000000 -0500

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.

-- 
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: [PATCH 4/7] sbc8560: Add device tree source for Wind River SBC8560 board
From: David Gibson @ 2008-01-10  2:56 UTC (permalink / raw)
  To: Paul Gortmaker; +Cc: linuxppc-dev
In-Reply-To: <d10d083bafb978936975111f09669120201072ec.1199715362.git.paul.gortmaker@windriver.com>

On Mon, Jan 07, 2008 at 09:25:29AM -0500, Paul Gortmaker wrote:
> This adds the device tree source for the Wind River SBC8560 board.  The
> biggest difference between this and the MPC8560ADS reference platform
> dts is the use of an external 16550 compatible UART instead of the CPM2.
> 
> Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
> ---
>  arch/powerpc/boot/dts/sbc8560.dts |  285 +++++++++++++++++++++++++++++++++++++

[snip]
> +	epld@fc000000 {
> +		#address-cells = <1>;
> +		#size-cells = <1>;
> +		compatible = "localbus";

This compatible doesn't look specific enough.  It should at least have
a vendor prefix.

> +		ranges = <0 fc000000 00c00000>;

Typically, we've been doing these external bust controller type
gadgets with address-cells = <2>, the first cell explicitly encoding
the chipselect.  This gets us closer to the ideal of the device tree
encoding only hardware information, not how the bridge controller is
configured (although "ranges" will still have to contain configuration
dependent information).


> +
> +		serial0: serial@700000 {
> +			device_type = "serial";
> +			compatible = "ns16550";
> +			reg = <700000 100>;
> +			clock-frequency = <1C2000>;
> +			interrupts = <9 2>;
> +			interrupt-parent = <&mpic>;
> +		};
> +
> +		serial1: serial@800000 {
> +			device_type = "serial";
> +			compatible = "ns16550";
> +			reg = <800000 100>;
> +			clock-frequency = <1C2000>;
> +			interrupts = <a 2>;
> +			interrupt-parent = <&mpic>;
> +		};
> +
> +		rtc@900000 {
> +			compatible = "m48t59";
> +			reg = <900000 2000>;
> +		};
> +	};
> +};

-- 
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: [PATCH 1/8] pseries: phyp dump: Docmentation
From: Olof Johansson @ 2008-01-10  3:17 UTC (permalink / raw)
  To: Linas Vepstas; +Cc: mahuja, linuxppc-dev, lkessler, Nathan Lynch, strosake
In-Reply-To: <3ae3aa420801091833i6cf32616o2a060579be1f3191@mail.gmail.com>

On Wed, Jan 09, 2008 at 08:33:53PM -0600, Linas Vepstas wrote:

> Heh. That's the elbow-grease of this thing.  The easy part is to get
> the core function working. The hard part is to test these various configs,
> and when they don't work, figure out what went wrong. That will take
> perseverence and brains.

This just sounds like a whole lot of extra work to get a feature that
already exists. Also, features like these seem to just get tested when the
next enterprise distro is released, so they're broken for long stretches
of time in mainline.

There's a bunch of problems like the NUMA ones, which would by far be
easiest to solve by just doing another reboot or kexec, wouldn't they?


-Olof

^ permalink raw reply

* Re: How complete should the DTS be?
From: David Gibson @ 2008-01-10  3:13 UTC (permalink / raw)
  To: Kumar Gala; +Cc: linuxppc-dev, Sean MacLennan
In-Reply-To: <86AA8535-E2CF-4891-900B-340049A5CA19@kernel.crashing.org>

On Tue, Jan 08, 2008 at 12:04:36AM -0600, Kumar Gala wrote:
> 
> On Jan 7, 2008, at 8:07 PM, Sean MacLennan wrote:
> 
> > Just a general question about DTS "completeness". Like all 440EP
> > processors, the taco has two i2c buses. However, only one bus has
> > anything connected to it.
> >
> > Should I show both bus entries in the DTS, or only the one that is  
> > used?
> > I have generally only been showing the devices that are present. i.e.
> > Only one emac, only one serial port.
> >
> > Is there a convention for this?
> 
> The .dts should reflect the HW as its used.  On some reference boards  
> we might put out more info because of the various configs these types  
> of boards can be setup in.  However if something has a static config  
> just describe that.  So in your example of two i2c buses with only one  
> connected, just describe the one that is used.

Hrm... I'd say this is not something which has a firm convention yet.

It's going to become more of an issue once we get a macros system for
dtc, so the "440EP" macro would have all the devices, even if some are
not connected on a given board.

I'm contemplating suggesting that we adopt the "status" property from
IEEE1275 to cover this.

-- 
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: [PATCH 2/5] Warp Base Platform - dts
From: Sean MacLennan @ 2008-01-10  3:14 UTC (permalink / raw)
  To: linuxppc-dev
In-Reply-To: <20080110024753.GC17816@localhost.localdomain>

David Gibson wrote:
> On Wed, Jan 09, 2008 at 03:21:07PM -0500, Sean MacLennan wrote:
>   
>> 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-08 12:04:10.000000000 -0500
>>     
>
> [snip]
>   
>> +	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>;
>> +		};
>> +
>> +		FPGA0: fpga {
>>     
>
> Surely this must be off the EBC, not directly of the PLB...?
>   
Could be, I don't really know :( I will move it if it makes more sense.

Cheers,
    Sean

^ permalink raw reply

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

David Gibson wrote:
> On Wed, Jan 09, 2008 at 03:22:46PM -0500, Sean MacLennan wrote:
>   
>> Basically the powerpc/boot directory files.
>>     
>
> [snip]
>   
>> --- /dev/null	2005-11-20 22:22:37.000000000 -0500
>> +++ arch/powerpc/boot/cuboot-warp.c	2008-01-08 12:09:39.000000000 -0500
>> @@ -0,0 +1,25 @@
>> +/*
>> + * 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 "44x.h"
>> +#include "cuboot.h"
>> +
>> +#define TARGET_44x
>> +#include "ppcboot.h"
>> +
>> +static bd_t bd;
>> +
>> +void platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
>> +				   unsigned long r6, unsigned long r7)
>> +{
>> +	CUBOOT_INIT();
>> +
>> +	warp_init(&bd.bi_enetaddr, &bd.bi_enet1addr);
>> +}
>> --- /dev/null	2005-11-20 22:22:37.000000000 -0500
>> +++ arch/powerpc/boot/warp.c	2008-01-08 12:09:54.000000000 -0500
>>     
>
> 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.
>
>   
Yes, there is still a plan to use the u-boot device tree. Although not 
in the near feature. I could roll them togeather for now and split them 
out later.

Cheers,
    Sean

^ permalink raw reply

* Re: [PATCH 2/5] Warp Base Platform - dts
From: Josh Boyer @ 2008-01-10  3:17 UTC (permalink / raw)
  To: Sean MacLennan; +Cc: linuxppc-dev
In-Reply-To: <47858D89.4070706@pikatech.com>

On Wed, 09 Jan 2008 22:14:17 -0500
Sean MacLennan <smaclennan@pikatech.com> wrote:

> David Gibson wrote:
> > On Wed, Jan 09, 2008 at 03:21:07PM -0500, Sean MacLennan wrote:
> >   
> >> 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-08 12:04:10.000000000 -0500
> >>     
> >
> > [snip]
> >   
> >> +	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>;
> >> +		};
> >> +
> >> +		FPGA0: fpga {
> >>     
> >
> > Surely this must be off the EBC, not directly of the PLB...?
> >   
> Could be, I don't really know :( I will move it if it makes more sense.

Well, "making more sense" would be finding out where it is on the board
and putting it in the proper place :).

josh

^ permalink raw reply

* Re: [PATCH 3/5] Warp Base Platform
From: David Gibson @ 2008-01-10  3:29 UTC (permalink / raw)
  To: Sean MacLennan; +Cc: linuxppc-dev
In-Reply-To: <47858E46.9010505@pikatech.com>

On Wed, Jan 09, 2008 at 10:17:26PM -0500, Sean MacLennan wrote:
> David Gibson wrote:
> > On Wed, Jan 09, 2008 at 03:22:46PM -0500, Sean MacLennan wrote:
> >   
> >> Basically the powerpc/boot directory files.
> >>     
> >
> > [snip]
> >   
> >> --- /dev/null	2005-11-20 22:22:37.000000000 -0500
> >> +++ arch/powerpc/boot/cuboot-warp.c	2008-01-08 12:09:39.000000000 -0500
> >> @@ -0,0 +1,25 @@
> >> +/*
> >> + * 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 "44x.h"
> >> +#include "cuboot.h"
> >> +
> >> +#define TARGET_44x
> >> +#include "ppcboot.h"
> >> +
> >> +static bd_t bd;
> >> +
> >> +void platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
> >> +				   unsigned long r6, unsigned long r7)
> >> +{
> >> +	CUBOOT_INIT();
> >> +
> >> +	warp_init(&bd.bi_enetaddr, &bd.bi_enet1addr);
> >> +}
> >> --- /dev/null	2005-11-20 22:22:37.000000000 -0500
> >> +++ arch/powerpc/boot/warp.c	2008-01-08 12:09:54.000000000 -0500
> >>     
> >
> > 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.
> >
> >   
> Yes, there is still a plan to use the u-boot device tree. Although not 
> in the near feature. I could roll them togeather for now and split them 
> out later.

Yes, but device-tree aware u-boot doesn't need anything platform
specific in the bootwrapper, so won't be a second user of warp.c.

-- 
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: [PATCH 2/5] Warp Base Platform - dts
From: Sean MacLennan @ 2008-01-10  3:33 UTC (permalink / raw)
  To: Josh Boyer; +Cc: linuxppc-dev
In-Reply-To: <20080109211758.26c8e235@zod.rchland.ibm.com>

Ok, the FPGA is off the EBC, I found it in the documentation.

Under the ebc, I notice the walnut has @n,m. What are n,m? Are they tied 
to chip selects?

The FPGA is CS2 according to the documentation. Do I make it fpga@2,0?

Cheers,
    Sean

^ permalink raw reply

* Re: [PATCH 2/5] Warp Base Platform - dts
From: Josh Boyer @ 2008-01-10  3:36 UTC (permalink / raw)
  To: Sean MacLennan; +Cc: linuxppc-dev
In-Reply-To: <47859224.70109@pikatech.com>

On Wed, 09 Jan 2008 22:33:56 -0500
Sean MacLennan <smaclennan@pikatech.com> wrote:

> Ok, the FPGA is off the EBC, I found it in the documentation.
> 
> Under the ebc, I notice the walnut has @n,m. What are n,m? Are they tied 
> to chip selects?

chip select,offset.

> The FPGA is CS2 according to the documentation. Do I make it fpga@2,0?

If the fpga is on chip select 2, offset 0 from that, yes.  Otherwise,
substitute the proper offset in place of 0.

The ranges property of the EBC node will do the actual address
translation.

josh

^ permalink raw reply

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

On Wed, Jan 09, 2008 at 10:33:56PM -0500, Sean MacLennan wrote:
> Ok, the FPGA is off the EBC, I found it in the documentation.
> 
> Under the ebc, I notice the walnut has @n,m. What are n,m? Are they tied 
> to chip selects?

n is the chipselect, m is the address offset within that chipselect.

> The FPGA is CS2 according to the documentation. Do I make it
> fpga@2,0?

Probably, yes.

-- 
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: [alsa-devel] [PATCH] ASoC drivers for the Freescale MPC8610 SoC
From: David Gibson @ 2008-01-10  3:49 UTC (permalink / raw)
  To: Timur Tabi, Jon Smirl, Liam Girdwood, alsa-devel, linuxppc-dev
In-Reply-To: <20080107182853.GA17312@sirena.org.uk>

On Mon, Jan 07, 2008 at 06:28:54PM +0000, Mark Brown wrote:
> On Mon, Jan 07, 2008 at 09:52:03AM -0600, Timur Tabi wrote:
> > David Gibson wrote:
> 
> > > Ok, but couldn't you strucutre your I2S or fabric driver so that it
> > > only becomes fully operational once the codec driver has registered
> > > with it?
> 
> > Not in ASoC V1.  You have to understand, ASoC V1 was designed without any 
> > consideration for runtime-bindings and other OF goodies.  All connections 
> > between the drivers are static, literally.  In fact, I wouldn't be surprised if 
> > some ASoC drivers cannot be compiled as modules.
> 
> I'd just like to emphasise this point - ASoC v1 really doesn't
> understand the idea that the components of the sound subsystem might be
> probed separately.  It's set up to handle bare hardware with everything
> being probed from code in the machine/fabric driver.  This makes life
> very messy for platforms with something like the device tree.
> 
> As has been said, handling this properly is one of the major motivations
> behind ASoC v2.

Ick.  Ok.

Nonetheless, messing up the device tree to workaround ASoC V1's silly
limitations is not a good idea.  The device tree must represent the
hardware as much as possible.  If that means we have to have a bunch
of platform-specific hacks to instatiate the drivers in the correct
order / combination, that's unfortunate, but there you go.

-- 
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: [PATCH 2/3] Look for include files in the directory of the including file.
From: David Gibson @ 2008-01-10  3:52 UTC (permalink / raw)
  To: Scott Wood; +Cc: linuxppc-dev, jdl
In-Reply-To: <20080106225252.GB8239@ld0162-tx32.am.freescale.net>

On Sun, Jan 06, 2008 at 04:52:52PM -0600, Scott Wood wrote:
> On Fri, Jan 04, 2008 at 03:27:39PM +1100, David Gibson wrote:
> > > +	newfile = dtc_open_file(filename, searchptr);
> > > +	if (!newfile) {
> > > +		yyerrorf("Couldn't open \"%s\": %s",
> > > +		         filename, strerror(errno));
> > > +		exit(1);
> > 
> > Use die() here, that's what it's for.
> 
> die() doesn't print file and line information.
> 
> > > +	while (search) {
> > > +		if (dtc_open_one(file, search->dir, fname))
> > > +			return file;
> > 
> > Don't we need a different case here somewhere for if someone specifies
> > an include file as an absolute path?  Have I missed something?
> 
> Yeah, I forgot about that, and sent another patch to fix it when I
> noticed (jdl had already pulled, so I didn't send an amended patch).
> 
> > [snip]
> > > +struct search_path {
> > > +	const char *dir; /* NULL for current directory */
> > > +	struct search_path *prev, *next;
> > > +};
> > 
> > I wouldn't suggest a doubly linked list here.  Or at least not without
> > converting our many existing singly linked lists at the same time.
> 
> The doubly-linked list is intended to make it easier to construct search
> path lists one-at-a-time from arguments in the proper order, without
> needing to reverse the list at the end.

We've already got that problem with a bunch of the lists we create
during parsing (we have several ugly add-to-end-of-singly-linked-list
functions).  Going to doubly-linked lists might not be a bad idea, but
we should do it across the board, probably using the kernel's list.h
or something like it.

-- 
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: [PATCH 1/8] pseries: phyp dump: Docmentation
From: Michael Ellerman @ 2008-01-10  3:55 UTC (permalink / raw)
  To: linasvepstas; +Cc: mahuja, linuxppc-dev, lkessler, Nathan Lynch, strosake
In-Reply-To: <3ae3aa420801091847l189df8dwb2348624f0267af@mail.gmail.com>

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

On Wed, 2008-01-09 at 20:47 -0600, Linas Vepstas wrote:
> On 09/01/2008, Michael Ellerman <michael@ellerman.id.au> wrote:
> >
> > > > Only if you can get at rtas, but you can't get at rtas at that point.
> >
> > AFAICT you don't need to get at RTAS, you just need to look at the
> > device tree to see if the property is present, and that is trivial.
> >
> > You probably just need to add a check in early_init_dt_scan_rtas() which
> > sets a flag for the PHYP dump stuff, or add your own scan routine if you
> > need.
> 
> I no longer remember the details. I do remember spending a lot of time
> trying to figure out how to do this. I know I didn't want to write my own scan
> routine; maybe that's what stopped me.  As it happens, we also did most
> of the development on a broken phyp which simply did not even have
> this property, no matter what, and so that may have brain-damaged me.

Sure, the API docs for the kernel are a little lacking ;)

> I went for the "most elegant" solution, where "most elegant" is defined
> as "fewest lines of code", "least effort", etc.
> 
> Manish may need some hands-on help to extract this token during
> early boot.  Hopefully, he'll let us know.

It would just be something like:

--- a/arch/powerpc/kernel/rtas.c
+++ b/arch/powerpc/kernel/rtas.c
@@ -901,6 +901,11 @@ int __init early_init_dt_scan_rtas(unsigned long node,
                rtas.size = *sizep;
        }
 
+#ifdef CONFIG_PHYP_DUMP
+       if (of_get_flat_dt_prop(node, "ibm,dump-kernel", NULL))
+               phyp_dump_is_active++;
+#endif
+
 #ifdef CONFIG_UDBG_RTAS_CONSOLE
        basep = of_get_flat_dt_prop(node, "put-term-char", NULL);
        if (basep)


Or to do your own scan routine:


diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
index acc0d24..442134e 100644
--- a/arch/powerpc/kernel/prom.c
+++ b/arch/powerpc/kernel/prom.c
@@ -1022,6 +1022,7 @@ void __init early_init_devtree(void *params)
        /* Some machines might need RTAS info for debugging, grab it now. */
        of_scan_flat_dt(early_init_dt_scan_rtas, NULL);
 #endif
+       of_scan_flat_dt(early_init_dt_scan_phyp_dump, NULL);
 
        /* Retrieve various informations from the /chosen node of the
         * device-tree, including the platform type, initrd location and
diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c
index 52e95c2..af2b6e8 100644
--- a/arch/powerpc/kernel/rtas.c
+++ b/arch/powerpc/kernel/rtas.c
@@ -883,6 +883,19 @@ void __init rtas_initialize(void)
 #endif
 }
 
+int __init early_init_dt_scan_phyp_dump(unsigned long node,
+               const char *uname, int depth, void *data)
+{
+#ifdef CONFIG_PHYP_DUMP
+       if (depth != 1 || strcmp(uname, "rtas") != 0)
+               return 0;
+
+       if (of_get_flat_dt_prop(node, "ibm,dump-kernel", NULL))
+               phyp_dump_is_active++;
+#endif
+       return 1;
+}
+
 int __init early_init_dt_scan_rtas(unsigned long node,
                const char *uname, int depth, void *data)
 {


cheers

-- 
Michael Ellerman
OzLabs, IBM Australia Development Lab

wwweb: http://michael.ellerman.id.au
phone: +61 2 6212 1183 (tie line 70 21183)

We do not inherit the earth from our ancestors,
we borrow it from our children. - S.M.A.R.T Person

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply related

* Re: [PATCH 3/3] Return a non-zero exit code if an error occurs during dts parsing.
From: David Gibson @ 2008-01-10  3:56 UTC (permalink / raw)
  To: Scott Wood; +Cc: linuxppc-dev, jdl
In-Reply-To: <20080106225509.GC8239@ld0162-tx32.am.freescale.net>

On Sun, Jan 06, 2008 at 04:55:09PM -0600, Scott Wood wrote:
> On Fri, Jan 04, 2008 at 03:30:33PM +1100, David Gibson wrote:
> > This is unequivocally wrong.  boot_info should have information about
> > the contents of the blob, not state information like the error.
> 
> "This blob is invalid" *is* information about the contents of the blob.
> 
> > If you're going to use an ugly global, then use it everywhere.
> 
> Why go out of our way to make the code even less library-able/thread-safe?

It doesn't make it any less thread-safe.  A global variable used some
places is just as bad as a global variable used everywhere from that
point of view, and is more complicated.

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


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