Skip to content

Commit 7850975

Browse files
committed
misc: amd-apml: Add common device registration framework
Add centralized device registration system for AMD APML devices. Provides global device list where SBRMI and SBTSI drivers can register themselves, enabling the Alert_L driver to discover and safely process alerts from registered devices. Reviewed-by: Naveen Krishna Chatradhi <naveenkrishna.chatradhi@amd.com> Signed-off-by: sathya priya kumar <SathyaPriya.K@amd.com> Signed-off-by: Akshay Gupta <akshay.gupta@amd.com>
1 parent 75e1868 commit 7850975

4 files changed

Lines changed: 281 additions & 0 deletions

File tree

drivers/misc/amd-apml/Kconfig

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,18 @@
33
# AMD APML BMC interface drivers
44
#
55

6+
config APML_COMMON
7+
tristate "AMD APML common device registration framework"
8+
default n
9+
help
10+
Enable support for the AMD APML (Advanced Platform Management Link)
11+
common device registration framework. This module provides a centralized
12+
registry where APML devices (SBRMI and SBTSI) can register themselves
13+
for discovery by other APML subsystems.
14+
15+
This framework enables the Alert_L driver to safely discover and access
16+
registered APML devices for alert processing across multiple sockets.
17+
618
config APML_SBRMI
719
tristate "Emulated SB-RMI interface driver over i3c bus"
820
depends on I3C && !SENSORS_SBRMI

drivers/misc/amd-apml/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
# AMD APML BMC interface drivers
55
#
66

