Skip to content

Commit 6523d3b

Browse files
iklimaszgregkh
authored andcommitted
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 <[email protected]> Co-developed-by: Jae Hyun Yoo <[email protected]> Reviewed-by: Pierre-Louis Bossart <[email protected]> Acked-by: Joel Stanley <[email protected]> Signed-off-by: Jason M Bills <[email protected]> Signed-off-by: Jae Hyun Yoo <[email protected]> Signed-off-by: Iwona Winiarska <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent ac2743a commit 6523d3b

File tree

8 files changed

+305
-0
lines changed

8 files changed

+305
-0
lines changed

MAINTAINERS

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15096,6 +15096,14 @@ L: [email protected]
1509615096
S: Maintained
1509715097
F: drivers/platform/x86/peaq-wmi.c
1509815098

15099+
PECI SUBSYSTEM
15100+
M: Iwona Winiarska <[email protected]>
15101+
L: [email protected] (moderated for non-subscribers)
15102+
S: Supported
15103+
F: Documentation/devicetree/bindings/peci/
15104+
F: drivers/peci/
15105+
F: include/linux/peci.h
15106+
1509915107
PENSANDO ETHERNET DRIVERS
1510015108
M: Shannon Nelson <[email protected]>
1510115109

drivers/Kconfig

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,4 +236,7 @@ source "drivers/interconnect/Kconfig"
236236
source "drivers/counter/Kconfig"
237237

238238
source "drivers/most/Kconfig"
239+
240+
source "drivers/peci/Kconfig"
241+
239242
endmenu

drivers/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,3 +187,4 @@ obj-$(CONFIG_GNSS) += gnss/
187187
obj-$(CONFIG_INTERCONNECT) += interconnect/
188188
obj-$(CONFIG_COUNTER) += counter/
189189
obj-$(CONFIG_MOST) += most/
190+
obj-$(CONFIG_PECI) += peci/

drivers/peci/Kconfig

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# SPDX-License-Identifier: GPL-2.0-only
2+
3+
menuconfig PECI
4+
tristate "PECI support"
5+
help
6+
The Platform Environment Control Interface (PECI) is an interface
7+
that provides a communication channel to Intel processors and
8+
chipset components from external monitoring or control devices.
9+
10+
If you are building a Baseboard Management Controller (BMC) kernel
11+
for Intel platform say Y here and also to the specific driver for
12+
your adapter(s) below. If unsure say N.
13+
14+
This support is also available as a module. If so, the module
15+
will be called peci.

drivers/peci/Makefile

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# SPDX-License-Identifier: GPL-2.0-only
2+
3+
# Core functionality
4+
peci-y := core.o
5+
obj-$(CONFIG_PECI) += peci.o

