[PATCH] ppc64: SMU partition recovery
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>
Mon, 7 Nov 2005 03:29:02 +0000 (14:29 +1100)
committerPaul Mackerras <paulus@samba.org>
Tue, 8 Nov 2005 00:17:40 +0000 (11:17 +1100)
This patch adds the ability to the SMU driver to recover missing
calibration partitions from the SMU chip itself. It also adds some
dynamic mecanism to /proc/device-tree so that new properties are visible
to userland.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>
arch/powerpc/kernel/prom.c
arch/ppc/syslib/prom.c
arch/ppc64/kernel/prom.c
drivers/macintosh/smu.c
fs/proc/proc_devtree.c
include/asm-powerpc/prom.h
include/asm-powerpc/smu.h
include/asm-ppc/prom.h
include/asm-ppc64/prom.h
include/linux/proc_fs.h

index 3675ef4..f645adb 100644 (file)
@@ -1974,14 +1974,29 @@ EXPORT_SYMBOL(get_property);
 /*
  * Add a property to a node
  */
-void prom_add_property(struct device_node* np, struct property* prop)
+int prom_add_property(struct device_node* np, struct property* prop)
 {
-       struct property **next = &np->properties;
+       struct property **next;
 
        prop->next = NULL;      
-       while (*next)
+       write_lock(&devtree_lock);
+       next = &np->properties;
+       while (*next) {
+               if (strcmp(prop->name, (*next)->name) == 0) {
+                       /* duplicate ! don't insert it */
+                       write_unlock(&devtree_lock);
+                       return -1;
+               }
                next = &(*next)->next;
+       }
        *next = prop;
+       write_unlock(&devtree_lock);
+
+       /* try to add to proc as well if it was initialized */
+       if (np->pde)
+               proc_device_tree_add_prop(np->pde, prop);
+
+       return 0;
 }
 
 /* I quickly hacked that one, check against spec ! */
index 1b9aa0d..03b1fc9 100644 (file)
@@ -1165,7 +1165,7 @@ get_property(struct device_node *np, const char *name, int *lenp)
 /*
  * Add a property to a node
  */
-void
+int
 prom_add_property(struct device_node* np, struct property* prop)
 {
        struct property **next = &np->properties;
@@ -1174,6 +1174,8 @@ prom_add_property(struct device_node* np, struct property* prop)
        while (*next)
                next = &(*next)->next;
        *next = prop;
+
+       return 0;
 }
 
 /* I quickly hacked that one, check against spec ! */
index 0e8961d..3402fbe 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/initrd.h>
 #include <linux/bitops.h>
 #include <linux/module.h>
+#include <linux/module.h>
 
 #include <asm/prom.h>
 #include <asm/rtas.h>
@@ -1865,17 +1866,32 @@ get_property(struct device_node *np, const char *name, int *lenp)
 EXPORT_SYMBOL(get_property);
 
 /*
- * Add a property to a node
+ * Add a property to a node.
  */
-void
+int
 prom_add_property(struct device_node* np, struct property* prop)
 {
-       struct property **next = &np->properties;
+       struct property **next;
 
        prop->next = NULL;      
-       while (*next)
+       write_lock(&devtree_lock);
+       next = &np->properties;
+       while (*next) {
+               if (strcmp(prop->name, (*next)->name) == 0) {
+                       /* duplicate ! don't insert it */
+                       write_unlock(&devtree_lock);
+                       return -1;
+               }
                next = &(*next)->next;
+       }
        *next = prop;
+       write_unlock(&devtree_lock);
+
+       /* try to add to proc as well if it was initialized */
+       if (np->pde)
+               proc_device_tree_add_prop(np->pde, prop);
+
+       return 0;
 }
 
 #if 0
index a931e50..a83c4ac 100644 (file)
 #include <asm/uaccess.h>
 #include <asm/of_device.h>
 
-#define VERSION "0.6"
+#define VERSION "0.7"
 #define AUTHOR  "(c) 2005 Benjamin Herrenschmidt, IBM Corp."
 
 #undef DEBUG_SMU
 
 #ifdef DEBUG_SMU
-#define DPRINTK(fmt, args...) do { printk(KERN_DEBUG fmt , ##args); } while (0)
+#define DPRINTK(fmt, args...) do { udbg_printf(KERN_DEBUG fmt , ##args); } while (0)
 #else
 #define DPRINTK(fmt, args...) do { } while (0)
 #endif
@@ -92,7 +92,7 @@ struct smu_device {
  * for now, just hard code that
  */
 static struct smu_device       *smu;
-
+static DECLARE_MUTEX(smu_part_access);
 
 /*
  * SMU driver low level stuff
@@ -113,9 +113,11 @@ static void smu_start_cmd(void)
 
        DPRINTK("SMU: starting cmd %x, %d bytes data\n", cmd->cmd,
                cmd->data_len);
-       DPRINTK("SMU: data buffer: %02x %02x %02x %02x ...\n",
+       DPRINTK("SMU: data buffer: %02x %02x %02x %02x %02x %02x %02x %02x\n",
                ((u8 *)cmd->data_buf)[0], ((u8 *)cmd->data_buf)[1],
-               ((u8 *)cmd->data_buf)[2], ((u8 *)cmd->data_buf)[3]);
+               ((u8 *)cmd->data_buf)[2], ((u8 *)cmd->data_buf)[3],
+               ((u8 *)cmd->data_buf)[4], ((u8 *)cmd->data_buf)[5],
+               ((u8 *)cmd->data_buf)[6], ((u8 *)cmd->data_buf)[7]);
 
        /* Fill the SMU command buffer */
        smu->cmd_buf->cmd = cmd->cmd;
@@ -440,7 +442,7 @@ int smu_present(void)
 EXPORT_SYMBOL(smu_present);
 
 
-int smu_init (void)
+int __init smu_init (void)
 {
        struct device_node *np;
        u32 *data;
@@ -845,16 +847,154 @@ int smu_queue_i2c(struct smu_i2c_cmd *cmd)
        return 0;
 }
 
-struct smu_sdbp_header *smu_get_sdb_partition(int id, unsigned int *size)
+/*
+ * Handling of "partitions"
+ */
+
+static int smu_read_datablock(u8 *dest, unsigned int addr, unsigned int len)
+{
+       DECLARE_COMPLETION(comp);
+       unsigned int chunk;
+       struct smu_cmd cmd;
+       int rc;
+       u8 params[8];
+
+       /* We currently use a chunk size of 0xe. We could check the
+        * SMU firmware version and use bigger sizes though
+        */
+       chunk = 0xe;
+
+       while (len) {
+               unsigned int clen = min(len, chunk);
+
+               cmd.cmd = SMU_CMD_MISC_ee_COMMAND;
+               cmd.data_len = 7;
+               cmd.data_buf = params;
+               cmd.reply_len = chunk;
+               cmd.reply_buf = dest;
+               cmd.done = smu_done_complete;
+               cmd.misc = &comp;
+               params[0] = SMU_CMD_MISC_ee_GET_DATABLOCK_REC;
+               params[1] = 0x4;
+               *((u32 *)&params[2]) = addr;
+               params[6] = clen;
+
+               rc = smu_queue_cmd(&cmd);
+               if (rc)
+                       return rc;
+               wait_for_completion(&comp);
+               if (cmd.status != 0)
+                       return rc;
+               if (cmd.reply_len != clen) {
+                       printk(KERN_DEBUG "SMU: short read in "
+                              "smu_read_datablock, got: %d, want: %d\n",
+                              cmd.reply_len, clen);
+                       return -EIO;
+               }
+               len -= clen;
+               addr += clen;
+               dest += clen;
+       }
+       return 0;
+}
+
+static struct smu_sdbp_header *smu_create_sdb_partition(int id)
+{
+       DECLARE_COMPLETION(comp);
+       struct smu_simple_cmd cmd;
+       unsigned int addr, len, tlen;
+       struct smu_sdbp_header *hdr;
+       struct property *prop;
+
+       /* First query the partition info */
+       smu_queue_simple(&cmd, SMU_CMD_PARTITION_COMMAND, 2,
+                        smu_done_complete, &comp,
+                        SMU_CMD_PARTITION_LATEST, id);
+       wait_for_completion(&comp);
+
+       /* Partition doesn't exist (or other error) */
+       if (cmd.cmd.status != 0 || cmd.cmd.reply_len != 6)
+               return NULL;
+
+       /* Fetch address and length from reply */
+       addr = *((u16 *)cmd.buffer);
+       len = cmd.buffer[3] << 2;
+       /* Calucluate total length to allocate, including the 17 bytes
+        * for "sdb-partition-XX" that we append at the end of the buffer
+        */
+       tlen = sizeof(struct property) + len + 18;
+
+       prop = kcalloc(tlen, 1, GFP_KERNEL);
+       if (prop == NULL)
+               return NULL;
+       hdr = (struct smu_sdbp_header *)(prop + 1);
+       prop->name = ((char *)prop) + tlen - 18;
+       sprintf(prop->name, "sdb-partition-%02x", id);
+       prop->length = len;
+       prop->value = (unsigned char *)hdr;
+       prop->next = NULL;
+
+       /* Read the datablock */
+       if (smu_read_datablock((u8 *)hdr, addr, len)) {
+               printk(KERN_DEBUG "SMU: datablock read failed while reading "
+                      "partition %02x !\n", id);
+               goto failure;
+       }
+
+       /* Got it, check a few things and create the property */
+       if (hdr->id != id) {
+               printk(KERN_DEBUG "SMU: Reading partition %02x and got "
+                      "%02x !\n", id, hdr->id);
+               goto failure;
+       }
+       if (prom_add_property(smu->of_node, prop)) {
+               printk(KERN_DEBUG "SMU: Failed creating sdb-partition-%02x "
+                      "property !\n", id);
+               goto failure;
+       }
+
+       return hdr;
+ failure:
+       kfree(prop);
+       return NULL;
+}
+
+/* Note: Only allowed to return error code in pointers (using ERR_PTR)
+ * when interruptible is 1
+ */
+struct smu_sdbp_header *__smu_get_sdb_partition(int id, unsigned int *size,
+                                               int interruptible)
 {
        char pname[32];
+       struct smu_sdbp_header *part;
 
        if (!smu)
                return NULL;
 
        sprintf(pname, "sdb-partition-%02x", id);
-       return (struct smu_sdbp_header *)get_property(smu->of_node,
+
+       if (interruptible) {
+               int rc;
+               rc = down_interruptible(&smu_part_access);
+               if (rc)
+                       return ERR_PTR(rc);
+       } else
+               down(&smu_part_access);
+
+       part = (struct smu_sdbp_header *)get_property(smu->of_node,
                                                      pname, size);
+       if (part == NULL) {
+               part = smu_create_sdb_partition(id);
+               if (part != NULL && size)
+                       *size = part->len << 2;
+       }
+       up(&smu_part_access);
+       return part;
+}
+
+struct smu_sdbp_header *smu_get_sdb_partition(int id, unsigned int *size)
+{
+       return __smu_get_sdb_partition(id, size, 0);
 }
 EXPORT_SYMBOL(smu_get_sdb_partition);
 
@@ -930,6 +1070,14 @@ static ssize_t smu_write(struct file *file, const char __user *buf,
        else if (hdr.cmdtype == SMU_CMDTYPE_WANTS_EVENTS) {
                pp->mode = smu_file_events;
                return 0;
+       } else if (hdr.cmdtype == SMU_CMDTYPE_GET_PARTITION) {
+               struct smu_sdbp_header *part;
+               part = __smu_get_sdb_partition(hdr.cmd, NULL, 1);
+               if (part == NULL)
+                       return -EINVAL;
+               else if (IS_ERR(part))
+                       return PTR_ERR(part);
+               return 0;
        } else if (hdr.cmdtype != SMU_CMDTYPE_SMU)
                return -EINVAL;
        else if (pp->mode != smu_file_commands)
index 6fd57f1..fb117b7 100644 (file)
@@ -49,6 +49,39 @@ static int property_read_proc(char *page, char **start, off_t off,
  */
 
 /*
+ * Add a property to a node
+ */
+static struct proc_dir_entry *
+__proc_device_tree_add_prop(struct proc_dir_entry *de, struct property *pp)
+{
+       struct proc_dir_entry *ent;
+
+       /*
+        * Unfortunately proc_register puts each new entry
+        * at the beginning of the list.  So we rearrange them.
+        */
+       ent = create_proc_read_entry(pp->name,
+                                    strncmp(pp->name, "security-", 9)
+                                    ? S_IRUGO : S_IRUSR, de,
+                                    property_read_proc, pp);
+       if (ent == NULL)
+               return NULL;
+
+       if (!strncmp(pp->name, "security-", 9))
+               ent->size = 0; /* don't leak number of password chars */
+       else
+               ent->size = pp->length;
+
+       return ent;
+}
+
+
+void proc_device_tree_add_prop(struct proc_dir_entry *pde, struct property *prop)
+{
+       __proc_device_tree_add_prop(pde, prop);
+}
+
+/*
  * Process a node, adding entries for its children and its properties.
  */
 void proc_device_tree_add_node(struct device_node *np,
@@ -57,11 +90,9 @@ void proc_device_tree_add_node(struct device_node *np,
        struct property *pp;
        struct proc_dir_entry *ent;
        struct device_node *child;
-       struct proc_dir_entry *list = NULL, **lastp;
        const char *p;
 
        set_node_proc_entry(np, de);
-       lastp = &list;
        for (child = NULL; (child = of_get_next_child(np, child));) {
                p = strrchr(child->full_name, '/');
                if (!p)
@@ -71,9 +102,6 @@ void proc_device_tree_add_node(struct device_node *np,
                ent = proc_mkdir(p, de);
                if (ent == 0)
                        break;
-               *lastp = ent;
-               ent->next = NULL;
-               lastp = &ent->next;
                proc_device_tree_add_node(child, ent);
        }
        of_node_put(child);
@@ -84,7 +112,7 @@ void proc_device_tree_add_node(struct device_node *np,
                 * properties are quite unimportant for us though, thus we
                 * simply "skip" them here, but we do have to check.
                 */
-               for (ent = list; ent != NULL; ent = ent->next)
+               for (ent = de->subdir; ent != NULL; ent = ent->next)
                        if (!strcmp(ent->name, pp->name))
                                break;
                if (ent != NULL) {
@@ -94,25 +122,10 @@ void proc_device_tree_add_node(struct device_node *np,
                        continue;
                }
 
-               /*
-                * Unfortunately proc_register puts each new entry
-                * at the beginning of the list.  So we rearrange them.
-                */
-               ent = create_proc_read_entry(pp->name,
-                                            strncmp(pp->name, "security-", 9)
-                                            ? S_IRUGO : S_IRUSR, de,
-                                            property_read_proc, pp);
+               ent = __proc_device_tree_add_prop(de, pp);
                if (ent == 0)
                        break;
-               if (!strncmp(pp->name, "security-", 9))
-                    ent->size = 0; /* don't leak number of password chars */
-               else
-                    ent->size = pp->length;
-               ent->next = NULL;
-               *lastp = ent;
-               lastp = &ent->next;
        }
-       de->subdir = list;
 }
 
 /*
index 7587bf5..f999df1 100644 (file)
@@ -203,7 +203,7 @@ extern int prom_n_addr_cells(struct device_node* np);
 extern int prom_n_size_cells(struct device_node* np);
 extern int prom_n_intr_cells(struct device_node* np);
 extern void prom_get_irq_senses(unsigned char *senses, int off, int max);
-extern void prom_add_property(struct device_node* np, struct property* prop);
+extern int prom_add_property(struct device_node* np, struct property* prop);
 
 #ifdef CONFIG_PPC32
 /*
index 959bad6..76c29a9 100644 (file)
 /*
  * Partition info commands
  *
- * I do not know what those are for at this point
+ * These commands are used to retreive the sdb-partition-XX datas from
+ * the SMU. The lenght is always 2. First byte is the subcommand code
+ * and second byte is the partition ID.
+ *
+ * The reply is 6 bytes:
+ *
+ *  - 0..1 : partition address
+ *  - 2    : a byte containing the partition ID
+ *  - 3    : length (maybe other bits are rest of header ?)
+ *
+ * The data must then be obtained with calls to another command:
+ * SMU_CMD_MISC_ee_GET_DATABLOCK_REC (described below).
  */
 #define SMU_CMD_PARTITION_COMMAND              0x3e
+#define   SMU_CMD_PARTITION_LATEST             0x01
+#define   SMU_CMD_PARTITION_BASE               0x02
+#define   SMU_CMD_PARTITION_UPDATE             0x03
 
 
 /*
  * Fan control
  *
- * This is a "mux" for fan control commands, first byte is the
- * "sub" command.
+ * This is a "mux" for fan control commands. The command seem to
+ * act differently based on the number of arguments. With 1 byte
+ * of argument, this seem to be queries for fans status, setpoint,
+ * etc..., while with 0xe arguments, we will set the fans speeds.
+ *
+ * Queries (1 byte arg):
+ * ---------------------
+ *
+ * arg=0x01: read RPM fans status
+ * arg=0x02: read RPM fans setpoint
+ * arg=0x11: read PWM fans status
+ * arg=0x12: read PWM fans setpoint
+ *
+ * the "status" queries return the current speed while the "setpoint" ones
+ * return the programmed/target speed. It _seems_ that the result is a bit
+ * mask in the first byte of active/available fans, followed by 6 words (16
+ * bits) containing the requested speed.
+ *
+ * Setpoint (14 bytes arg):
+ * ------------------------
+ *
+ * first arg byte is 0 for RPM fans and 0x10 for PWM. Second arg byte is the
+ * mask of fans affected by the command. Followed by 6 words containing the
+ * setpoint value for selected fans in the mask (or 0 if mask value is 0)
  */
 #define SMU_CMD_FAN_COMMAND                    0x4a
 
 #define   SMU_CMD_POWER_SHUTDOWN               "SHUTDOWN"
 #define   SMU_CMD_POWER_VOLTAGE_SLEW           "VSLEW"
 
+/*
+ * Read ADC sensors
+ *
+ * This command takes one byte of parameter: the sensor ID (or "reg"
+ * value in the device-tree) and returns a 16 bits value
+ */
+#define SMU_CMD_READ_ADC                       0xd8
+
 /* Misc commands
  *
  * This command seem to be a grab bag of various things
  * Misc commands
  *
  * This command seem to be a grab bag of various things
+ *
+ * SMU_CMD_MISC_ee_GET_DATABLOCK_REC is used, among others, to
+ * transfer blocks of data from the SMU. So far, I've decrypted it's
+ * usage to retreive partition data. In order to do that, you have to
+ * break your transfer in "chunks" since that command cannot transfer
+ * more than a chunk at a time. The chunk size used by OF is 0xe bytes,
+ * but it seems that the darwin driver will let you do 0x1e bytes if
+ * your "PMU" version is >= 0x30. You can get the "PMU" version apparently
+ * either in the last 16 bits of property "smu-version-pmu" or as the 16
+ * bytes at offset 1 of "smu-version-info"
+ *
+ * For each chunk, the command takes 7 bytes of arguments:
+ *  byte 0: subcommand code (0x02)
+ *  byte 1: 0x04 (always, I don't know what it means, maybe the address
+ *                space to use or some other nicety. It's hard coded in OF)
+ *  byte 2..5: SMU address of the chunk (big endian 32 bits)
+ *  byte 6: size to transfer (up to max chunk size)
+ *
+ * The data is returned directly
  */
 #define SMU_CMD_MISC_ee_COMMAND                        0xee
 #define   SMU_CMD_MISC_ee_GET_DATABLOCK_REC    0x02
@@ -353,21 +416,26 @@ struct smu_sdbp_header {
        __u8    flags;
 };
 
-/*
- * 32 bits integers are usually encoded with 2x16 bits swapped,
- * this demangles them
+
+ /*
+ * demangle 16 and 32 bits integer in some SMU partitions
+ * (currently, afaik, this concerns only the FVT partition
+ * (0x12)
  */
-#define SMU_U32_MIX(x) ((((x) << 16) & 0xffff0000u) | (((x) >> 16) & 0xffffu))
+#define SMU_U16_MIX(x) le16_to_cpu(x);
+#define SMU_U32_MIX(x)  ((((x) & 0xff00ff00u) >> 8)|(((x) & 0x00ff00ffu) << 8))
+
 
 /* This is the definition of the SMU sdb-partition-0x12 table (called
  * CPU F/V/T operating points in Darwin). The definition for all those
  * SMU tables should be moved to some separate file
  */
-#define SMU_SDB_FVT_ID         0x12
+#define SMU_SDB_FVT_ID                 0x12
 
 struct smu_sdbp_fvt {
        __u32   sysclk;                 /* Base SysClk frequency in Hz for
-                                        * this operating point
+                                        * this operating point. Value need to
+                                        * be unmixed with SMU_U32_MIX()
                                         */
        __u8    pad;
        __u8    maxtemp;                /* Max temp. supported by this
@@ -376,10 +444,73 @@ struct smu_sdbp_fvt {
 
        __u16   volts[3];               /* CPU core voltage for the 3
                                         * PowerTune modes, a mode with
-                                        * 0V = not supported.
+                                        * 0V = not supported. Value need
+                                        * to be unmixed with SMU_U16_MIX()
                                         */
 };
 
+/* This partition contains voltage & current sensor calibration
+ * informations
+ */
+#define SMU_SDB_CPUVCP_ID              0x21
+
+struct smu_sdbp_cpuvcp {
+       __u16   volt_scale;             /* u4.12 fixed point */
+       __s16   volt_offset;            /* s4.12 fixed point */
+       __u16   curr_scale;             /* u4.12 fixed point */
+       __s16   curr_offset;            /* s4.12 fixed point */
+       __s32   power_quads[3];         /* s4.28 fixed point */
+};
+
+/* This partition contains CPU thermal diode calibration
+ */
+#define SMU_SDB_CPUDIODE_ID            0x18
+
+struct smu_sdbp_cpudiode {
+       __u16   m_value;                /* u1.15 fixed point */
+       __s16   b_value;                /* s10.6 fixed point */
+
+};
+
+/* This partition contains Slots power calibration
+ */
+#define SMU_SDB_SLOTSPOW_ID            0x78
+
+struct smu_sdbp_slotspow {
+       __u16   pow_scale;              /* u4.12 fixed point */
+       __s16   pow_offset;             /* s4.12 fixed point */
+};
+
+/* This partition contains machine specific version information about
+ * the sensor/control layout
+ */
+#define SMU_SDB_SENSORTREE_ID          0x25
+
+struct smu_sdbp_sensortree {
+       u8      model_id;
+       u8      unknown[3];
+};
+
+/* This partition contains CPU thermal control PID informations. So far
+ * only single CPU machines have been seen with an SMU, so we assume this
+ * carries only informations for those
+ */
+#define SMU_SDB_CPUPIDDATA_ID          0x17
+
+struct smu_sdbp_cpupiddata {
+       u8      unknown1;
+       u8      target_temp_delta;
+       u8      unknown2;
+       u8      history_len;
+       s16     power_adj;
+       u16     max_power;
+       s32     gp,gr,gd;
+};
+
+
+/* Other partitions without known structures */
+#define SMU_SDB_DEBUG_SWITCHES_ID      0x05
+
 #ifdef __KERNEL__
 /*
  * This returns the pointer to an SMU "sdb" partition data or NULL
@@ -423,8 +554,10 @@ struct smu_user_cmd_hdr
        __u32           cmdtype;
 #define SMU_CMDTYPE_SMU                        0       /* SMU command */
 #define SMU_CMDTYPE_WANTS_EVENTS       1       /* switch fd to events mode */
+#define SMU_CMDTYPE_GET_PARTITION      2       /* retreive an sdb partition */
 
        __u8            cmd;                    /* SMU command byte */
+       __u8            pad[3];                 /* padding */
        __u32           data_len;               /* Lenght of data following */
 };
 
index 75c0637..3e39827 100644 (file)
@@ -93,7 +93,7 @@ extern int device_is_compatible(struct device_node *device, const char *);
 extern int machine_is_compatible(const char *compat);
 extern unsigned char *get_property(struct device_node *node, const char *name,
                                   int *lenp);
-extern void prom_add_property(struct device_node* np, struct property* prop);
+extern int prom_add_property(struct device_node* np, struct property* prop);
 extern void prom_get_irq_senses(unsigned char *, int, int);
 extern int prom_n_addr_cells(struct device_node* np);
 extern int prom_n_size_cells(struct device_node* np);
index bdb4717..76bb026 100644 (file)
@@ -213,6 +213,6 @@ extern int prom_n_addr_cells(struct device_node* np);
 extern int prom_n_size_cells(struct device_node* np);
 extern int prom_n_intr_cells(struct device_node* np);
 extern void prom_get_irq_senses(unsigned char *senses, int off, int max);
-extern void prom_add_property(struct device_node* np, struct property* prop);
+extern int prom_add_property(struct device_node* np, struct property* prop);
 
 #endif /* _PPC64_PROM_H */
index 0563581..65ceeaa 100644 (file)
@@ -139,15 +139,12 @@ extern void proc_tty_unregister_driver(struct tty_driver *driver);
 /*
  * proc_devtree.c
  */
+#ifdef CONFIG_PROC_DEVICETREE
 struct device_node;
+struct property;
 extern void proc_device_tree_init(void);
-#ifdef CONFIG_PROC_DEVICETREE
 extern void proc_device_tree_add_node(struct device_node *, struct proc_dir_entry *);
-#else /* !CONFIG_PROC_DEVICETREE */
-static inline void proc_device_tree_add_node(struct device_node *np, struct proc_dir_entry *pde)
-{
-       return;
-}
+extern void proc_device_tree_add_prop(struct proc_dir_entry *pde, struct property *prop);
 #endif /* CONFIG_PROC_DEVICETREE */
 
 extern struct proc_dir_entry *proc_symlink(const char *,