7+
obj-$(CONFIG_APML_COMMON) += apml_common.o
78
obj-$(CONFIG_APML_SBRMI) += sbrmi.o sbrmi-common.o
89
obj-$(CONFIG_APML_SBTSI) += apml_sbtsi.o
910
obj-$(CONFIG_APML_ALERTL) += apml_alertl.o
Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
// SPDX-License-Identifier: GPL-2.0-or-later
2+
/*
3+
* apml-common.c - Common registration system for APML devices
4+
*
5+
* Copyright (C) 2025 Advanced Micro Devices, Inc.
6+
*/
7+
8+
#include <linux/module.h>
9+
#include <linux/slab.h>
10+
#include <linux/i2c.h>
11+
#include <linux/i3c/device.h>
12+
#include <linux/i3c/master.h>
13+
#include <linux/mutex.h>
14+
#include <linux/list.h>
15+
#include <linux/kref.h>
16+
17+
#include "apml_common.h"
18+
19+
/* Global list of registered APML devices */
20+
LIST_HEAD(apml_devices);
21+
EXPORT_SYMBOL_GPL(apml_devices);
22+
23+
/* Mutex to protect apml_devices list operations and device node access */
24+
DEFINE_MUTEX(apml_devices_lock);
25+
EXPORT_SYMBOL_GPL(apml_devices_lock);
26+
27+
/* Release function for device node reference counting */
28+
static void apml_device_node_release(struct kref *ref)
29+
{
30+
struct apml_device_node *node = container_of(ref, struct apml_device_node, ref);
31+
32+
kfree(node);
33+
}
34+
35+
/* Get a reference to a device node - increases reference count */
36+
struct apml_device_node *apml_get_device_node(struct apml_device_node *node)
37+
{
38+
if (node && kref_get_unless_zero(&node->ref))
39+
return node;
40+
return NULL;
41+
}
42+
EXPORT_SYMBOL_GPL(apml_get_device_node);
43+
44+
/* Put a reference to a device node - decreases reference count */
45+
void apml_put_device_node(struct apml_device_node *node)
46+
{
47+
if (node)
48+
kref_put(&node->ref, apml_device_node_release);
49+
}
50+
EXPORT_SYMBOL_GPL(apml_put_device_node);
51+
52+
static void apml_add_device_node(struct apml_device_node *node)
53+
{
54+
mutex_lock(&apml_devices_lock);
55+
list_add_tail(&node->list, &apml_devices);
56+
mutex_unlock(&apml_devices_lock);
57+
}
58+
59+
/* Device registration function */
60+
int apml_register_device(void *device, enum apml_device_type dev_type)
61+
{
62+
struct apml_device_node *node;
63+
struct apml_sbrmi_device *rmi_dev;
64+
struct apml_sbtsi_device *tsi_dev;
65+
66+
if (!device) {
67+
pr_info("APML: Cannot register NULL device\n");
68+
return -EINVAL;
69+
}
70+
71+
node = kzalloc(sizeof(*node), GFP_KERNEL);
72+
if (!node)
73+
return -ENOMEM;
74+
75+
node->dev_type = dev_type;
76+
kref_init(&node->ref); /* Initialize reference count to 1 */
77+
78+
switch (node->dev_type) {
79+
case APML_RMI_DEVICE:
80+
rmi_dev = (struct apml_sbrmi_device *)device;
81+
82+
if (!rmi_dev->i3cdev && !rmi_dev->client) {
83+
pr_err("APML: Invalid RMI device - no I2C or I3C device\n");
84+
kfree(node);
85+
return -EINVAL;
86+
}
87+
node->rmi_dev = rmi_dev;
88+
pr_info("APML: Registered SBRMI device at address 0x%x\n",
89+
rmi_dev->i3cdev ? rmi_dev->dev_static_addr : rmi_dev->client->addr);
90+
break;
91+
case APML_TSI_DEVICE:
92+
tsi_dev = (struct apml_sbtsi_device *)device;
93+
94+
if (!tsi_dev->i3cdev && !tsi_dev->client) {
95+
pr_info("APML: Invalid TSI device - no I2C or I3C device\n");
96+
kfree(node);
97+
return -EINVAL;
98+
}
99+
node->tsi_dev = tsi_dev;
100+
pr_info("APML: Registered SBTSI device at address 0x%x\n",
101+
tsi_dev->i3cdev ? tsi_dev->dev_static_addr : tsi_dev->client->addr);
102+
break;
103+
default:
104+
kfree(node);
105+
return -EINVAL;
106+
}
107+
108+
apml_add_device_node(node);
109+
return 0;
110+
}
111+
112+
/* Register an SBRMI device */
113+
int apml_register_sbrmi_device(struct apml_sbrmi_device *rmi_dev)
114+
{
115+
return apml_register_device(rmi_dev, APML_RMI_DEVICE);
116+
}
117+
EXPORT_SYMBOL_GPL(apml_register_sbrmi_device);
118+
119+
/* Register an SBTSI device*/
120+
int apml_register_sbtsi_device(struct apml_sbtsi_device *tsi_dev)
121+
{
122+
return apml_register_device(tsi_dev, APML_TSI_DEVICE);
123+
}
124+
EXPORT_SYMBOL_GPL(apml_register_sbtsi_device);
125+
126+
/* Device unregistration function*/
127+
void apml_unregister_device(void *device, enum apml_device_type dev_type)
128+
{
129+
struct apml_device_node *node, *tmp, *found_node = NULL;
130+
bool found = false;
131+
132+
if (!device)
133+
return;
134+
135+
/* Find and mark device as invalid and removing */
136+
mutex_lock(&apml_devices_lock);
137+
list_for_each_entry(node, &apml_devices, list) {
138+
if (node->dev_type != dev_type)
139+
continue;
140+
141+
switch (dev_type) {
142+
case APML_RMI_DEVICE:
143+
if (node->rmi_dev == (struct apml_sbrmi_device *)device)
144+
found = true;
145+
break;
146+
case APML_TSI_DEVICE:
147+
if (node->tsi_dev == (struct apml_sbtsi_device *)device)
148+
found = true;
149+
break;
150+
}
151+
152+
if (found) {
153+
/* Get a reference to keep node alive during removal */
154+
found_node = apml_get_device_node(node);
155+
break;
156+
}
157+
}
158+
mutex_unlock(&apml_devices_lock);
159+
160+
if (!found_node)
161+
return;
162+
163+
/* Remove from list and release reference */
164+
mutex_lock(&apml_devices_lock);
165+
list_for_each_entry_safe(node, tmp, &apml_devices, list) {
166+
if (node == found_node) {
167+
list_del(&node->list);
168+
break;
169+
}
170+
}
171+
mutex_unlock(&apml_devices_lock);
172+
173+
/* Release our reference - this may free the node if no other references exist */
174+
apml_put_device_node(found_node);
175+
}
176+
177+
/* Unregister an SBRMI device */
178+
void apml_unregister_sbrmi_device(struct apml_sbrmi_device *rmi_dev)
179+
{
180+
apml_unregister_device(rmi_dev, APML_RMI_DEVICE);
181+
}
182+
EXPORT_SYMBOL_GPL(apml_unregister_sbrmi_device);
183+
184+
/* Unregister an SBTSI device */
185+
void apml_unregister_sbtsi_device(struct apml_sbtsi_device *tsi_dev)
186+
{
187+
apml_unregister_device(tsi_dev, APML_TSI_DEVICE);
188+
}
189+
EXPORT_SYMBOL_GPL(apml_unregister_sbtsi_device);
190+
191+
MODULE_AUTHOR("Akshay Gupta <akshay.gupta@amd.com>");
192+
MODULE_AUTHOR("sathya priya kumar <SathyaPriya.K@amd.com>");
193+
MODULE_AUTHOR("Naveenkrishna Chatradhi <naveenkrishna.chatradhi@amd.com>");
194+
MODULE_DESCRIPTION("AMD APML Common Device Registration");
195+
MODULE_LICENSE("GPL");
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/* SPDX-License-Identifier: GPL-2.0-or-later */
2+
/*
3+
* Copyright (C) 2025 Advanced Micro Devices, Inc.
4+
*/
5+
6+
#ifndef _AMD_APML_COMMON_H_
7+
#define _AMD_APML_COMMON_H_
8+
9+
#include <linux/list.h>
10+
#include <linux/kref.h>
11+
#include "sbrmi-common.h"
12+
#include "sbtsi-common.h"
13+
14+
extern struct list_head apml_devices;
15+
extern struct mutex apml_devices_lock;
16+
17+
enum apml_device_type {
18+
APML_RMI_DEVICE,
19+
APML_TSI_DEVICE,
20+
};
21+
22+
struct apml_device_node {
23+
struct list_head list;
24+
struct kref ref;
25+
enum apml_device_type dev_type;
26+
union {
27+
struct apml_sbrmi_device *rmi_dev;
28+
struct apml_sbtsi_device *tsi_dev;
29+
};
30+
};
31+
32+
/* Function declarations - available when APML_COMMON is built */
33+
#if IS_ENABLED(CONFIG_APML_COMMON)
34+
int apml_register_sbrmi_device(struct apml_sbrmi_device *rmi_dev);
35+
void apml_unregister_sbrmi_device(struct apml_sbrmi_device *rmi_dev);
36+
int apml_register_sbtsi_device(struct apml_sbtsi_device *tsi_dev);
37+
void apml_unregister_sbtsi_device(struct apml_sbtsi_device *tsi_dev);
38+
struct apml_device_node *apml_get_device_node(struct apml_device_node *node);
39+
void apml_put_device_node(struct apml_device_node *node);
40+
#else
41+
/* Stub functions when APML_COMMON is not available */
42+
static inline int apml_register_sbrmi_device(struct apml_sbrmi_device *rmi_dev)
43+
{
44+
return 0;
45+
}
46+
47+
static inline void apml_unregister_sbrmi_device(struct apml_sbrmi_device *rmi_dev)
48+
{
49+
return 0;
50+
}
51+
52+
static inline int apml_register_sbtsi_device(struct apml_sbtsi_device *tsi_dev)
53+
{
54+
return 0;
55+
}
56+
57+
static inline void apml_unregister_sbtsi_device(struct apml_sbtsi_device *tsi_dev)
58+
{
59+
return 0
60+
}
61+
62+
static inline struct apml_device_node *apml_get_device_node(struct apml_device_node *node)
63+
{
64+
return NULL;
65+
}
66+
67+
static inline void apml_put_device_node(struct apml_device_node *node)
68+
{
69+
return 0;
70+
}
71+
72+
#endif /* IS_ENABLED(CONFIG_APML_COMMON) */
73+
#endif /* _AMD_APML_COMMON_H_ */

0 commit comments

Comments
 (0)