aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
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 /drivers
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>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/macintosh/smu.c164
1 files changed, 156 insertions, 8 deletions
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)