diff options
| -rw-r--r-- | arch/powerpc/kernel/prom.c | 21 | ||||
| -rw-r--r-- | arch/ppc/syslib/prom.c | 4 | ||||
| -rw-r--r-- | arch/ppc64/kernel/prom.c | 24 | ||||
| -rw-r--r-- | drivers/macintosh/smu.c | 164 | ||||
| -rw-r--r-- | fs/proc/proc_devtree.c | 57 | ||||
| -rw-r--r-- | include/asm-powerpc/prom.h | 2 | ||||
| -rw-r--r-- | include/asm-powerpc/smu.h | 153 | ||||
| -rw-r--r-- | include/asm-ppc/prom.h | 2 | ||||
| -rw-r--r-- | include/asm-ppc64/prom.h | 2 | ||||
| -rw-r--r-- | include/linux/proc_fs.h | 9 |
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 | */ |
| 1977 | void prom_add_property(struct device_node* np, struct property* prop) | 1977 | int 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 | */ |
| 1168 | void | 1168 | int |
| 1169 | prom_add_property(struct device_node* np, struct property* prop) | 1169 | prom_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) | |||
| 1865 | EXPORT_SYMBOL(get_property); | 1866 | EXPORT_SYMBOL(get_property); |
| 1866 | 1867 | ||
| 1867 | /* | 1868 | /* |
| 1868 | * Add a property to a node | 1869 | * Add a property to a node. |
| 1869 | */ | 1870 | */ |
| 1870 | void | 1871 | int |
| 1871 | prom_add_property(struct device_node* np, struct property* prop) | 1872 | prom_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 | */ |
| 94 | static struct smu_device *smu; | 94 | static struct smu_device *smu; |
| 95 | 95 | static 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) | |||
| 440 | EXPORT_SYMBOL(smu_present); | 442 | EXPORT_SYMBOL(smu_present); |
| 441 | 443 | ||
| 442 | 444 | ||
| 443 | int smu_init (void) | 445 | int __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 | ||
| 848 | struct smu_sdbp_header *smu_get_sdb_partition(int id, unsigned int *size) | 850 | /* |
| 851 | * Handling of "partitions" | ||
| 852 | */ | ||
| 853 | |||
| 854 | static 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 = ∁ | ||
| 877 | params[0] = SMU_CMD_MISC_ee_GET_DATABLOCK_REC; | ||
| 878 | params[1] = 0x4; | ||
| 879 | *((u32 *)¶ms[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 | |||
| 901 | static 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 | */ | ||
| 965 | struct 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 | |||
| 995 | struct smu_sdbp_header *smu_get_sdb_partition(int id, unsigned int *size) | ||
| 996 | { | ||
| 997 | return __smu_get_sdb_partition(id, size, 0); | ||
| 858 | } | 998 | } |
| 859 | EXPORT_SYMBOL(smu_get_sdb_partition); | 999 | EXPORT_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 | */ | ||
| 54 | static 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 | |||
| 79 | void 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 | */ |
| 54 | void proc_device_tree_add_node(struct device_node *np, | 87 | void 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); | |||
| 203 | extern int prom_n_size_cells(struct device_node* np); | 203 | extern int prom_n_size_cells(struct device_node* np); |
| 204 | extern int prom_n_intr_cells(struct device_node* np); | 204 | extern int prom_n_intr_cells(struct device_node* np); |
| 205 | extern void prom_get_irq_senses(unsigned char *senses, int off, int max); | 205 | extern void prom_get_irq_senses(unsigned char *senses, int off, int max); |
| 206 | extern void prom_add_property(struct device_node* np, struct property* prop); | 206 | extern 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 | ||
| 368 | struct smu_sdbp_fvt { | 435 | struct 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 | |||
| 457 | struct 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 | |||
| 469 | struct 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 | |||
| 479 | struct 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 | |||
| 489 | struct 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 | |||
| 500 | struct 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 *); | |||
| 93 | extern int machine_is_compatible(const char *compat); | 93 | extern int machine_is_compatible(const char *compat); |
| 94 | extern unsigned char *get_property(struct device_node *node, const char *name, | 94 | extern unsigned char *get_property(struct device_node *node, const char *name, |
| 95 | int *lenp); | 95 | int *lenp); |
| 96 | extern void prom_add_property(struct device_node* np, struct property* prop); | 96 | extern int prom_add_property(struct device_node* np, struct property* prop); |
| 97 | extern void prom_get_irq_senses(unsigned char *, int, int); | 97 | extern void prom_get_irq_senses(unsigned char *, int, int); |
| 98 | extern int prom_n_addr_cells(struct device_node* np); | 98 | extern int prom_n_addr_cells(struct device_node* np); |
| 99 | extern int prom_n_size_cells(struct device_node* np); | 99 | extern 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); | |||
| 213 | extern int prom_n_size_cells(struct device_node* np); | 213 | extern int prom_n_size_cells(struct device_node* np); |
| 214 | extern int prom_n_intr_cells(struct device_node* np); | 214 | extern int prom_n_intr_cells(struct device_node* np); |
| 215 | extern void prom_get_irq_senses(unsigned char *senses, int off, int max); | 215 | extern void prom_get_irq_senses(unsigned char *senses, int off, int max); |
| 216 | extern void prom_add_property(struct device_node* np, struct property* prop); | 216 | extern 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 | ||
| 142 | struct device_node; | 143 | struct device_node; |
| 144 | struct property; | ||
| 143 | extern void proc_device_tree_init(void); | 145 | extern void proc_device_tree_init(void); |
| 144 | #ifdef CONFIG_PROC_DEVICETREE | ||
| 145 | extern void proc_device_tree_add_node(struct device_node *, struct proc_dir_entry *); | 146 | extern void proc_device_tree_add_node(struct device_node *, struct proc_dir_entry *); |
| 146 | #else /* !CONFIG_PROC_DEVICETREE */ | 147 | extern void proc_device_tree_add_prop(struct proc_dir_entry *pde, struct property *prop); |
| 147 | static 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 | ||
| 153 | extern struct proc_dir_entry *proc_symlink(const char *, | 150 | extern struct proc_dir_entry *proc_symlink(const char *, |
