aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/peci/core.c
diff options
context:
space:
mode:
authorIwona Winiarska <iwona.winiarska@intel.com>2022-02-08 16:36:30 +0100
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2022-02-09 08:04:43 +0100
commit6523d3b2ffa238ac033c34a726617061d6a744aa (patch)
tree9d38dab516e5ddd69fccbec568526b5812295138 /drivers/peci/core.c
parentARM: dts: aspeed: Add PECI controller nodes (diff)
downloadlinux-dev-6523d3b2ffa238ac033c34a726617061d6a744aa.tar.xz
linux-dev-6523d3b2ffa238ac033c34a726617061d6a744aa.zip
peci: Add core infrastructure
Intel processors provide access for various services designed to support processor and DRAM thermal management, platform manageability and processor interface tuning and diagnostics. Those services are available via the Platform Environment Control Interface (PECI) that provides a communication channel between the processor and the Baseboard Management Controller (BMC) or other platform management device. This change introduces PECI subsystem by adding the initial core module and API for controller drivers. Co-developed-by: Jason M Bills <jason.m.bills@linux.intel.com> Co-developed-by: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com> Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com> Acked-by: Joel Stanley <joel@jms.id.au> Signed-off-by: Jason M Bills <jason.m.bills@linux.intel.com> Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com> Signed-off-by: Iwona Winiarska <iwona.winiarska@intel.com> Link: https://lore.kernel.org/r/20220208153639.255278-5-iwona.winiarska@intel.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/peci/core.c')
-rw-r--r--drivers/peci/core.c158
1 files changed, 158 insertions, 0 deletions
diff --git a/drivers/peci/core.c b/drivers/peci/core.c
new file mode 100644
index 000000000000..73ad0a47fa9d
--- /dev/null
+++ b/drivers/peci/core.c
@@ -0,0 +1,158 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// Copyright (c) 2018-2021 Intel Corporation
+
+#include <linux/bug.h>
+#include <linux/device.h>
+#include <linux/export.h>
+#include <linux/idr.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/peci.h>
+#include <linux/pm_runtime.h>
+#include <linux/property.h>
+#include <linux/slab.h>
+
+#include "internal.h"
+
+static DEFINE_IDA(peci_controller_ida);
+
+static void peci_controller_dev_release(struct device *dev)
+{
+ struct peci_controller *controller = to_peci_controller(dev);
+
+ mutex_destroy(&controller->bus_lock);
+ ida_free(&peci_controller_ida, controller->id);
+ kfree(controller);
+}
+
+struct device_type peci_controller_type = {
+ .release = peci_controller_dev_release,
+};
+
+static struct peci_controller *peci_controller_alloc(struct device *dev,
+ struct peci_controller_ops *ops)
+{
+ struct peci_controller *controller;
+ int ret;
+
+ if (!ops->xfer)
+ return ERR_PTR(-EINVAL);
+
+ controller = kzalloc(sizeof(*controller), GFP_KERNEL);
+ if (!controller)
+ return ERR_PTR(-ENOMEM);
+
+ ret = ida_alloc_max(&peci_controller_ida, U8_MAX, GFP_KERNEL);
+ if (ret < 0)
+ goto err;
+ controller->id = ret;
+
+ controller->ops = ops;
+
+ controller->dev.parent = dev;
+ controller->dev.bus = &peci_bus_type;
+ controller->dev.type = &peci_controller_type;
+
+ device_initialize(&controller->dev);
+
+ mutex_init(&controller->bus_lock);
+
+ return controller;
+
+err:
+ kfree(controller);
+ return ERR_PTR(ret);
+}
+
+static void unregister_controller(void *_controller)
+{
+ struct peci_controller *controller = _controller;
+
+ device_unregister(&controller->dev);
+
+ fwnode_handle_put(controller->dev.fwnode);
+
+ pm_runtime_disable(&controller->dev);
+}
+
+/**
+ * devm_peci_controller_add() - add PECI controller
+ * @dev: device for devm operations
+ * @ops: pointer to controller specific methods
+ *
+ * In final stage of its probe(), peci_controller driver calls
+ * devm_peci_controller_add() to register itself with the PECI bus.
+ *
+ * Return: Pointer to the newly allocated controller or ERR_PTR() in case of failure.
+ */
+struct peci_controller *devm_peci_controller_add(struct device *dev,
+ struct peci_controller_ops *ops)
+{
+ struct peci_controller *controller;
+ int ret;
+
+ controller = peci_controller_alloc(dev, ops);
+ if (IS_ERR(controller))
+ return controller;
+
+ ret = dev_set_name(&controller->dev, "peci-%d", controller->id);
+ if (ret)
+ goto err_put;
+
+ pm_runtime_no_callbacks(&controller->dev);
+ pm_suspend_ignore_children(&controller->dev, true);
+ pm_runtime_enable(&controller->dev);
+
+ device_set_node(&controller->dev, fwnode_handle_get(dev_fwnode(dev)));
+
+ ret = device_add(&controller->dev);
+ if (ret)
+ goto err_fwnode;
+
+ ret = devm_add_action_or_reset(dev, unregister_controller, controller);
+ if (ret)
+ return ERR_PTR(ret);
+
+ return controller;
+
+err_fwnode:
+ fwnode_handle_put(controller->dev.fwnode);
+
+ pm_runtime_disable(&controller->dev);
+
+err_put:
+ put_device(&controller->dev);
+
+ return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_NS_GPL(devm_peci_controller_add, PECI);
+
+struct bus_type peci_bus_type = {
+ .name = "peci",
+};
+
+static int __init peci_init(void)
+{
+ int ret;
+
+ ret = bus_register(&peci_bus_type);
+ if (ret < 0) {
+ pr_err("peci: failed to register PECI bus type!\n");
+ return ret;
+ }
+
+ return 0;
+}
+module_init(peci_init);
+
+static void __exit peci_exit(void)
+{
+ bus_unregister(&peci_bus_type);
+}
+module_exit(peci_exit);
+
+MODULE_AUTHOR("Jason M Bills <jason.m.bills@linux.intel.com>");
+MODULE_AUTHOR("Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>");
+MODULE_AUTHOR("Iwona Winiarska <iwona.winiarska@intel.com>");
+MODULE_DESCRIPTION("PECI bus core module");
+MODULE_LICENSE("GPL");