Commit 183d0202 authored by Benjamin Herrenschmidt's avatar Benjamin Herrenschmidt Committed by Paul Mackerras

[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: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
parent 4350147a
...@@ -1974,14 +1974,29 @@ EXPORT_SYMBOL(get_property); ...@@ -1974,14 +1974,29 @@ EXPORT_SYMBOL(get_property);
/* /*
* Add a property to a node * 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; 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 = &(*next)->next;
}
*next = prop; *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 ! */ /* I quickly hacked that one, check against spec ! */
......
...@@ -1165,7 +1165,7 @@ get_property(struct device_node *np, const char *name, int *lenp) ...@@ -1165,7 +1165,7 @@ get_property(struct device_node *np, const char *name, int *lenp)
/* /*
* Add a property to a node * Add a property to a node
*/ */
void int
prom_add_property(struct device_node* np, struct property* prop) prom_add_property(struct device_node* np, struct property* prop)
{ {
struct property **next = &np->properties; struct property **next = &np->properties;
...@@ -1174,6 +1174,8 @@ prom_add_property(struct device_node* np, struct property* prop) ...@@ -1174,6 +1174,8 @@ prom_add_property(struct device_node* np, struct property* prop)
while (*next) while (*next)
next = &(*next)->next; next = &(*next)->next;
*next = prop; *next = prop;
return 0;
} }
/* I quickly hacked that one, check against spec ! */ /* I quickly hacked that one, check against spec ! */
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include <linux/initrd.h> #include <linux/initrd.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/module.h>
#include <asm/prom.h> #include <asm/prom.h>
#include <asm/rtas.h> #include <asm/rtas.h>
...@@ -1865,17 +1866,32 @@ get_property(struct device_node *np, const char *name, int *lenp) ...@@ -1865,17 +1866,32 @@ get_property(struct device_node *np, const char *name, int *lenp)
EXPORT_SYMBOL(get_property); 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) prom_add_property(struct device_node* np, struct property* prop)
{ {
struct property **next = &np->properties; struct property **next;
prop->next = NULL; 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 = &(*next)->next;
}
*next = prop; *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 #if 0
......
...@@ -47,13 +47,13 @@ ...@@ -47,13 +47,13 @@
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/of_device.h> #include <asm/of_device.h>
#define VERSION "0.6" #define VERSION "0.7"
#define AUTHOR "(c) 2005 Benjamin Herrenschmidt, IBM Corp." #define AUTHOR "(c) 2005 Benjamin Herrenschmidt, IBM Corp."
#undef DEBUG_SMU #undef DEBUG_SMU
#ifdef 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 #else
#define DPRINTK(fmt, args...) do { } while (0) #define DPRINTK(fmt, args...) do { } while (0)
#endif #endif
...@@ -92,7 +92,7 @@ struct smu_device { ...@@ -92,7 +92,7 @@ struct smu_device {
* for now, just hard code that * for now, just hard code that
*/ */
static struct smu_device *smu; static struct smu_device *smu;
static DECLARE_MUTEX(smu_part_access);
/* /*
* SMU driver low level stuff * SMU driver low level stuff
...@@ -113,9 +113,11 @@ static void smu_start_cmd(void) ...@@ -113,9 +113,11 @@ static void smu_start_cmd(void)
DPRINTK("SMU: starting cmd %x, %d bytes data\n", cmd->cmd, DPRINTK("SMU: starting cmd %x, %d bytes data\n", cmd->cmd,
cmd->data_len); 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)[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 */ /* Fill the SMU command buffer */
smu->cmd_buf->cmd = cmd->cmd; smu->cmd_buf->cmd = cmd->cmd;
...@@ -440,7 +442,7 @@ int smu_present(void) ...@@ -440,7 +442,7 @@ int smu_present(void)
EXPORT_SYMBOL(smu_present); EXPORT_SYMBOL(smu_present);
int smu_init (void) int __init smu_init (void)
{ {
struct device_node *np; struct device_node *np;
u32 *data; u32 *data;
...@@ -845,16 +847,154 @@ int smu_queue_i2c(struct smu_i2c_cmd *cmd) ...@@ -845,16 +847,154 @@ int smu_queue_i2c(struct smu_i2c_cmd *cmd)
return 0; 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]; char pname[32];
struct smu_sdbp_header *part;
if (!smu) if (!smu)
return NULL; return NULL;
sprintf(pname, "sdb-partition-%02x", id); 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); 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); EXPORT_SYMBOL(smu_get_sdb_partition);
...@@ -930,6 +1070,14 @@ static ssize_t smu_write(struct file *file, const char __user *buf, ...@@ -930,6 +1070,14 @@ static ssize_t smu_write(struct file *file, const char __user *buf,
else if (hdr.cmdtype == SMU_CMDTYPE_WANTS_EVENTS) { else if (hdr.cmdtype == SMU_CMDTYPE_WANTS_EVENTS) {
pp->mode = smu_file_events; pp->mode = smu_file_events;
return 0; 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) } else if (hdr.cmdtype != SMU_CMDTYPE_SMU)
return -EINVAL; return -EINVAL;
else if (pp->mode != smu_file_commands) else if (pp->mode != smu_file_commands)
......
...@@ -48,6 +48,39 @@ static int property_read_proc(char *page, char **start, off_t off, ...@@ -48,6 +48,39 @@ static int property_read_proc(char *page, char **start, off_t off,
* and "@10" to it. * and "@10" to it.
*/ */
/*
* 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. * Process a node, adding entries for its children and its properties.
*/ */
...@@ -57,11 +90,9 @@ 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 property *pp;
struct proc_dir_entry *ent; struct proc_dir_entry *ent;
struct device_node *child; struct device_node *child;
struct proc_dir_entry *list = NULL, **lastp;
const char *p; const char *p;
set_node_proc_entry(np, de); set_node_proc_entry(np, de);
lastp = &list;
for (child = NULL; (child = of_get_next_child(np, child));) { for (child = NULL; (child = of_get_next_child(np, child));) {
p = strrchr(child->full_name, '/'); p = strrchr(child->full_name, '/');
if (!p) if (!p)
...@@ -71,9 +102,6 @@ void proc_device_tree_add_node(struct device_node *np, ...@@ -71,9 +102,6 @@ void proc_device_tree_add_node(struct device_node *np,
ent = proc_mkdir(p, de); ent = proc_mkdir(p, de);
if (ent == 0) if (ent == 0)
break; break;
*lastp = ent;
ent->next = NULL;
lastp = &ent->next;
proc_device_tree_add_node(child, ent); proc_device_tree_add_node(child, ent);
} }
of_node_put(child); of_node_put(child);
...@@ -84,7 +112,7 @@ void proc_device_tree_add_node(struct device_node *np, ...@@ -84,7 +112,7 @@ void proc_device_tree_add_node(struct device_node *np,
* properties are quite unimportant for us though, thus we * properties are quite unimportant for us though, thus we
* simply "skip" them here, but we do have to check. * 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)) if (!strcmp(ent->name, pp->name))
break; break;
if (ent != NULL) { if (ent != NULL) {
...@@ -94,25 +122,10 @@ void proc_device_tree_add_node(struct device_node *np, ...@@ -94,25 +122,10 @@ void proc_device_tree_add_node(struct device_node *np,
continue; continue;
} }
/* ent = __proc_device_tree_add_prop(de, pp);
* 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 == 0) if (ent == 0)
break; 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;
} }
/* /*
......
...@@ -203,7 +203,7 @@ extern int prom_n_addr_cells(struct device_node* np); ...@@ -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_size_cells(struct device_node* np);
extern int prom_n_intr_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_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 #ifdef CONFIG_PPC32
/* /*
......
...@@ -20,16 +20,52 @@ ...@@ -20,16 +20,52 @@
/* /*
* Partition info commands * 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_COMMAND 0x3e
#define SMU_CMD_PARTITION_LATEST 0x01
#define SMU_CMD_PARTITION_BASE 0x02
#define SMU_CMD_PARTITION_UPDATE 0x03
/* /*
* Fan control * Fan control
* *
* This is a "mux" for fan control commands, first byte is the * This is a "mux" for fan control commands. The command seem to
* "sub" command. * 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_FAN_COMMAND 0x4a
...@@ -156,6 +192,14 @@ ...@@ -156,6 +192,14 @@
#define SMU_CMD_POWER_SHUTDOWN "SHUTDOWN" #define SMU_CMD_POWER_SHUTDOWN "SHUTDOWN"
#define SMU_CMD_POWER_VOLTAGE_SLEW "VSLEW" #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 /* Misc commands
* *
* This command seem to be a grab bag of various things * This command seem to be a grab bag of various things
...@@ -176,6 +220,25 @@ ...@@ -176,6 +220,25 @@
* Misc commands * Misc commands
* *
* This command seem to be a grab bag of various things * 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_COMMAND 0xee
#define SMU_CMD_MISC_ee_GET_DATABLOCK_REC 0x02 #define SMU_CMD_MISC_ee_GET_DATABLOCK_REC 0x02
...@@ -353,21 +416,26 @@ struct smu_sdbp_header { ...@@ -353,21 +416,26 @@ struct smu_sdbp_header {
__u8 flags; __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 /* 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 * CPU F/V/T operating points in Darwin). The definition for all those
* SMU tables should be moved to some separate file * 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 { struct smu_sdbp_fvt {
__u32 sysclk; /* Base SysClk frequency in Hz for __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 pad;
__u8 maxtemp; /* Max temp. supported by this __u8 maxtemp; /* Max temp. supported by this
...@@ -376,10 +444,73 @@ struct smu_sdbp_fvt { ...@@ -376,10 +444,73 @@ struct smu_sdbp_fvt {
__u16 volts[3]; /* CPU core voltage for the 3 __u16 volts[3]; /* CPU core voltage for the 3
* PowerTune modes, a mode with * 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__ #ifdef __KERNEL__
/* /*
* This returns the pointer to an SMU "sdb" partition data or NULL * This returns the pointer to an SMU "sdb" partition data or NULL
...@@ -423,8 +554,10 @@ struct smu_user_cmd_hdr ...@@ -423,8 +554,10 @@ struct smu_user_cmd_hdr
__u32 cmdtype; __u32 cmdtype;
#define SMU_CMDTYPE_SMU 0 /* SMU command */ #define SMU_CMDTYPE_SMU 0 /* SMU command */
#define SMU_CMDTYPE_WANTS_EVENTS 1 /* switch fd to events mode */ #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 cmd; /* SMU command byte */
__u8 pad[3]; /* padding */
__u32 data_len; /* Lenght of data following */ __u32 data_len; /* Lenght of data following */
}; };
......
...@@ -93,7 +93,7 @@ extern int device_is_compatible(struct device_node *device, const char *); ...@@ -93,7 +93,7 @@ extern int device_is_compatible(struct device_node *device, const char *);
extern int machine_is_compatible(const char *compat); extern int machine_is_compatible(const char *compat);
extern unsigned char *get_property(struct device_node *node, const char *name, extern unsigned char *get_property(struct device_node *node, const char *name,
int *lenp); 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 void prom_get_irq_senses(unsigned char *, int, int);
extern int prom_n_addr_cells(struct device_node* np); extern int prom_n_addr_cells(struct device_node* np);
extern int prom_n_size_cells(struct device_node* np); extern int prom_n_size_cells(struct device_node* np);
......
...@@ -213,6 +213,6 @@ extern int prom_n_addr_cells(struct device_node* np); ...@@ -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_size_cells(struct device_node* np);
extern int prom_n_intr_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_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 */ #endif /* _PPC64_PROM_H */
...@@ -139,15 +139,12 @@ extern void proc_tty_unregister_driver(struct tty_driver *driver); ...@@ -139,15 +139,12 @@ extern void proc_tty_unregister_driver(struct tty_driver *driver);
/* /*
* proc_devtree.c * proc_devtree.c
*/ */
#ifdef CONFIG_PROC_DEVICETREE
struct device_node; struct device_node;
struct property;
extern void proc_device_tree_init(void); 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 *); extern void proc_device_tree_add_node(struct device_node *, struct proc_dir_entry *);
#else /* !CONFIG_PROC_DEVICETREE */ extern void proc_device_tree_add_prop(struct proc_dir_entry *pde, struct property *prop);
static inline void proc_device_tree_add_node(struct device_node *np, struct proc_dir_entry *pde)
{
return;
}
#endif /* CONFIG_PROC_DEVICETREE */ #endif /* CONFIG_PROC_DEVICETREE */
extern struct proc_dir_entry *proc_symlink(const char *, extern struct proc_dir_entry *proc_symlink(const char *,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment