@@ -219,6 +219,7 @@ struct amd_pmf_dev {
bool cnqf_supported;
struct notifier_block pwr_src_notifier;
/* Smart PC solution builder */
+ struct dentry *esbin;
unsigned char *policy_buf;
u32 policy_sz;
struct tee_context *tee_ctx;
@@ -8,6 +8,7 @@
* Author: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
*/
+#include <linux/debugfs.h>
#include <linux/tee_drv.h>
#include <linux/uuid.h>
#include "pmf.h"
@@ -16,9 +17,14 @@
/* Policy binary actions sampling frequency (in ms) */
static int pb_actions_ms = MSEC_PER_SEC;
+/* Sideload policy binaries to debug policy failures */
+static bool pb_side_load;
+
#ifdef CONFIG_AMD_PMF_DEBUG
module_param(pb_actions_ms, int, 0644);
MODULE_PARM_DESC(pb_actions_ms, "Policy binary actions sampling frequency (default = 1000ms)");
+module_param(pb_side_load, bool, 0444);
+MODULE_PARM_DESC(pb_side_load, "Sideload policy binaries debug policy failures");
#endif
static const uuid_t amd_pmf_ta_uuid = UUID_INIT(0x6fd93b77, 0x3fb8, 0x524d,
@@ -268,6 +274,61 @@ static int amd_pmf_start_policy_engine(struct amd_pmf_dev *dev)
return 0;
}
+#ifdef CONFIG_AMD_PMF_DEBUG
+static ssize_t amd_pmf_get_pb_data(struct file *filp, const char __user *buf,
+ size_t length, loff_t *pos)
+{
+ struct amd_pmf_dev *dev = filp->private_data;
+ int ret;
+
+ /* policy binary size cannot exceed POLICY_BUF_MAX_SZ */
+ if (length > POLICY_BUF_MAX_SZ || length == 0)
+ return -EINVAL;
+
+ dev->policy_sz = length;
+ if (copy_from_user(dev->policy_buf, buf, dev->policy_sz))
+ return -EFAULT;
+
+ ret = amd_pmf_start_policy_engine(dev);
+ if (ret)
+ return -EINVAL;
+
+ return length;
+}
+
+static const struct file_operations pb_fops = {
+ .write = amd_pmf_get_pb_data,
+ .open = simple_open,
+};
+
+static int amd_pmf_open_pb(struct amd_pmf_dev *dev, struct dentry *debugfs_root)
+{
+ struct dentry *file = NULL;
+
+ dev->esbin = debugfs_create_dir("pb", debugfs_root);
+ if (IS_ERR(dev->esbin))
+ return -EINVAL;
+
+ file = debugfs_create_file("update_policy", 0644, dev->esbin, dev, &pb_fops);
+ if (!file)
+ return -EINVAL;
+
+ return 0;
+}
+
+static void amd_pmf_remove_pb(struct amd_pmf_dev *dev)
+{
+ debugfs_remove_recursive(dev->esbin);
+}
+#else
+static int amd_pmf_open_pb(struct amd_pmf_dev *dev, struct dentry *debugfs_root)
+{
+ return 0;
+}
+
+static void amd_pmf_remove_pb(struct amd_pmf_dev *dev) {}
+#endif
+
static int amd_pmf_get_bios_buffer(struct amd_pmf_dev *dev)
{
dev->policy_buf = kzalloc(dev->policy_sz, GFP_KERNEL);
@@ -280,6 +341,9 @@ static int amd_pmf_get_bios_buffer(struct amd_pmf_dev *dev)
memcpy(dev->policy_buf, dev->policy_base, dev->policy_sz);
+ if (pb_side_load)
+ amd_pmf_open_pb(dev, dev->dbgfs_dir);
+
return amd_pmf_start_policy_engine(dev);
}
@@ -381,6 +445,9 @@ int amd_pmf_init_smart_pc(struct amd_pmf_dev *dev)
void amd_pmf_deinit_smart_pc(struct amd_pmf_dev *dev)
{
+ if (pb_side_load)
+ amd_pmf_remove_pb(dev);
+
kfree(dev->prev_data);
kfree(dev->policy_buf);
cancel_delayed_work_sync(&dev->pb_work);