On 2025-08-12 15:57:09 Tue, Haren Myneni wrote: > ibm,receive-hvpipe-msg RTAS call is used to receive data from the > source (Ex: Hardware Management Console) over the hypervisor > pipe. The hypervisor will signal the OS via a Hypervisor Pipe > Event external interrupt when data is available to be received > from the pipe and the event message has the source ID and the > message type such as payload or closed pipe to the specific > source. The hypervisor will not generate another interrupt for > the next payload until the partition reads the previous payload. > It means the hvpipe is blocked and will not deliver other events > for any source. The maximum data length of 4048 bytes is > supported with this RTAS call right now. > > The user space uses read() to receive data from HMC which issues > ibm,receive-hvpipe-msg RTAS and the kernel returns the buffer > length (including papr_hvpipe_hdr length) to the user space for > success or RTAS failure error. If the message is regarding the > pipe closed, kernel just returns the papr_hvpipe_hdr with > flags = HVPIPE_LOST_CONNECTION and expects the user space to > close FD for the corresponding source. > > bm,receive-hvpipe-msg RTAS call passes the buffer and returns > the source ID from where this payload is received and the > payload length. > > Signed-off-by: Haren Myneni <ha...@linux.ibm.com> > --- > arch/powerpc/platforms/pseries/papr-hvpipe.c | 164 ++++++++++++++++++- > arch/powerpc/platforms/pseries/papr-hvpipe.h | 1 + > 2 files changed, 163 insertions(+), 2 deletions(-) > > diff --git a/arch/powerpc/platforms/pseries/papr-hvpipe.c > b/arch/powerpc/platforms/pseries/papr-hvpipe.c > index c30f4d75e645..21483ea09489 100644 > --- a/arch/powerpc/platforms/pseries/papr-hvpipe.c > +++ b/arch/powerpc/platforms/pseries/papr-hvpipe.c > @@ -60,6 +60,54 @@ static LIST_HEAD(hvpipe_src_list); > * return code for failure. > */ > > +/* > + * ibm,receive-hvpipe-msg RTAS call. > + * @area: Caller-provided work area buffer for results. > + * @srcID: Source ID returned by the RTAS call. > + * @bytesw: Bytes written by RTAS call to @area. > + */ > +static int rtas_ibm_receive_hvpipe_msg(struct rtas_work_area *area, > + u32 *srcID, u32 *bytesw) > +{ > + const s32 token = rtas_function_token(RTAS_FN_IBM_RECEIVE_HVPIPE_MSG); > + u32 rets[2]; > + s32 fwrc; > + int ret; > + > + if (token == RTAS_UNKNOWN_SERVICE) > + return -ENOENT; > + > + do { > + fwrc = rtas_call(token, 2, 3, rets, > + rtas_work_area_phys(area), > + rtas_work_area_size(area)); > + > + } while (rtas_busy_delay(fwrc)); > + > + switch (fwrc) { > + case RTAS_SUCCESS: > + *srcID = rets[0]; > + *bytesw = rets[1]; > + ret = 0; > + break; > + case RTAS_HARDWARE_ERROR: > + ret = -EIO; > + break; > + case RTAS_INVALID_PARAMETER: > + ret = -EINVAL; > + break; > + case RTAS_FUNC_NOT_SUPPORTED: > + ret = -EOPNOTSUPP; > + break; > + default: > + ret = -EIO; > + pr_err_ratelimited("unexpected ibm,receive-hvpipe-msg status > %d\n", fwrc); > + break; > + } > + > + return ret; > +} > + > /* > * ibm,send-hvpipe-msg RTAS call > * @area: Caller-provided work area buffer to send. > @@ -116,9 +164,60 @@ static struct hvpipe_source_info *hvpipe_find_source(u32 > srcID) > return NULL; > } > > +/* > + * This work function collects receive buffer with recv HVPIPE > + * RTAS call. Called from read() > + * @buf: User specified buffer to copy the payload that returned > + * from recv HVPIPE RTAS. > + * @size: Size of buffer user passed. > + */ > +static int hvpipe_rtas_recv_msg(char __user *buf, int size) > +{ > + struct rtas_work_area *work_area; > + u32 srcID, bytes_written; > + int ret; > + > + work_area = rtas_work_area_alloc(SZ_4K); > + if (!work_area) { > + pr_err("Could not allocate RTAS buffer for recv pipe\n"); > + return -ENOMEM; > + } > + > + ret = rtas_ibm_receive_hvpipe_msg(work_area, &srcID, > + &bytes_written); > + if (!ret) { > + /* > + * Recv HVPIPE RTAS is successful. > + * When releasing FD or no one is waiting on the > + * specific source, issue recv HVPIPE RTAS call > + * so that pipe is not blocked - this func is called > + * with NULL buf. > + */ > + if (buf) { > + if (size < bytes_written) { > + pr_err("Received the payload size = %d, but the > buffer size = %d\n", > + bytes_written, size); > + bytes_written = size; > + } > + ret = copy_to_user(buf, > + rtas_work_area_raw_buf(work_area), > + bytes_written); > + if (!ret) > + ret = bytes_written; > + } > + } else { > + pr_err("ibm,receive-hvpipe-msg failed with %d\n", > + ret); > + } > + > + rtas_work_area_free(work_area); > + return ret; > +} > + > /* > * papr_hvpipe_handle_write - Issue send HVPIPE RTAS and return > - * the RTAS status to the user space > + * the size (payload + HVPIPE_HDR_LEN) for RTAS success. > + * Otherwise returns the status of RTAS to the user space > */ > static ssize_t papr_hvpipe_handle_write(struct file *file, > const char __user *buf, size_t size, loff_t *off) > @@ -217,11 +316,72 @@ static ssize_t papr_hvpipe_handle_read(struct file > *file, > { > > struct hvpipe_source_info *src_info = file->private_data; > + struct papr_hvpipe_hdr hdr; > + long ret; > > if (!src_info) > return -EIO; > > - return 0; > + /* > + * Max payload is 4048 (HVPIPE_MAX_WRITE_BUFFER_SIZE) > + */ > + if ((size > (HVPIPE_HDR_LEN + HVPIPE_MAX_WRITE_BUFFER_SIZE)) || > + (size < HVPIPE_HDR_LEN)) > + return -EINVAL; > + > + /* > + * Payload is not available to receive or source pipe > + * is not closed. > + */ > + if (!src_info->hvpipe_status) > + return 0; > + > + hdr.version = 0; > + hdr.flags = 0; > + > + /* > + * In case if the hvpipe has payload and also the > + * hypervisor closed the pipe to the source, retrieve > + * the payload and return to the user space first and > + * then notify the userspace about the hvpipe close in > + * next read(). > + */ > + if (src_info->hvpipe_status & HVPIPE_MSG_AVAILABLE) > + hdr.flags = HVPIPE_MSG_AVAILABLE; > + else if (src_info->hvpipe_status & HVPIPE_LOST_CONNECTION) > + hdr.flags = HVPIPE_LOST_CONNECTION; > + else > + /* > + * Should not be here without one of the above > + * flags set > + */ > + return -EIO; > + > + ret = copy_to_user(buf, &hdr, HVPIPE_HDR_LEN); > + if (ret) > + return ret; > + > + /* > + * Message event has payload, so get the payload with > + * recv HVPIPE RTAS. > + */ > + if (hdr.flags & HVPIPE_MSG_AVAILABLE) { > + ret = hvpipe_rtas_recv_msg(buf + HVPIPE_HDR_LEN, > + size - HVPIPE_HDR_LEN); > + if (ret > 0) { > + src_info->hvpipe_status &= ~HVPIPE_MSG_AVAILABLE; > + ret += HVPIPE_HDR_LEN; > + } > + } else if (hdr.flags & HVPIPE_LOST_CONNECTION) { > + /* > + * Hypervisor is closing the pipe for the specific > + * source. So notify user space. > + */ > + src_info->hvpipe_status &= ~HVPIPE_LOST_CONNECTION; > + ret = HVPIPE_HDR_LEN; > + } > + > + return ret; > }
Looks good to me. Reviewed-by: Mahesh Salgaonkar <mah...@linux.ibm.com> Thanks, -Mahesh.