drivers/peci/core.c

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
// Copyright (c) 2018-2021 Intel Corporation
3+
4+
#include <linux/bug.h>
5+
#include <linux/device.h>
6+
#include <linux/export.h>
7+
#include <linux/idr.h>
8+
#include <linux/module.h>
9+
#include <linux/of.h>
10+
#include <linux/peci.h>
11+
#include <linux/pm_runtime.h>
12+
#include <linux/property.h>
13+
#include <linux/slab.h>
14+
15+
#include "internal.h"
16+
17+
static DEFINE_IDA(peci_controller_ida);
18+
19+
static void peci_controller_dev_release(struct device *dev)
20+
{
21+
struct peci_controller *controller = to_peci_controller(dev);
22+
23+
mutex_destroy(&controller->bus_lock);
24+
ida_free(&peci_controller_ida, controller->id);
25+
kfree(controller);
26+
}
27+
28+
struct device_type peci_controller_type = {
29+
.release = peci_controller_dev_release,
30+
};
31+
32+
static struct peci_controller *peci_controller_alloc(struct device *dev,
33+
struct peci_controller_ops *ops)
34+
{
35+
struct peci_controller *controller;
36+
int ret;
37+
38+
if (!ops->xfer)
39+
return ERR_PTR(-EINVAL);
40+
41+
controller = kzalloc(sizeof(*controller), GFP_KERNEL);
42+
if (!controller)
43+
return ERR_PTR(-ENOMEM);
44+
45+
ret = ida_alloc_max(&peci_controller_ida, U8_MAX, GFP_KERNEL);
46+
if (ret < 0)
47+
goto err;
48+
controller->id = ret;
49+
50+
controller->ops = ops;
51+
52+
controller->dev.parent = dev;
53+
controller->dev.bus = &peci_bus_type;
54+
controller->dev.type = &peci_controller_type;
55+
56+
device_initialize(&controller->dev);
57+
58+
mutex_init(&controller->bus_lock);
59+
60+
return controller;
61+
62+
err:
63+
kfree(controller);
64+
return ERR_PTR(ret);
65+
}
66+
67+
static void unregister_controller(void *_controller)
68+
{
69+
struct peci_controller *controller = _controller;
70+
71+
device_unregister(&controller->dev);
72+
73+
fwnode_handle_put(controller->dev.fwnode);
74+
75+
pm_runtime_disable(&controller->dev);
76+
}
77+
78+
/**
79+
* devm_peci_controller_add() - add PECI controller
80+
* @dev: device for devm operations
81+
* @ops: pointer to controller specific methods
82+
*
83+
* In final stage of its probe(), peci_controller driver calls
84+
* devm_peci_controller_add() to register itself with the PECI bus.
85+
*
86+
* Return: Pointer to the newly allocated controller or ERR_PTR() in case of failure.
87+
*/
88+
struct peci_controller *devm_peci_controller_add(struct device *dev,
89+
struct peci_controller_ops *ops)
90+
{
91+
struct peci_controller *controller;
92+
int ret;
93+
94+
controller = peci_controller_alloc(dev, ops);
95+
if (IS_ERR(controller))
96+
return controller;
97+
98+
ret = dev_set_name(&controller->dev, "peci-%d", controller->id);
99+
if (ret)
100+
goto err_put;
101+
102+
pm_runtime_no_callbacks(&controller->dev);
103+
pm_suspend_ignore_children(&controller->dev, true);
104+
pm_runtime_enable(&controller->dev);
105+
106+
device_set_node(&controller->dev, fwnode_handle_get(dev_fwnode(dev)));
107+
108+
ret = device_add(&controller->dev);
109+
if (ret)
110+
goto err_fwnode;
111+
112+
ret = devm_add_action_or_reset(dev, unregister_controller, controller);
113+
if (ret)
114+
return ERR_PTR(ret);
115+
116+
return controller;
117+
118+
err_fwnode:
119+
fwnode_handle_put(controller->dev.fwnode);
120+
121+
pm_runtime_disable(&controller->dev);
122+
123+
err_put:
124+
put_device(&controller->dev);
125+
126+
return ERR_PTR(ret);
127+
}
128+
EXPORT_SYMBOL_NS_GPL(devm_peci_controller_add, PECI);
129+
130+
struct bus_type peci_bus_type = {
131+
.name = "peci",
132+
};
133+
134+
static int __init peci_init(void)
135+
{
136+
int ret;
137+
138+
ret = bus_register(&peci_bus_type);
139+
if (ret < 0) {
140+
pr_err("peci: failed to register PECI bus type!\n");
141+
return ret;
142+
}
143+
144+
return 0;
145+
}
146+
module_init(peci_init);
147+
148+
static void __exit peci_exit(void)
149+
{
150+
bus_unregister(&peci_bus_type);
151+
}
152+
module_exit(peci_exit);
153+
154+
MODULE_AUTHOR("Jason M Bills <[email protected]>");
155+
MODULE_AUTHOR("Jae Hyun Yoo <[email protected]>");
156+
MODULE_AUTHOR("Iwona Winiarska <[email protected]>");
157+
MODULE_DESCRIPTION("PECI bus core module");
158+
MODULE_LICENSE("GPL");

