Skip to content

Commit 7018cb9

Browse files
author
Mamatha Inamdar
committed
powerpc/pseries: Add papr-hvpipe char driver for HVPIPE interfaces
JIRA: https://issues.redhat.com/browse/RHEL-101849 Conflicts: - Use rtas_service_present() instead of rtas_function_implemented() commit 814ef09 Author: Haren Myneni <haren@linux.ibm.com> Date: Tue Sep 9 01:43:55 2025 -0700 powerpc/pseries: Add papr-hvpipe char driver for HVPIPE interfaces The hypervisor provides ibm,send-hvpipe-msg and ibm,receive-hvpipe-msg RTAS calls which can be used by the partition to communicate through an inband hypervisor channel with different external sources such as Hardware Management Console (HMC). The information exchanged, whether it be messages, raw or formatted data, etc., is only known to between applications in the OS and the source (HMC). This patch adds papr-hvpipe character driver and provides the standard interfaces such as open / ioctl/ read / write to user space for exchanging information with HMC using send/recevive HVPIPE RTAS functions. PAPR (7.3.32 Hypervisor Pipe Information Exchange) defines the HVPIPE usage: - The hypervisor has one HVPIPE per partition for all sources. - OS can determine this feature’s availability by detecting the “ibm,hypervisor-pipe-capable” property in the /rtas node of the device tree. - Each source is represented by the source ID which is used in send / recv HVPIPE RTAS. (Ex: source ID is the target for the payload in send RTAS). - Return status of ibm,send-hvpipe-msg can be considered as delivered the payload. - Return status of ibm,receive-hvpipe-msg can be considered as ACK to source. - The hypervisor generates hvpipe message event interrupt when the partition has the payload to receive. Provide the interfaces to the user space with /dev/papr-hvpipe character device using the following programming model: int devfd = open("/dev/papr-hvpipe") int fd = ioctl(devfd, PAPR_HVPIPE_IOC_CREATE_HANDLE, &srcID); - Restrict the user space to use the same source ID and do not expect more than one process access with the same source. char *buf = malloc(size); - SIZE should be 4K and the buffer contains header and the payload. length = write(fd, buf, size); - OS issues ibm,send-hvpipe-msg RTAS and returns the RTAS status to the user space. ret = poll(fd,...) - The HVPIPE event message IRQ wakes up for any waiting FDs. length = read(fd, buf, size); - OS issues ibm,receive-hvpipe-msg to receive payload from the hypervisor. release(fd); - OS issues ibm,receive-hvpipe-msg if any payload is pending so that pipe is not blocked. The actual implementation of these calls are added in the next patches. Signed-off-by: Haren Myneni <haren@linux.ibm.com> Tested-by: Shashank MS <shashank.gowda@in.ibm.com> Reviewed-by: Mahesh Salgaonkar <mahesh@linux.ibm.com> Reviewed-by: Tyrel Datwyler <tyreld@linux.ibm.com> Signed-off-by: Madhavan Srinivasan <maddy@linux.ibm.com> Link: https://patch.msgid.link/20250909084402.1488456-4-haren@linux.ibm.com Signed-off-by: Mamatha Inamdar <minamdar@redhat.com>
1 parent 0061533 commit 7018cb9

File tree

3 files changed

+300
-0
lines changed

3 files changed

+300
-0
lines changed

