[PATCH v2 5/9] powerpc/pseries: Receive payload with ibm,receive-hvpipe-msg RTAS
Mahesh J Salgaonkar
mahesh at linux.ibm.com
Thu Aug 28 04:24:43 AEST 2025
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 <haren at 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 <mahesh at linux.ibm.com>
Thanks,
-Mahesh.
More information about the Linuxppc-dev
mailing list