drivers/peci/internal.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/* SPDX-License-Identifier: GPL-2.0-only */
2+
/* Copyright (c) 2018-2021 Intel Corporation */
3+
4+
#ifndef __PECI_INTERNAL_H
5+
#define __PECI_INTERNAL_H
6+
7+
#include <linux/device.h>
8+
#include <linux/types.h>
9+
10+
struct peci_controller;
11+
12+
extern struct bus_type peci_bus_type;
13+
14+
extern struct device_type peci_controller_type;
15+
16+
#endif /* __PECI_INTERNAL_H */

include/linux/peci.h

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
/* SPDX-License-Identifier: GPL-2.0-only */
2+
/* Copyright (c) 2018-2021 Intel Corporation */
3+
4+
#ifndef __LINUX_PECI_H
5+
#define __LINUX_PECI_H
6+
7+
#include <linux/device.h>
8+
#include <linux/kernel.h>
9+
#include <linux/mutex.h>
10+
#include <linux/types.h>
11+
12+
/*
13+
* Currently we don't support any PECI command over 32 bytes.
14+
*/
15+
#define PECI_REQUEST_MAX_BUF_SIZE 32
16+
17+
struct peci_controller;
18+
struct peci_request;
19+
20+
/**
21+
* struct peci_controller_ops - PECI controller specific methods
22+
* @xfer: PECI transfer function
23+
*
24+
* PECI controllers may have different hardware interfaces - the drivers
25+
* implementing PECI controllers can use this structure to abstract away those
26+
* differences by exposing a common interface for PECI core.
27+
*/
28+
struct peci_controller_ops {
29+
int (*xfer)(struct peci_controller *controller, u8 addr, struct peci_request *req);
30+
};
31+
32+
/**
33+
* struct peci_controller - PECI controller
34+
* @dev: device object to register PECI controller to the device model
35+
* @ops: pointer to device specific controller operations
36+
* @bus_lock: lock used to protect multiple callers
37+
* @id: PECI controller ID
38+
*
39+
* PECI controllers usually connect to their drivers using non-PECI bus,
40+
* such as the platform bus.
41+
* Each PECI controller can communicate with one or more PECI devices.
42+
*/
43+
struct peci_controller {
44+
struct device dev;
45+
struct peci_controller_ops *ops;
46+
struct mutex bus_lock; /* held for the duration of xfer */
47+
u8 id;
48+
};
49+
50+
struct peci_controller *devm_peci_controller_add(struct device *parent,
51+
struct peci_controller_ops *ops);
52+
53+
static inline struct peci_controller *to_peci_controller(void *d)
54+
{
55+
return container_of(d, struct peci_controller, dev);
56+
}
57+
58+
/**
59+
* struct peci_device - PECI device
60+
* @dev: device object to register PECI device to the device model
61+
* @controller: manages the bus segment hosting this PECI device
62+
* @addr: address used on the PECI bus connected to the parent controller
63+
*
64+
* A peci_device identifies a single device (i.e. CPU) connected to a PECI bus.
65+
* The behaviour exposed to the rest of the system is defined by the PECI driver
66+
* managing the device.
67+
*/
68+
struct peci_device {
69+
struct device dev;
70+
u8 addr;
71+
};
72+
73+
static inline struct peci_device *to_peci_device(struct device *d)
74+
{
75+
return container_of(d, struct peci_device, dev);
76+
}
77+
78+
/**
79+
* struct peci_request - PECI request
80+
* @device: PECI device to which the request is sent
81+
* @tx: TX buffer specific data
82+
* @tx.buf: TX buffer
83+
* @tx.len: transfer data length in bytes
84+
* @rx: RX buffer specific data
85+
* @rx.buf: RX buffer
86+
* @rx.len: received data length in bytes
87+
*
88+
* A peci_request represents a request issued by PECI originator (TX) and
89+
* a response received from PECI responder (RX).
90+
*/
91+
struct peci_request {
92+
struct peci_device *device;
93+
struct {
94+
u8 buf[PECI_REQUEST_MAX_BUF_SIZE];
95+
u8 len;
96+
} rx, tx;
97+
};
98+
99+
#endif /* __LINUX_PECI_H */

0 commit comments

Comments
 (0)