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.


Reply via email to