On Wed, 2025-03-12 at 10:55 +0530, Mukesh Kumar Chaurasiya wrote: > On Tue, Mar 11, 2025 at 03:50:42PM -0700, Haren Myneni wrote: > > The RTAS call can be normal where retrieves the data form the > > hypervisor once or sequence based RTAS call which has to > > issue multiple times until the complete data is obtained. For > > some of these sequence RTAS calls, the OS should not interleave > > calls with different input until the sequence is completed. > > The data is collected for each call and copy to the buffer > > for the entire sequence during ioctl() handle and then expose > > this buffer to the user space with read() handle. > > > > One such sequence RTAS call is ibm,get-vpd and its support is > > already included in the current code. To add the similar support > > for other sequence based calls, move the common functions in to > > separate file and update papr_rtas_sequence struct with the > > following callbacks so that RTAS call specific code will be > > defined and executed to complete the sequence. > > > > struct papr_rtas_sequence { > > int error; > > void params; > > void (*begin) (struct papr_rtas_sequence *); > > void (*end) (struct papr_rtas_sequence *); > > const char * (*work) (struct papr_rtas_sequence *, size_t > > *); > > }; > > > > params: Input parameters used to pass for RTAS call. > > Begin: RTAS call specific function to initialize data > > including work area allocation. > > End: RTAS call specific function to free up resources > > (free work area) after the sequence is completed. > > Work: The actual RTAS call specific function which collects > > the data from the hypervisor. > > > > Signed-off-by: Haren Myneni <ha...@linux.ibm.com> > > --- > > arch/powerpc/platforms/pseries/Makefile | 2 +- > > .../platforms/pseries/papr-rtas-common.c | 310 > > ++++++++++++++++ > > .../platforms/pseries/papr-rtas-common.h | 61 +++ > > arch/powerpc/platforms/pseries/papr-vpd.c | 351 +++----------- > > ---- > > 4 files changed, 416 insertions(+), 308 deletions(-) > > create mode 100644 arch/powerpc/platforms/pseries/papr-rtas- > > common.c > > create mode 100644 arch/powerpc/platforms/pseries/papr-rtas- > > common.h > > > > diff --git a/arch/powerpc/platforms/pseries/Makefile > > b/arch/powerpc/platforms/pseries/Makefile > > index 7bf506f6b8c8..697c216b70dc 100644 > > --- a/arch/powerpc/platforms/pseries/Makefile > > +++ b/arch/powerpc/platforms/pseries/Makefile > > @@ -3,7 +3,7 @@ ccflags-$(CONFIG_PPC_PSERIES_DEBUG) += -DDEBUG > > > > obj-y := lpar.o hvCall.o nvram.o reconfig.o \ > > of_helpers.o rtas-work-area.o papr-sysparm.o > > \ > > - papr-vpd.o \ > > + papr-rtas-common.o papr-vpd.o \ > > setup.o iommu.o event_sources.o ras.o \ > > firmware.o power.o dlpar.o mobility.o rng.o > > \ > > pci.o pci_dlpar.o eeh_pseries.o msi.o \ > > diff --git a/arch/powerpc/platforms/pseries/papr-rtas-common.c > > b/arch/powerpc/platforms/pseries/papr-rtas-common.c > > new file mode 100644 > > index 000000000000..2d0220209de0 > > --- /dev/null > > +++ b/arch/powerpc/platforms/pseries/papr-rtas-common.c > > @@ -0,0 +1,310 @@ > > +// SPDX-License-Identifier: GPL-2.0-only > > + > > +#define pr_fmt(fmt) "papr-common: " fmt > > + > > +#include <linux/types.h> > > +#include <linux/kernel.h> > > +#include <linux/signal.h> > > +#include <linux/slab.h> > > +#include <linux/file.h> > > +#include <linux/fs.h> > > +#include <linux/anon_inodes.h> > > +#include <linux/sched/signal.h> > > +#include "papr-rtas-common.h" > > + > > +/* > > + * Sequence based RTAS HCALL has to issue multiple times to > > retrieve > > + * complete data from the hypervisor. For some of these RTAS > > calls, > > + * the OS should not interleave calls with different input until > > the > > + * sequence is completed. So data is collected for these calls > > during > > + * ioctl handle and export to user space with read() handle. > > + * This file provides common functions needed for such sequence > > based > > + * RTAS calls Ex: ibm,get-vpd and ibm,get-indices. > > + */ > > + > > +bool papr_rtas_blob_has_data(const struct papr_rtas_blob *blob) > > +{ > > + return blob->data && blob->len; > > +} > > + > > +void papr_rtas_blob_free(const struct papr_rtas_blob *blob) > > +{ > > + if (blob) { > > + kvfree(blob->data); > > + kfree(blob); > > + } > > +} > > + > > +/** > > + * papr_rtas_blob_extend() - Append data to a &struct > > papr_rtas_blob. > > + * @blob: The blob to extend. > > + * @data: The new data to append to @blob. > > + * @len: The length of @data. > > + * > > + * Context: May sleep. > > + * Return: -ENOMEM on allocation failure, 0 otherwise. > > + */ > > +static int papr_rtas_blob_extend(struct papr_rtas_blob *blob, > > + const char *data, size_t len) > > +{ > > + const size_t new_len = blob->len + len; > > + const size_t old_len = blob->len; > > + const char *old_ptr = blob->data; > > + char *new_ptr; > > + > > + new_ptr = kvrealloc(old_ptr, new_len, GFP_KERNEL_ACCOUNT); > > + if (!new_ptr) > > + return -ENOMEM; > > + > > + memcpy(&new_ptr[old_len], data, len); > > + blob->data = new_ptr; > > + blob->len = new_len; > > + return 0; > > +} > > + > > +/** > > + * papr_rtas_blob_generate() - Construct a new &struct > > papr_rtas_blob. > > + * @seq: work function of the caller that is called to obtain > > + * data with the caller RTAS call. > > + * > > + * The @work callback is invoked until it returns NULL. @seq is > > + * passed to @work in its first argument on each call. When > > + * @work returns data, it should store the data length in its > > + * second argument. > > + * > > + * Context: May sleep. > > + * Return: A completely populated &struct papr_rtas_blob, or NULL > > on error. > > + */ > > +static const struct papr_rtas_blob * > > +papr_rtas_blob_generate(struct papr_rtas_sequence *seq) > > +{ > > + struct papr_rtas_blob *blob; > > + const char *buf; > > + size_t len; > > + int err = 0; > > + > > + blob = kzalloc(sizeof(*blob), GFP_KERNEL_ACCOUNT); > > + if (!blob) > > + return NULL; > > + > > + if (!seq->work) > > + return ERR_PTR(-EINVAL); > > + > > + > > + while (err == 0 && (buf = seq->work(seq, &len))) > > + err = papr_rtas_blob_extend(blob, buf, len); > > + > > + if (err != 0 || !papr_rtas_blob_has_data(blob)) > > + goto free_blob; > > + > > + return blob; > > +free_blob: > > + papr_rtas_blob_free(blob); > > + return NULL; > > +} > > + > > +int papr_rtas_sequence_set_err(struct papr_rtas_sequence *seq, int > > err) > > +{ > > + /* Preserve the first error recorded. */ > > + if (seq->error == 0) > > + seq->error = err; > > + > > + return seq->error; > > +} > > + > > +/* > > + * Higher-level retrieval code below. These functions use the > > + * papr_rtas_blob_* and sequence_* APIs defined above to create > > fd-based > > + * handles for consumption by user space. > > + */ > > + > > +/** > > + * papr_rtas_run_sequence() - Run a single retrieval sequence. > > + * @seq: Functions of the caller to complete the sequence > > + * > > + * Context: May sleep. Holds a mutex and an RTAS work area for its > > + * duration. Typically performs multiple sleepable slab > > + * allocations. > > + * > > + * Return: A populated &struct papr_rtas_blob on success. Encoded > > error > > + * pointer otherwise. > > + */ > > +static const struct papr_rtas_blob *papr_rtas_run_sequence(struct > > papr_rtas_sequence *seq) > > +{ > > + const struct papr_rtas_blob *blob; > > + > > + if (seq->begin) > > + seq->begin(seq); > > + > > + blob = papr_rtas_blob_generate(seq); > > + if (!blob) > > + papr_rtas_sequence_set_err(seq, -ENOMEM); > > + > > + if (seq->end) > > + seq->end(seq); > > + > > + > > + if (seq->error) { > > + papr_rtas_blob_free(blob); > > + return ERR_PTR(seq->error); > > + } > > + > > + return blob; > > +} > > + > > +/** > > + * papr_rtas_retrieve() - Return the data blob that is exposed to > > + * user space. > > + * @seq: RTAS call specific functions to be invoked until the > > + * sequence is completed. > > + * > > + * Run sequences against @param until a blob is successfully > > + * instantiated, or a hard error is encountered, or a fatal signal > > is > > + * pending. > > + * > > + * Context: May sleep. > > + * Return: A fully populated data blob when successful. Encoded > > error > > + * pointer otherwise. > > + */ > > +const struct papr_rtas_blob *papr_rtas_retrieve(struct > > papr_rtas_sequence *seq) > > +{ > > + const struct papr_rtas_blob *blob; > > + > > + /* > > + * EAGAIN means the sequence returns error with a -4 (data > > + * changed and need to start the sequence) status from RTAS > > calls > > + * and we should attempt a new sequence. PAPR+ (v2.13 > > R1–7.3.20–5 > > + * - ibm,get-vpd, R1–7.3.17–6 - ibm,get-indices) indicates that > > + * this should be a transient condition, not something that > > + * happens continuously. But we'll stop trying on a fatal > > signal. > > + */ > > + do { > > + blob = papr_rtas_run_sequence(seq); > > + if (!IS_ERR(blob)) /* Success. */ > > + break; > > + if (PTR_ERR(blob) != -EAGAIN) /* Hard error. */ > > + break; > > + cond_resched(); > > + } while (!fatal_signal_pending(current)); > > + > > + return blob; > > +} > > + > > +/** > > + * papr_rtas_setup_file_interface - Complete the sequence and > > obtain > > + * the data and export to user space with fd-based handles. Then > > the > > + * user spave gets the data with read() handle. > > + * @seq: RTAS call specific functions to get the data. > > + * @fops: RTAS call specific file operations such as read(). > > + * @name: RTAS call specific char device node. > > + * > > + * Return: FD handle for consumption by user space > > + */ > > +long papr_rtas_setup_file_interface(struct papr_rtas_sequence > > *seq, > > + const struct file_operations *fops, > > + char *name) > > +{ > > + const struct papr_rtas_blob *blob; > > + struct file *file; > > + long ret; > > + int fd; > > + > > + blob = papr_rtas_retrieve(seq); > > + if (IS_ERR(blob)) > > + return PTR_ERR(blob); > > + > > + fd = get_unused_fd_flags(O_RDONLY | O_CLOEXEC); > > + if (fd < 0) { > > + ret = fd; > > + goto free_blob; > > + } > > + > > + file = anon_inode_getfile(name, fops, (void *)blob, O_RDONLY); > > + if (IS_ERR(file)) { > > + ret = PTR_ERR(file); > > + goto put_fd; > > + } > > + > > + file->f_mode |= FMODE_LSEEK | FMODE_PREAD; > > + fd_install(fd, file); > > + return fd; > > + > > +put_fd: > > + put_unused_fd(fd); > > +free_blob: > > + papr_rtas_blob_free(blob); > > + return ret; > > +} > > + > > +/* > > + * papr_rtas_sequence_should_stop() - Determine whether RTAS > > retrieval > > + * sequence should continue. > > + * > > + * Examines the sequence error state and outputs of the last call > > to > > + * the specific RTAS to determine whether the sequence in progress > > + * should continue or stop. > > + * > > + * Return: True if the sequence has encountered an error or if all > > data > > + * for this sequence has been retrieved. False otherwise. > > + */ > > +bool papr_rtas_sequence_should_stop(const struct > > papr_rtas_sequence *seq, > > + s32 status, bool init_state) > > +{ > > + bool done; > > + > > + if (seq->error) > > + return true; > > + > > + switch (status) { > > + case RTAS_SEQ_COMPLETE: > > + if (init_state) > > + done = false; /* Initial state. */ > > + else > > + done = true; /* All data consumed. */ > > + break; > > + case RTAS_SEQ_MORE_DATA: > > + done = false; /* More data available. */ > > + break; > > + default: > > + done = true; /* Error encountered. */ > > + break; > > + } > > + > > + return done; > > +} > > + > > +/* > > + * User space read to retrieve data for the corresponding RTAS > > call. > > + * papr_rtas_blob is filled with the data using the corresponding > > RTAS > > + * call sequence API. > > + */ > > +ssize_t papr_rtas_common_handle_read(struct file *file, > > + char __user *buf, size_t size, loff_t *off) > > +{ > > + const struct papr_rtas_blob *blob = file->private_data; > > + > > + /* bug: we should not instantiate a handle without any data > > attached. */ if (!papr_rtas_blob_has_data(blob)) { > Line break is missing here.
Thanks for finding it. I did not find this with checkpatch initially. Looks like made this mistake in v4 revision.