[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