arch/powerpc/platforms/pseries/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ obj-y := lpar.o hvCall.o nvram.o reconfig.o \
66
of_helpers.o rtas-work-area.o papr-sysparm.o \
77
papr-rtas-common.o papr-vpd.o papr-indices.o \
88
papr-platform-dump.o papr-phy-attest.o \
9+
papr-hvpipe.o \
910
setup.o iommu.o event_sources.o ras.o \
1011
firmware.o power.o dlpar.o mobility.o rng.o \
1112
pci.o pci_dlpar.o eeh_pseries.o msi.o \
Lines changed: 285 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,285 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
3+
#define pr_fmt(fmt) "papr-hvpipe: " fmt
4+
5+
#include <linux/module.h>
6+
#include <linux/kernel.h>
7+
#include <linux/types.h>
8+
#include <linux/delay.h>
9+
#include <linux/anon_inodes.h>
10+
#include <linux/miscdevice.h>
11+
#include <linux/file.h>
12+
#include <linux/fs.h>
13+
#include <linux/poll.h>
14+
#include <linux/of.h>
15+
#include <asm/machdep.h>
16+
#include <asm/rtas.h>
17+
#include <uapi/asm/papr-hvpipe.h>
18+
#include "pseries.h"
19+
#include "papr-hvpipe.h"
20+
21+
static DEFINE_SPINLOCK(hvpipe_src_list_lock);
22+
static LIST_HEAD(hvpipe_src_list);
23+
24+
/*
25+
* New PowerPC FW provides support for partitions and various
26+
* sources (Ex: remote hardware management console (HMC)) to
27+
* exchange information through an inband hypervisor channel
28+
* called HVPIPE. Only HMCs are supported right now and
29+
* partitions can communicate with multiple HMCs and each
30+
* source represented by source ID.
31+
*
32+
* FW introduces send HVPIPE and recv HVPIPE RTAS calls for
33+
* partitions to send and receive payloads respectively.
34+
*
35+
* These RTAS functions have the following certain requirements
36+
* / limitations:
37+
* - One hvpipe per partition for all sources.
38+
* - Assume the return status of send HVPIPE as delivered to source
39+
* - Assume the return status of recv HVPIPE as ACK to source
40+
* - Generates HVPIPE event message when the payload is ready
41+
* for the partition. The hypervisor will not deliver another
42+
* event until the partition read the previous payload which
43+
* means the pipe is blocked for any sources.
44+
*
45+
* Linux implementation:
46+
* Follow the similar interfaces that the OS has for other RTAS calls.
47+
* ex: /dev/papr-indices, /dev/papr-vpd, etc.
48+
* - /dev/papr-hvpipe is available for the user space.
49+
* - devfd = open("/dev/papr-hvpipe", ..)
50+
* - fd = ioctl(fd,HVPIPE_IOC_CREATE_HANDLE,&srcID)-for each source
51+
* - write(fd, buf, size) --> Issue send HVPIPE RTAS call and
52+
* returns size for success or the corresponding error for RTAS
53+
* return code for failure.
54+
* - poll(fd,..) -> wakeup FD if the payload is available to read.
55+
* HVPIPE event message handler wakeup FD based on source ID in
56+
* the event message
57+
* - read(fd, buf, size) --> Issue recv HVPIPE RTAS call and
58+
* returns size for success or the corresponding error for RTAS
59+
* return code for failure.
60+
*/
61+
62+
static struct hvpipe_source_info *hvpipe_find_source(u32 srcID)
63+
{
64+
struct hvpipe_source_info *src_info;
65+
66+
list_for_each_entry(src_info, &hvpipe_src_list, list)
67+
if (src_info->srcID == srcID)
68+
return src_info;
69+
70+
return NULL;
71+
}
72+
73+
/*
74+
* papr_hvpipe_handle_write - Issue send HVPIPE RTAS and return
75+
* the RTAS status to the user space
76+
*/
77+
static ssize_t papr_hvpipe_handle_write(struct file *file,
78+
const char __user *buf, size_t size, loff_t *off)
79+
{
80+
struct hvpipe_source_info *src_info = file->private_data;
81+
82+
if (!src_info)
83+
return -EIO;
84+
85+
return 0;
86+
}
87+
88+
/*
89+
* papr_hvpipe_handle_read - If the payload for the specific
90+
* source is pending in the hypervisor, issue recv HVPIPE RTAS
91+
* and return the payload to the user space.
92+
*
93+
* When the payload is available for the partition, the
94+
* hypervisor notifies HVPIPE event with the source ID
95+
* and the event handler wakeup FD(s) that are waiting.
96+
*/
97+
static ssize_t papr_hvpipe_handle_read(struct file *file,
98+
char __user *buf, size_t size, loff_t *off)
99+
{
100+
101+
struct hvpipe_source_info *src_info = file->private_data;
102+
103+
if (!src_info)
104+
return -EIO;
105+
106+
return 0;
107+
}
108+
109+
/*
110+
* The user space waits for the payload to receive.
111+
* The hypervisor sends HVPIPE event message to the partition
112+
* when the payload is available. The event handler wakeup FD
113+
* depends on the source ID in the message event.
114+
*/
115+
static __poll_t papr_hvpipe_handle_poll(struct file *filp,
116+
struct poll_table_struct *wait)
117+
{
118+
struct hvpipe_source_info *src_info = filp->private_data;
119+
120+
if (!src_info)
121+
return POLLNVAL;
122+
123+
return 0;
124+
}
125+
126+
static int papr_hvpipe_handle_release(struct inode *inode,
127+
struct file *file)
128+
{
129+
struct hvpipe_source_info *src_info;
130+
131+
/*
132+
* Hold the lock, remove source from src_list, reset the
133+
* hvpipe status and release the lock to prevent any race
134+
* with message event IRQ.
135+
*/
136+
spin_lock(&hvpipe_src_list_lock);
137+
src_info = file->private_data;
138+
list_del(&src_info->list);
139+
file->private_data = NULL;
140+
spin_unlock(&hvpipe_src_list_lock);
141+
kfree(src_info);
142+
return 0;
143+
}
144+
145+
static const struct file_operations papr_hvpipe_handle_ops = {
146+
.read = papr_hvpipe_handle_read,
147+
.write = papr_hvpipe_handle_write,
148+
.release = papr_hvpipe_handle_release,
149+
.poll = papr_hvpipe_handle_poll,
150+
};
151+
152+
static int papr_hvpipe_dev_create_handle(u32 srcID)
153+
{
154+
struct hvpipe_source_info *src_info;
155+
struct file *file;
156+
long err;
157+
int fd;
158+
159+
spin_lock(&hvpipe_src_list_lock);
160+
/*
161+
* Do not allow more than one process communicates with
162+
* each source.
163+
*/
164+
src_info = hvpipe_find_source(srcID);
165+
if (src_info) {
166+
spin_unlock(&hvpipe_src_list_lock);
167+
pr_err("pid(%d) is already using the source(%d)\n",
168+
src_info->tsk->pid, srcID);
169+
return -EALREADY;
170+
}
171+
spin_unlock(&hvpipe_src_list_lock);
172+
173+
src_info = kzalloc(sizeof(*src_info), GFP_KERNEL_ACCOUNT);
174+
if (!src_info)
175+
return -ENOMEM;
176+
177+
src_info->srcID = srcID;
178+
src_info->tsk = current;
179+
init_waitqueue_head(&src_info->recv_wqh);
180+
181+
fd = get_unused_fd_flags(O_RDONLY | O_CLOEXEC);
182+
if (fd < 0) {
183+
err = fd;
184+
goto free_buf;
185+
}
186+
187+
file = anon_inode_getfile("[papr-hvpipe]",
188+
&papr_hvpipe_handle_ops, (void *)src_info,
189+
O_RDWR);
190+
if (IS_ERR(file)) {
191+
err = PTR_ERR(file);
192+
goto free_fd;
193+
}
194+
195+
spin_lock(&hvpipe_src_list_lock);
196+
/*
197+
* If two processes are executing ioctl() for the same
198+
* source ID concurrently, prevent the second process to
199+
* acquire FD.
200+
*/
201+
if (hvpipe_find_source(srcID)) {
202+
spin_unlock(&hvpipe_src_list_lock);
203+
err = -EALREADY;
204+
goto free_file;
205+
}
206+
list_add(&src_info->list, &hvpipe_src_list);
207+
spin_unlock(&hvpipe_src_list_lock);
208+
209+
fd_install(fd, file);
210+
return fd;
211+
212+
free_file:
213+
fput(file);
214+
free_fd:
215+
put_unused_fd(fd);
216+
free_buf:
217+
kfree(src_info);
218+
return err;
219+
}
220+
221+
/*
222+
* Top-level ioctl handler for /dev/papr_hvpipe
223+
*
224+
* Use separate FD for each source (exa :HMC). So ioctl is called
225+
* with source ID which returns FD.
226+
*/
227+
static long papr_hvpipe_dev_ioctl(struct file *filp, unsigned int ioctl,
228+
unsigned long arg)
229+
{
230+
u32 __user *argp = (void __user *)arg;
231+
u32 srcID;
232+
long ret;
233+
234+
if (get_user(srcID, argp))
235+
return -EFAULT;
236+
237+
/*
238+
* Support only HMC source right now
239+
*/
240+
if (!(srcID & HVPIPE_HMC_ID_MASK))
241+
return -EINVAL;
242+
243+
switch (ioctl) {
244+
case PAPR_HVPIPE_IOC_CREATE_HANDLE:
245+
ret = papr_hvpipe_dev_create_handle(srcID);
246+
break;
247+
default:
248+
ret = -ENOIOCTLCMD;
249+
break;
250+
}
251+
252+
return ret;
253+
}
254+
255+
static const struct file_operations papr_hvpipe_ops = {
256+
.unlocked_ioctl = papr_hvpipe_dev_ioctl,
257+
};
258+
259+
static struct miscdevice papr_hvpipe_dev = {
260+
.minor = MISC_DYNAMIC_MINOR,
261+
.name = "papr-hvpipe",
262+
.fops = &papr_hvpipe_ops,
263+
};
264+
265+
static int __init papr_hvpipe_init(void)
266+
{
267+
int ret;
268+
269+
if (!of_find_property(rtas.dev, "ibm,hypervisor-pipe-capable",
270+
NULL))
271+
return -ENODEV;
272+
273+
if (!rtas_service_present("ibm,send-hvpipe-msg") ||
274+
!rtas_service_present("ibm,receive-hvpipe-msg"))
275+
return -ENODEV;
276+
277+
ret = misc_register(&papr_hvpipe_dev);
278+
if (ret) {
279+
pr_err("misc-dev registration failed %d\n", ret);
280+
return ret;
281+
}
282+
283+
return 0;
284+
}
285+
machine_device_initcall(pseries, papr_hvpipe_init);
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/* SPDX-License-Identifier: GPL-2.0-only */
2+
#ifndef _PAPR_HVPIPE_H
3+
#define _PAPR_HVPIPE_H
4+
5+
#define HVPIPE_HMC_ID_MASK 0x02000000 /*02-HMC,00-reserved and HMC ID */
6+
7+
struct hvpipe_source_info {
8+
struct list_head list; /* list of sources */
9+
u32 srcID;
10+
wait_queue_head_t recv_wqh; /* wake up poll() waitq */
11+
struct task_struct *tsk;
12+
};
13+
14+
#endif /* _PAPR_HVPIPE_H */

0 commit comments

Comments
 (0)