diff options
Diffstat (limited to 'drivers/platform/x86/amd/hsmp/hsmp.c')
-rw-r--r-- | drivers/platform/x86/amd/hsmp/hsmp.c | 48 |
1 files changed, 41 insertions, 7 deletions
diff --git a/drivers/platform/x86/amd/hsmp/hsmp.c b/drivers/platform/x86/amd/hsmp/hsmp.c index 227b4ad4a51a..a3ac09a90de4 100644 --- a/drivers/platform/x86/amd/hsmp/hsmp.c +++ b/drivers/platform/x86/amd/hsmp/hsmp.c @@ -8,7 +8,6 @@ */ #include <asm/amd_hsmp.h> -#include <asm/amd_nb.h> #include <linux/acpi.h> #include <linux/delay.h> @@ -33,7 +32,13 @@ #define HSMP_WR true #define HSMP_RD false -#define DRIVER_VERSION "2.3" +#define DRIVER_VERSION "2.4" + +/* + * When same message numbers are used for both GET and SET operation, + * bit:31 indicates whether its SET or GET operation. + */ +#define CHECK_GET_BIT BIT(31) static struct hsmp_plat_device hsmp_pdev; @@ -167,11 +172,28 @@ static int validate_message(struct hsmp_message *msg) if (hsmp_msg_desc_table[msg->msg_id].type == HSMP_RSVD) return -ENOMSG; - /* num_args and response_sz against the HSMP spec */ - if (msg->num_args != hsmp_msg_desc_table[msg->msg_id].num_args || - msg->response_sz != hsmp_msg_desc_table[msg->msg_id].response_sz) + /* + * num_args passed by user should match the num_args specified in + * message description table. + */ + if (msg->num_args != hsmp_msg_desc_table[msg->msg_id].num_args) return -EINVAL; + /* + * Some older HSMP SET messages are updated to add GET in the same message. + * In these messages, GET returns the current value and SET also returns + * the successfully set value. To support this GET and SET in same message + * while maintaining backward compatibility for the HSMP users, + * hsmp_msg_desc_table[] indicates only maximum allowed response_sz. + */ + if (hsmp_msg_desc_table[msg->msg_id].type == HSMP_SET_GET) { + if (msg->response_sz > hsmp_msg_desc_table[msg->msg_id].response_sz) + return -EINVAL; + } else { + /* only HSMP_SET or HSMP_GET messages go through this strict check */ + if (msg->response_sz != hsmp_msg_desc_table[msg->msg_id].response_sz) + return -EINVAL; + } return 0; } @@ -239,6 +261,18 @@ int hsmp_test(u16 sock_ind, u32 value) } EXPORT_SYMBOL_NS_GPL(hsmp_test, "AMD_HSMP"); +static bool is_get_msg(struct hsmp_message *msg) +{ + if (hsmp_msg_desc_table[msg->msg_id].type == HSMP_GET) + return true; + + if (hsmp_msg_desc_table[msg->msg_id].type == HSMP_SET_GET && + (msg->args[0] & CHECK_GET_BIT)) + return true; + + return false; +} + long hsmp_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) { int __user *arguser = (int __user *)arg; @@ -261,7 +295,7 @@ long hsmp_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) * Device is opened in O_WRONLY mode * Execute only set/configure commands */ - if (hsmp_msg_desc_table[msg.msg_id].type != HSMP_SET) + if (is_get_msg(&msg)) return -EPERM; break; case FMODE_READ: @@ -269,7 +303,7 @@ long hsmp_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) * Device is opened in O_RDONLY mode * Execute only get/monitor commands */ - if (hsmp_msg_desc_table[msg.msg_id].type != HSMP_GET) + if (!is_get_msg(&msg)) return -EPERM; break; case FMODE_READ | FMODE_WRITE: |