aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2005-11-06 22:29:02 -0500
committerPaul Mackerras <paulus@samba.org>2005-11-07 19:17:40 -0500
commit183d020258dfd08178a05c6793dae10409db8abb (patch)
tree5b20bc62709c94bd63e17d800544140213eaf0f5
parent4350147a816b9c5b40fa59e4fa23f17490630b79 (diff)
[PATCH] ppc64: SMU partition recovery
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>
-rw-r--r--arch/powerpc/kernel/prom.c21
-rw-r--r--arch/ppc/syslib/prom.c4
-rw-r--r--arch/ppc64/kernel/prom.c24
-rw-r--r--drivers/macintosh/smu.c164
-rw-r--r--fs/proc/proc_devtree.c57
-rw-r--r--include/asm-powerpc/prom.h2
-rw-r--r--include/asm-powerpc/smu.h153
-rw-r--r--include/asm-ppc/prom.h2
-rw-r--r--include/asm-ppc64/prom.h2
-rw-r--r--include/linux/proc_fs.h9
10 files changed, 381 insertions, 57 deletions
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
index 3675ef4bac90..f645adb57534 100644
--- a/arch/powerpc/kernel/prom.c
+++ b/arch/powerpc/kernel/prom.c
@@ -1974,14 +1974,29 @@ EXPORT_SYMBOL(get_property);
1974/* 1974/*
1975 * Add a property to a node 1975 * Add a property to a node
1976 */ 1976 */
1977void prom_add_property(struct device_node* np, struct property* prop) 1977int prom_add_property(struct device_node* np, struct property* prop)
1978{ 1978{
1979 struct property **next = &np->properties; 1979 struct property **next;
1980 1980
1981 prop->next = NULL; 1981 prop->next = NULL;
1982 while (*next) 1982 write_lock(&devtree_lock);
1983 next = &np->properties;
1984 while (*next) {
1985 if (strcmp(prop->name, (*next)->name) == 0) {
1986 /* duplicate ! don't insert it */
1987 write_unlock(&devtree_lock);
1988 return -1;
1989 }
1983 next = &(*next)->next; 1990 next = &(*next)->next;
1991 }
1984 *next = prop; 1992 *next = prop;
1993 write_unlock(&devtree_lock);
1994
1995 /* try to add to proc as well if it was initialized */
1996 if (np->pde)
1997 proc_device_tree_add_prop(np->pde, prop);
1998
1999 return 0;
1985} 2000}
1986 2001
1987/* I quickly hacked that one, check against spec ! */ 2002/* I quickly hacked that one, check against spec ! */
diff --git a/arch/ppc/syslib/prom.c b/arch/ppc/syslib/prom.c
index 1b9aa0d6a924..03b1fc9b9501 100644
--- a/arch/ppc/syslib/prom.c
+++ b/arch/ppc/syslib/prom.c
@@ -1165,7 +1165,7 @@ get_property(struct device_node *np, const char *name, int *lenp)
1165/* 1165/*
1166 * Add a property to a node 1166 * Add a property to a node
1167 */ 1167 */
1168void 1168int
1169prom_add_property(struct device_node* np, struct property* prop) 1169prom_add_property(struct device_node* np, struct property* prop)
1170{ 1170{
1171 struct property **next = &np->properties; 1171 struct property **next = &np->properties;
@@ -1174,6 +1174,8 @@ prom_add_property(struct device_node* np, struct property* prop)
1174 while (*next) 1174 while (*next)
1175 next = &(*next)->next; 1175 next = &(*next)->next;
1176 *next = prop; 1176 *next = prop;
1177
1178 return 0;
1177} 1179}
1178 1180
1179/* I quickly hacked that one, check against spec ! */ 1181/* I quickly hacked that one, check against spec ! */
diff --git a/arch/ppc64/kernel/prom.c b/arch/ppc64/kernel/prom.c
index 0e8961dea3bc..3402fbee62c7 100644
--- a/arch/ppc64/kernel/prom.c
+++ b/arch/ppc64/kernel/prom.c
@@ -31,6 +31,7 @@
31#include <linux/initrd.h> 31#include <linux/initrd.h>
32#include <linux/bitops.h> 32#include <linux/bitops.h>
33#include <linux/module.h> 33#include <linux/module.h>
34#include <linux/module.h>
34 35
35#include <asm/prom.h> 36#include <asm/prom.h>
36#include <asm/rtas.h> 37#include <asm/rtas.h>
@@ -1865,17 +1866,32 @@ get_property(struct device_node *np, const char *name, int *lenp)
1865EXPORT_SYMBOL(get_property); 1866EXPORT_SYMBOL(get_property);
1866 1867
1867/* 1868/*
1868 * Add a property to a node 1869 * Add a property to a node.
1869 */ 1870 */
1870void 1871int
1871prom_add_property(struct device_node* np, struct property* prop) 1872prom_add_property(struct device_node* np, struct property* prop)
1872{ 1873{
1873 struct property **next = &np->properties; 1874 struct property **next;
1874 1875
1875 prop->next = NULL; 1876 prop->next = NULL;
1876 while (*next) 1877 write_lock(&devtree_lock);
1878 next = &np->properties;
1879 while (*next) {
1880 if (strcmp(prop->name, (*next)->name) == 0) {
1881 /* duplicate ! don't insert it */
1882 write_unlock(&devtree_lock);
1883 return -1;
1884 }
1877 next = &(*next)->next; 1885 next = &(*next)->next;
1886 }
1878 *next = prop; 1887 *next = prop;
1888 write_unlock(&devtree_lock);
1889
1890 /* try to add to proc as well if it was initialized */
1891 if (np->pde)
1892 proc_device_tree_add_prop(np->pde, prop);
1893
1894 return 0;
1879} 1895}
1880 1896
1881#if 0 1897#if 0
diff --git a/drivers/macintosh/smu.c b/drivers/macintosh/smu.c
index a931e508feb6..a83c4acf5710 100644
--- a/drivers/macintosh/smu.c
+++ b/drivers/macintosh/smu.c
@@ -47,13 +47,13 @@
47#include <asm/uaccess.h> 47#include <asm/uaccess.h>
48#include <asm/of_device.h> 48#include <asm/of_device.h>
49 49
50#define VERSION "0.6" 50#define VERSION "0.7"
51#define AUTHOR "(c) 2005 Benjamin Herrenschmidt, IBM Corp." 51#define AUTHOR "(c) 2005 Benjamin Herrenschmidt, IBM Corp."
52 52
53#undef DEBUG_SMU 53#undef DEBUG_SMU
54 54
55#ifdef DEBUG_SMU 55#ifdef DEBUG_SMU
56#define DPRINTK(fmt, args...) do { printk(KERN_DEBUG fmt , ##args); } while (0) 56#define DPRINTK(fmt, args...) do { udbg_printf(KERN_DEBUG fmt , ##args); } while (0)
57#else 57#else
58#define DPRINTK(fmt, args...) do { } while (0) 58#define DPRINTK(fmt, args...) do { } while (0)
59#endif 59#endif
@@ -92,7 +92,7 @@ struct smu_device {
92 * for now, just hard code that 92 * for now, just hard code that
93 */ 93 */
94static struct smu_device *smu; 94static struct smu_device *smu;
95 95static DECLARE_MUTEX(smu_part_access);
96 96
97/* 97/*
98 * SMU driver low level stuff 98 * SMU driver low level stuff
@@ -113,9 +113,11 @@ static void smu_start_cmd(void)
113 113
114 DPRINTK("SMU: starting cmd %x, %d bytes data\n", cmd->cmd, 114 DPRINTK("SMU: starting cmd %x, %d bytes data\n", cmd->cmd,
115 cmd->data_len); 115 cmd->data_len);
116 DPRINTK("SMU: data buffer: %02x %02x %02x %02x ...\n", 116 DPRINTK("SMU: data buffer: %02x %02x %02x %02x %02x %02x %02x %02x\n",
117 ((u8 *)cmd->data_buf)[0], ((u8 *)cmd->data_buf)[1], 117 ((u8 *)cmd->data_buf)[0], ((u8 *)cmd->data_buf)[1],
118 ((u8 *)cmd->data_buf)[2], ((u8 *)cmd->data_buf)[3]); 118 ((u8 *)cmd->data_buf)[2], ((u8 *)cmd->data_buf)[3],
119 ((u8 *)cmd->data_buf)[4], ((u8 *)cmd->data_buf)[5],
120 ((u8 *)cmd->data_buf)[6], ((u8 *)cmd->data_buf)[7]);
119 121
120 /* Fill the SMU command buffer */ 122 /* Fill the SMU command buffer */
121 smu->cmd_buf->cmd = cmd->cmd; 123 smu->cmd_buf->cmd = cmd->cmd;
@@ -440,7 +442,7 @@ int smu_present(void)
440EXPORT_SYMBOL(smu_present); 442EXPORT_SYMBOL(smu_present);
441 443
442 444
443int smu_init (void) 445int __init smu_init (void)
444{ 446{
445 struct device_node *np; 447 struct device_node *np;
446 u32 *data; 448 u32 *data;
@@ -845,16 +847,154 @@ int smu_queue_i2c(struct smu_i2c_cmd *cmd)
845 return 0; 847 return 0;
846} 848}
847 849
848struct smu_sdbp_header *smu_get_sdb_partition(int id, unsigned int *size) 850/*
851 * Handling of "partitions"
852 */
853
854static int smu_read_datablock(u8 *dest, unsigned int addr, unsigned int len)
855{
856 DECLARE_COMPLETION(comp);
857 unsigned int chunk;
858 struct smu_cmd cmd;
859 int rc;
860 u8 params[8];
861
862 /* We currently use a chunk size of 0xe. We could check the
863 * SMU firmware version and use bigger sizes though
864 */
865 chunk = 0xe;
866
867 while (len) {
868 unsigned int clen = min(len, chunk);
869
870 cmd.cmd = SMU_CMD_MISC_ee_COMMAND;
871 cmd.data_len = 7;
872 cmd.data_buf = params;
873 cmd.reply_len = chunk;
874 cmd.reply_buf = dest;
875 cmd.done = smu_done_complete;
876 cmd.misc = &comp;
877 params[0] = SMU_CMD_MISC_ee_GET_DATABLOCK_REC;
878 params[1] = 0x4;
879 *((u32 *)&params[2]) = addr;
880 params[6] = clen;
881
882 rc = smu_queue_cmd(&cmd);
883 if (rc)
884 return rc;
885 wait_for_completion(&comp);
886 if (cmd.status != 0)
887 return rc;
888 if (cmd.reply_len != clen) {
889 printk(KERN_DEBUG "SMU: short read in "
890 "smu_read_datablock, got: %d, want: %d\n",
891 cmd.reply_len, clen);
892 return -EIO;
893 }
894 len -= clen;
895 addr += clen;
896 dest += clen;
897 }
898 return 0;
899}
900
901static struct smu_sdbp_header *smu_create_sdb_partition(int id)
902{
903 DECLARE_COMPLETION(comp);
904 struct smu_simple_cmd cmd;
905 unsigned int addr, len, tlen;
906 struct smu_sdbp_header *hdr;
907 struct property *prop;
908
909 /* First query the partition info */
910 smu_queue_simple(&cmd, SMU_CMD_PARTITION_COMMAND, 2,
911 smu_done_complete, &comp,
912 SMU_CMD_PARTITION_LATEST, id);
913 wait_for_completion(&comp);
914
915 /* Partition doesn't exist (or other error) */
916 if (cmd.cmd.status != 0 || cmd.cmd.reply_len != 6)
917 return NULL;
918
919 /* Fetch address and length from reply */
920 addr = *((u16 *)cmd.buffer);
921 len = cmd.buffer[3] << 2;
922 /* Calucluate total length to allocate, including the 17 bytes
923 * for "sdb-partition-XX" that we append at the end of the buffer
924 */
925 tlen = sizeof(struct property) + len + 18;
926
927 prop = kcalloc(tlen, 1, GFP_KERNEL);
928 if (prop == NULL)
929 return NULL;
930 hdr = (struct smu_sdbp_header *)(prop + 1);
931 prop->name = ((char *)prop) + tlen - 18;
932 sprintf(prop->name, "sdb-partition-%02x", id);
933 prop->length = len;
934 prop->value = (unsigned char *)hdr;
935 prop->next = NULL;
936
937 /* Read the datablock */
938 if (smu_read_datablock((u8 *)hdr, addr, len)) {
939 printk(KERN_DEBUG "SMU: datablock read failed while reading "
940 "partition %02x !\n", id);
941 goto failure;
942 }
943
944 /* Got it, check a few things and create the property */
945 if (hdr->id != id) {
946 printk(KERN_DEBUG "SMU: Reading partition %02x and got "
947 "%02x !\n", id, hdr->id);
948 goto failure;
949 }
950 if (prom_add_property(smu->of_node, prop)) {
951 printk(KERN_DEBUG "SMU: Failed creating sdb-partition-%02x "
952 "property !\n", id);
953 goto failure;
954 }
955
956 return hdr;
957 failure:
958 kfree(prop);
959 return NULL;
960}
961
962/* Note: Only allowed to return error code in pointers (using ERR_PTR)
963 * when interruptible is 1
964 */
965struct smu_sdbp_header *__smu_get_sdb_partition(int id, unsigned int *size,
966 int interruptible)
849{ 967{
850 char pname[32]; 968 char pname[32];
969 struct smu_sdbp_header *part;
851 970
852 if (!smu) 971 if (!smu)
853 return NULL; 972 return NULL;
854 973
855 sprintf(pname, "sdb-partition-%02x", id); 974 sprintf(pname, "sdb-partition-%02x", id);
856 return (struct smu_sdbp_header *)get_property(smu->of_node, 975
976 if (interruptible) {
977 int rc;
978 rc = down_interruptible(&smu_part_access);
979 if (rc)
980 return ERR_PTR(rc);
981 } else
982 down(&smu_part_access);
983
984 part = (struct smu_sdbp_header *)get_property(smu->of_node,
857 pname, size); 985 pname, size);
986 if (part == NULL) {
987 part = smu_create_sdb_partition(id);
988 if (part != NULL && size)
989 *size = part->len << 2;
990 }
991 up(&smu_part_access);
992 return part;
993}
994
995struct smu_sdbp_header *smu_get_sdb_partition(int id, unsigned int *size)
996{
997 return __smu_get_sdb_partition(id, size, 0);
858} 998}
859EXPORT_SYMBOL(smu_get_sdb_partition); 999EXPORT_SYMBOL(smu_get_sdb_partition);
860 1000
@@ -930,6 +1070,14 @@ static ssize_t smu_write(struct file *file, const char __user *buf,
930 else if (hdr.cmdtype == SMU_CMDTYPE_WANTS_EVENTS) { 1070 else if (hdr.cmdtype == SMU_CMDTYPE_WANTS_EVENTS) {
931 pp->mode = smu_file_events; 1071 pp->mode = smu_file_events;
932 return 0; 1072 return 0;
1073 } else if (hdr.cmdtype == SMU_CMDTYPE_GET_PARTITION) {
1074 struct smu_sdbp_header *part;
1075 part = __smu_get_sdb_partition(hdr.cmd, NULL, 1);
1076 if (part == NULL)
1077 return -EINVAL;
1078 else if (IS_ERR(part))
1079 return PTR_ERR(part);
1080 return 0;
933 } else if (hdr.cmdtype != SMU_CMDTYPE_SMU) 1081 } else if (hdr.cmdtype != SMU_CMDTYPE_SMU)
934 return -EINVAL; 1082 return -EINVAL;
935 else if (pp->mode != smu_file_commands) 1083 else if (pp->mode != smu_file_commands)
diff --git a/fs/proc/proc_devtree.c b/fs/proc/proc_devtree.c
index 6fd57f154197..fb117b74809e 100644
--- a/fs/proc/proc_devtree.c
+++ b/fs/proc/proc_devtree.c
@@ -49,6 +49,39 @@ static int property_read_proc(char *page, char **start, off_t off,
49 */ 49 */
50 50
51/* 51/*
52 * Add a property to a node
53 */
54static struct proc_dir_entry *
55__proc_device_tree_add_prop(struct proc_dir_entry *de, struct property *pp)
56{
57 struct proc_dir_entry *ent;
58
59 /*
60 * Unfortunately proc_register puts each new entry
61 * at the beginning of the list. So we rearrange them.
62 */
63 ent = create_proc_read_entry(pp->name,
64 strncmp(pp->name, "security-", 9)
65 ? S_IRUGO : S_IRUSR, de,
66 property_read_proc, pp);
67 if (ent == NULL)
68 return NULL;
69
70 if (!strncmp(pp->name, "security-", 9))
71 ent->size = 0; /* don't leak number of password chars */
72 else
73 ent->size = pp->length;
74
75 return ent;
76}
77
78
79void proc_device_tree_add_prop(struct proc_dir_entry *pde, struct property *prop)
80{
81 __proc_device_tree_add_prop(pde, prop);
82}
83
84/*
52 * Process a node, adding entries for its children and its properties. 85 * Process a node, adding entries for its children and its properties.
53 */ 86 */
54void proc_device_tree_add_node(struct device_node *np, 87void proc_device_tree_add_node(struct device_node *np,
@@ -57,11 +90,9 @@ void proc_device_tree_add_node(struct device_node *np,
57 struct property *pp; 90 struct property *pp;
58 struct proc_dir_entry *ent; 91 struct proc_dir_entry *ent;
59 struct device_node *child; 92 struct device_node *child;
60 struct proc_dir_entry *list = NULL, **lastp;
61 const char *p; 93 const char *p;
62 94
63 set_node_proc_entry(np, de); 95 set_node_proc_entry(np, de);
64 lastp = &list;
65 for (child = NULL; (child = of_get_next_child(np, child));) { 96 for (child = NULL; (child = of_get_next_child(np, child));) {
66 p = strrchr(child->full_name, '/'); 97 p = strrchr(child->full_name, '/');
67 if (!p) 98 if (!p)
@@ -71,9 +102,6 @@ void proc_device_tree_add_node(struct device_node *np,
71 ent = proc_mkdir(p, de); 102 ent = proc_mkdir(p, de);
72 if (ent == 0) 103 if (ent == 0)
73 break; 104 break;
74 *lastp = ent;
75 ent->next = NULL;
76 lastp = &ent->next;
77 proc_device_tree_add_node(child, ent); 105 proc_device_tree_add_node(child, ent);
78 } 106 }
79 of_node_put(child); 107 of_node_put(child);
@@ -84,7 +112,7 @@ void proc_device_tree_add_node(struct device_node *np,
84 * properties are quite unimportant for us though, thus we 112 * properties are quite unimportant for us though, thus we
85 * simply "skip" them here, but we do have to check. 113 * simply "skip" them here, but we do have to check.
86 */ 114 */
87 for (ent = list; ent != NULL; ent = ent->next) 115 for (ent = de->subdir; ent != NULL; ent = ent->next)
88 if (!strcmp(ent->name, pp->name)) 116 if (!strcmp(ent->name, pp->name))
89 break; 117 break;
90 if (ent != NULL) { 118 if (ent != NULL) {
@@ -94,25 +122,10 @@ void proc_device_tree_add_node(struct device_node *np,
94 continue; 122 continue;
95 } 123 }
96 124
97 /* 125 ent = __proc_device_tree_add_prop(de, pp);
98 * Unfortunately proc_register puts each new entry
99 * at the beginning of the list. So we rearrange them.
100 */
101 ent = create_proc_read_entry(pp->name,
102 strncmp(pp->name, "security-", 9)
103 ? S_IRUGO : S_IRUSR, de,
104 property_read_proc, pp);
105 if (ent == 0) 126 if (ent == 0)
106 break; 127 break;
107 if (!strncmp(pp->name, "security-", 9))
108 ent->size = 0; /* don't leak number of password chars */
109 else
110 ent->size = pp->length;
111 ent->next = NULL;
112 *lastp = ent;
113 lastp = &ent->next;
114 } 128 }
115 de->subdir = list;
116} 129}
117 130
118/* 131/*
diff --git a/include/asm-powerpc/prom.h b/include/asm-powerpc/prom.h
index 7587bf5f38c6..f999df1c5c90 100644
--- a/include/asm-powerpc/prom.h
+++ b/include/asm-powerpc/prom.h
@@ -203,7 +203,7 @@ extern int prom_n_addr_cells(struct device_node* np);
203extern int prom_n_size_cells(struct device_node* np); 203extern int prom_n_size_cells(struct device_node* np);
204extern int prom_n_intr_cells(struct device_node* np); 204extern int prom_n_intr_cells(struct device_node* np);
205extern void prom_get_irq_senses(unsigned char *senses, int off, int max); 205extern void prom_get_irq_senses(unsigned char *senses, int off, int max);
206extern void prom_add_property(struct device_node* np, struct property* prop); 206extern int prom_add_property(struct device_node* np, struct property* prop);
207 207
208#ifdef CONFIG_PPC32 208#ifdef CONFIG_PPC32
209/* 209/*
diff --git a/include/asm-powerpc/smu.h b/include/asm-powerpc/smu.h
index 959bad660233..76c29a9784dd 100644
--- a/include/asm-powerpc/smu.h
+++ b/include/asm-powerpc/smu.h
@@ -20,16 +20,52 @@
20/* 20/*
21 * Partition info commands 21 * Partition info commands
22 * 22 *
23 * I do not know what those are for at this point 23 * These commands are used to retreive the sdb-partition-XX datas from
24 * the SMU. The lenght is always 2. First byte is the subcommand code
25 * and second byte is the partition ID.
26 *
27 * The reply is 6 bytes:
28 *
29 * - 0..1 : partition address
30 * - 2 : a byte containing the partition ID
31 * - 3 : length (maybe other bits are rest of header ?)
32 *
33 * The data must then be obtained with calls to another command:
34 * SMU_CMD_MISC_ee_GET_DATABLOCK_REC (described below).
24 */ 35 */
25#define SMU_CMD_PARTITION_COMMAND 0x3e 36#define SMU_CMD_PARTITION_COMMAND 0x3e
37#define SMU_CMD_PARTITION_LATEST 0x01
38#define SMU_CMD_PARTITION_BASE 0x02
39#define SMU_CMD_PARTITION_UPDATE 0x03
26 40
27 41
28/* 42/*
29 * Fan control 43 * Fan control
30 * 44 *
31 * This is a "mux" for fan control commands, first byte is the 45 * This is a "mux" for fan control commands. The command seem to
32 * "sub" command. 46 * act differently based on the number of arguments. With 1 byte
47 * of argument, this seem to be queries for fans status, setpoint,
48 * etc..., while with 0xe arguments, we will set the fans speeds.
49 *
50 * Queries (1 byte arg):
51 * ---------------------
52 *
53 * arg=0x01: read RPM fans status
54 * arg=0x02: read RPM fans setpoint
55 * arg=0x11: read PWM fans status
56 * arg=0x12: read PWM fans setpoint
57 *
58 * the "status" queries return the current speed while the "setpoint" ones
59 * return the programmed/target speed. It _seems_ that the result is a bit
60 * mask in the first byte of active/available fans, followed by 6 words (16
61 * bits) containing the requested speed.
62 *
63 * Setpoint (14 bytes arg):
64 * ------------------------
65 *
66 * first arg byte is 0 for RPM fans and 0x10 for PWM. Second arg byte is the
67 * mask of fans affected by the command. Followed by 6 words containing the
68 * setpoint value for selected fans in the mask (or 0 if mask value is 0)
33 */ 69 */
34#define SMU_CMD_FAN_COMMAND 0x4a 70#define SMU_CMD_FAN_COMMAND 0x4a
35 71
@@ -156,6 +192,14 @@
156#define SMU_CMD_POWER_SHUTDOWN "SHUTDOWN" 192#define SMU_CMD_POWER_SHUTDOWN "SHUTDOWN"
157#define SMU_CMD_POWER_VOLTAGE_SLEW "VSLEW" 193#define SMU_CMD_POWER_VOLTAGE_SLEW "VSLEW"
158 194
195/*
196 * Read ADC sensors
197 *
198 * This command takes one byte of parameter: the sensor ID (or "reg"
199 * value in the device-tree) and returns a 16 bits value
200 */
201#define SMU_CMD_READ_ADC 0xd8
202
159/* Misc commands 203/* Misc commands
160 * 204 *
161 * This command seem to be a grab bag of various things 205 * This command seem to be a grab bag of various things
@@ -176,6 +220,25 @@
176 * Misc commands 220 * Misc commands
177 * 221 *
178 * This command seem to be a grab bag of various things 222 * This command seem to be a grab bag of various things
223 *
224 * SMU_CMD_MISC_ee_GET_DATABLOCK_REC is used, among others, to
225 * transfer blocks of data from the SMU. So far, I've decrypted it's
226 * usage to retreive partition data. In order to do that, you have to
227 * break your transfer in "chunks" since that command cannot transfer
228 * more than a chunk at a time. The chunk size used by OF is 0xe bytes,
229 * but it seems that the darwin driver will let you do 0x1e bytes if
230 * your "PMU" version is >= 0x30. You can get the "PMU" version apparently
231 * either in the last 16 bits of property "smu-version-pmu" or as the 16
232 * bytes at offset 1 of "smu-version-info"
233 *
234 * For each chunk, the command takes 7 bytes of arguments:
235 * byte 0: subcommand code (0x02)
236 * byte 1: 0x04 (always, I don't know what it means, maybe the address
237 * space to use or some other nicety. It's hard coded in OF)
238 * byte 2..5: SMU address of the chunk (big endian 32 bits)
239 * byte 6: size to transfer (up to max chunk size)
240 *
241 * The data is returned directly
179 */ 242 */
180#define SMU_CMD_MISC_ee_COMMAND 0xee 243#define SMU_CMD_MISC_ee_COMMAND 0xee
181#define SMU_CMD_MISC_ee_GET_DATABLOCK_REC 0x02 244#define SMU_CMD_MISC_ee_GET_DATABLOCK_REC 0x02
@@ -353,21 +416,26 @@ struct smu_sdbp_header {
353 __u8 flags; 416 __u8 flags;
354}; 417};
355 418
356/* 419
357 * 32 bits integers are usually encoded with 2x16 bits swapped, 420 /*
358 * this demangles them 421 * demangle 16 and 32 bits integer in some SMU partitions
422 * (currently, afaik, this concerns only the FVT partition
423 * (0x12)
359 */ 424 */
360#define SMU_U32_MIX(x) ((((x) << 16) & 0xffff0000u) | (((x) >> 16) & 0xffffu)) 425#define SMU_U16_MIX(x) le16_to_cpu(x);
426#define SMU_U32_MIX(x) ((((x) & 0xff00ff00u) >> 8)|(((x) & 0x00ff00ffu) << 8))
427
361 428
362/* This is the definition of the SMU sdb-partition-0x12 table (called 429/* This is the definition of the SMU sdb-partition-0x12 table (called
363 * CPU F/V/T operating points in Darwin). The definition for all those 430 * CPU F/V/T operating points in Darwin). The definition for all those
364 * SMU tables should be moved to some separate file 431 * SMU tables should be moved to some separate file
365 */ 432 */
366#define SMU_SDB_FVT_ID 0x12 433#define SMU_SDB_FVT_ID 0x12
367 434
368struct smu_sdbp_fvt { 435struct smu_sdbp_fvt {
369 __u32 sysclk; /* Base SysClk frequency in Hz for 436 __u32 sysclk; /* Base SysClk frequency in Hz for
370 * this operating point 437 * this operating point. Value need to
438 * be unmixed with SMU_U32_MIX()
371 */ 439 */
372 __u8 pad; 440 __u8 pad;
373 __u8 maxtemp; /* Max temp. supported by this 441 __u8 maxtemp; /* Max temp. supported by this
@@ -376,10 +444,73 @@ struct smu_sdbp_fvt {
376 444
377 __u16 volts[3]; /* CPU core voltage for the 3 445 __u16 volts[3]; /* CPU core voltage for the 3
378 * PowerTune modes, a mode with 446 * PowerTune modes, a mode with
379 * 0V = not supported. 447 * 0V = not supported. Value need
448 * to be unmixed with SMU_U16_MIX()
380 */ 449 */
381}; 450};
382 451
452/* This partition contains voltage & current sensor calibration
453 * informations
454 */
455#define SMU_SDB_CPUVCP_ID 0x21
456
457struct smu_sdbp_cpuvcp {
458 __u16 volt_scale; /* u4.12 fixed point */
459 __s16 volt_offset; /* s4.12 fixed point */
460 __u16 curr_scale; /* u4.12 fixed point */
461 __s16 curr_offset; /* s4.12 fixed point */
462 __s32 power_quads[3]; /* s4.28 fixed point */
463};
464
465/* This partition contains CPU thermal diode calibration
466 */
467#define SMU_SDB_CPUDIODE_ID 0x18
468
469struct smu_sdbp_cpudiode {
470 __u16 m_value; /* u1.15 fixed point */
471 __s16 b_value; /* s10.6 fixed point */
472
473};
474
475/* This partition contains Slots power calibration
476 */
477#define SMU_SDB_SLOTSPOW_ID 0x78
478
479struct smu_sdbp_slotspow {
480 __u16 pow_scale; /* u4.12 fixed point */
481 __s16 pow_offset; /* s4.12 fixed point */
482};
483
484/* This partition contains machine specific version information about
485 * the sensor/control layout
486 */
487#define SMU_SDB_SENSORTREE_ID 0x25
488
489struct smu_sdbp_sensortree {
490 u8 model_id;
491 u8 unknown[3];
492};
493
494/* This partition contains CPU thermal control PID informations. So far
495 * only single CPU machines have been seen with an SMU, so we assume this
496 * carries only informations for those
497 */
498#define SMU_SDB_CPUPIDDATA_ID 0x17
499
500struct smu_sdbp_cpupiddata {
501 u8 unknown1;
502 u8 target_temp_delta;
503 u8 unknown2;
504 u8 history_len;
505 s16 power_adj;
506 u16 max_power;
507 s32 gp,gr,gd;
508};
509
510
511/* Other partitions without known structures */
512#define SMU_SDB_DEBUG_SWITCHES_ID 0x05
513
383#ifdef __KERNEL__ 514#ifdef __KERNEL__
384/* 515/*
385 * This returns the pointer to an SMU "sdb" partition data or NULL 516 * This returns the pointer to an SMU "sdb" partition data or NULL
@@ -423,8 +554,10 @@ struct smu_user_cmd_hdr
423 __u32 cmdtype; 554 __u32 cmdtype;
424#define SMU_CMDTYPE_SMU 0 /* SMU command */ 555#define SMU_CMDTYPE_SMU 0 /* SMU command */
425#define SMU_CMDTYPE_WANTS_EVENTS 1 /* switch fd to events mode */ 556#define SMU_CMDTYPE_WANTS_EVENTS 1 /* switch fd to events mode */
557#define SMU_CMDTYPE_GET_PARTITION 2 /* retreive an sdb partition */
426 558
427 __u8 cmd; /* SMU command byte */ 559 __u8 cmd; /* SMU command byte */
560 __u8 pad[3]; /* padding */
428 __u32 data_len; /* Lenght of data following */ 561 __u32 data_len; /* Lenght of data following */
429}; 562};
430 563
diff --git a/include/asm-ppc/prom.h b/include/asm-ppc/prom.h
index 75c0637acdc8..3e39827ed566 100644
--- a/include/asm-ppc/prom.h
+++ b/include/asm-ppc/prom.h
@@ -93,7 +93,7 @@ extern int device_is_compatible(struct device_node *device, const char *);
93extern int machine_is_compatible(const char *compat); 93extern int machine_is_compatible(const char *compat);
94extern unsigned char *get_property(struct device_node *node, const char *name, 94extern unsigned char *get_property(struct device_node *node, const char *name,
95 int *lenp); 95 int *lenp);
96extern void prom_add_property(struct device_node* np, struct property* prop); 96extern int prom_add_property(struct device_node* np, struct property* prop);
97extern void prom_get_irq_senses(unsigned char *, int, int); 97extern void prom_get_irq_senses(unsigned char *, int, int);
98extern int prom_n_addr_cells(struct device_node* np); 98extern int prom_n_addr_cells(struct device_node* np);
99extern int prom_n_size_cells(struct device_node* np); 99extern int prom_n_size_cells(struct device_node* np);
diff --git a/include/asm-ppc64/prom.h b/include/asm-ppc64/prom.h
index bdb47174ff0e..76bb0266d67c 100644
--- a/include/asm-ppc64/prom.h
+++ b/include/asm-ppc64/prom.h
@@ -213,6 +213,6 @@ extern int prom_n_addr_cells(struct device_node* np);
213extern int prom_n_size_cells(struct device_node* np); 213extern int prom_n_size_cells(struct device_node* np);
214extern int prom_n_intr_cells(struct device_node* np); 214extern int prom_n_intr_cells(struct device_node* np);
215extern void prom_get_irq_senses(unsigned char *senses, int off, int max); 215extern void prom_get_irq_senses(unsigned char *senses, int off, int max);
216extern void prom_add_property(struct device_node* np, struct property* prop); 216extern int prom_add_property(struct device_node* np, struct property* prop);
217 217
218#endif /* _PPC64_PROM_H */ 218#endif /* _PPC64_PROM_H */
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
index 0563581e3a02..65ceeaa30652 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -139,15 +139,12 @@ extern void proc_tty_unregister_driver(struct tty_driver *driver);
139/* 139/*
140 * proc_devtree.c 140 * proc_devtree.c
141 */ 141 */
142#ifdef CONFIG_PROC_DEVICETREE
142struct device_node; 143struct device_node;
144struct property;
143extern void proc_device_tree_init(void); 145extern void proc_device_tree_init(void);
144#ifdef CONFIG_PROC_DEVICETREE
145extern void proc_device_tree_add_node(struct device_node *, struct proc_dir_entry *); 146extern void proc_device_tree_add_node(struct device_node *, struct proc_dir_entry *);
146#else /* !CONFIG_PROC_DEVICETREE */ 147extern void proc_device_tree_add_prop(struct proc_dir_entry *pde, struct property *prop);
147static inline void proc_device_tree_add_node(struct device_node *np, struct proc_dir_entry *pde)
148{
149 return;
150}
151#endif /* CONFIG_PROC_DEVICETREE */ 148#endif /* CONFIG_PROC_DEVICETREE */
152 149
153extern struct proc_dir_entry *proc_symlink(const char *, 150extern struct proc_dir_entry *proc_symlink(const char *,