Path: blob/master/arch/powerpc/platforms/pseries/papr-rtas-common.c
26481 views
// SPDX-License-Identifier: GPL-2.0-only12#define pr_fmt(fmt) "papr-common: " fmt34#include <linux/types.h>5#include <linux/kernel.h>6#include <linux/signal.h>7#include <linux/slab.h>8#include <linux/file.h>9#include <linux/fs.h>10#include <linux/anon_inodes.h>11#include <linux/sched/signal.h>12#include "papr-rtas-common.h"1314/*15* Sequence based RTAS HCALL has to issue multiple times to retrieve16* complete data from the hypervisor. For some of these RTAS calls,17* the OS should not interleave calls with different input until the18* sequence is completed. So data is collected for these calls during19* ioctl handle and export to user space with read() handle.20* This file provides common functions needed for such sequence based21* RTAS calls Ex: ibm,get-vpd and ibm,get-indices.22*/2324bool papr_rtas_blob_has_data(const struct papr_rtas_blob *blob)25{26return blob->data && blob->len;27}2829void papr_rtas_blob_free(const struct papr_rtas_blob *blob)30{31if (blob) {32kvfree(blob->data);33kfree(blob);34}35}3637/**38* papr_rtas_blob_extend() - Append data to a &struct papr_rtas_blob.39* @blob: The blob to extend.40* @data: The new data to append to @blob.41* @len: The length of @data.42*43* Context: May sleep.44* Return: -ENOMEM on allocation failure, 0 otherwise.45*/46static int papr_rtas_blob_extend(struct papr_rtas_blob *blob,47const char *data, size_t len)48{49const size_t new_len = blob->len + len;50const size_t old_len = blob->len;51const char *old_ptr = blob->data;52char *new_ptr;5354new_ptr = kvrealloc(old_ptr, new_len, GFP_KERNEL_ACCOUNT);55if (!new_ptr)56return -ENOMEM;5758memcpy(&new_ptr[old_len], data, len);59blob->data = new_ptr;60blob->len = new_len;61return 0;62}6364/**65* papr_rtas_blob_generate() - Construct a new &struct papr_rtas_blob.66* @seq: work function of the caller that is called to obtain67* data with the caller RTAS call.68*69* The @work callback is invoked until it returns NULL. @seq is70* passed to @work in its first argument on each call. When71* @work returns data, it should store the data length in its72* second argument.73*74* Context: May sleep.75* Return: A completely populated &struct papr_rtas_blob, or NULL on error.76*/77static const struct papr_rtas_blob *78papr_rtas_blob_generate(struct papr_rtas_sequence *seq)79{80struct papr_rtas_blob *blob;81const char *buf;82size_t len;83int err = 0;8485blob = kzalloc(sizeof(*blob), GFP_KERNEL_ACCOUNT);86if (!blob)87return NULL;8889if (!seq->work)90return ERR_PTR(-EINVAL);919293while (err == 0 && (buf = seq->work(seq, &len)))94err = papr_rtas_blob_extend(blob, buf, len);9596if (err != 0 || !papr_rtas_blob_has_data(blob))97goto free_blob;9899return blob;100free_blob:101papr_rtas_blob_free(blob);102return NULL;103}104105int papr_rtas_sequence_set_err(struct papr_rtas_sequence *seq, int err)106{107/* Preserve the first error recorded. */108if (seq->error == 0)109seq->error = err;110111return seq->error;112}113114/*115* Higher-level retrieval code below. These functions use the116* papr_rtas_blob_* and sequence_* APIs defined above to create fd-based117* handles for consumption by user space.118*/119120/**121* papr_rtas_run_sequence() - Run a single retrieval sequence.122* @seq: Functions of the caller to complete the sequence123*124* Context: May sleep. Holds a mutex and an RTAS work area for its125* duration. Typically performs multiple sleepable slab126* allocations.127*128* Return: A populated &struct papr_rtas_blob on success. Encoded error129* pointer otherwise.130*/131static const struct papr_rtas_blob *papr_rtas_run_sequence(struct papr_rtas_sequence *seq)132{133const struct papr_rtas_blob *blob;134135if (seq->begin)136seq->begin(seq);137138blob = papr_rtas_blob_generate(seq);139if (!blob)140papr_rtas_sequence_set_err(seq, -ENOMEM);141142if (seq->end)143seq->end(seq);144145146if (seq->error) {147papr_rtas_blob_free(blob);148return ERR_PTR(seq->error);149}150151return blob;152}153154/**155* papr_rtas_retrieve() - Return the data blob that is exposed to156* user space.157* @seq: RTAS call specific functions to be invoked until the158* sequence is completed.159*160* Run sequences against @param until a blob is successfully161* instantiated, or a hard error is encountered, or a fatal signal is162* pending.163*164* Context: May sleep.165* Return: A fully populated data blob when successful. Encoded error166* pointer otherwise.167*/168const struct papr_rtas_blob *papr_rtas_retrieve(struct papr_rtas_sequence *seq)169{170const struct papr_rtas_blob *blob;171172/*173* EAGAIN means the sequence returns error with a -4 (data174* changed and need to start the sequence) status from RTAS calls175* and we should attempt a new sequence. PAPR+ (v2.13 R1–7.3.20–5176* - ibm,get-vpd, R1–7.3.17–6 - ibm,get-indices) indicates that177* this should be a transient condition, not something that178* happens continuously. But we'll stop trying on a fatal signal.179*/180do {181blob = papr_rtas_run_sequence(seq);182if (!IS_ERR(blob)) /* Success. */183break;184if (PTR_ERR(blob) != -EAGAIN) /* Hard error. */185break;186cond_resched();187} while (!fatal_signal_pending(current));188189return blob;190}191192/**193* papr_rtas_setup_file_interface - Complete the sequence and obtain194* the data and export to user space with fd-based handles. Then the195* user spave gets the data with read() handle.196* @seq: RTAS call specific functions to get the data.197* @fops: RTAS call specific file operations such as read().198* @name: RTAS call specific char device node.199*200* Return: FD handle for consumption by user space201*/202long papr_rtas_setup_file_interface(struct papr_rtas_sequence *seq,203const struct file_operations *fops,204char *name)205{206const struct papr_rtas_blob *blob;207struct file *file;208long ret;209int fd;210211blob = papr_rtas_retrieve(seq);212if (IS_ERR(blob))213return PTR_ERR(blob);214215fd = get_unused_fd_flags(O_RDONLY | O_CLOEXEC);216if (fd < 0) {217ret = fd;218goto free_blob;219}220221file = anon_inode_getfile_fmode(name, fops, (void *)blob,222O_RDONLY, FMODE_LSEEK | FMODE_PREAD);223if (IS_ERR(file)) {224ret = PTR_ERR(file);225goto put_fd;226}227228fd_install(fd, file);229return fd;230231put_fd:232put_unused_fd(fd);233free_blob:234papr_rtas_blob_free(blob);235return ret;236}237238/*239* papr_rtas_sequence_should_stop() - Determine whether RTAS retrieval240* sequence should continue.241*242* Examines the sequence error state and outputs of the last call to243* the specific RTAS to determine whether the sequence in progress244* should continue or stop.245*246* Return: True if the sequence has encountered an error or if all data247* for this sequence has been retrieved. False otherwise.248*/249bool papr_rtas_sequence_should_stop(const struct papr_rtas_sequence *seq,250s32 status, bool init_state)251{252bool done;253254if (seq->error)255return true;256257switch (status) {258case RTAS_SEQ_COMPLETE:259if (init_state)260done = false; /* Initial state. */261else262done = true; /* All data consumed. */263break;264case RTAS_SEQ_MORE_DATA:265done = false; /* More data available. */266break;267default:268done = true; /* Error encountered. */269break;270}271272return done;273}274275/*276* User space read to retrieve data for the corresponding RTAS call.277* papr_rtas_blob is filled with the data using the corresponding RTAS278* call sequence API.279*/280ssize_t papr_rtas_common_handle_read(struct file *file,281char __user *buf, size_t size, loff_t *off)282{283const struct papr_rtas_blob *blob = file->private_data;284285/* We should not instantiate a handle without any data attached. */286if (!papr_rtas_blob_has_data(blob)) {287pr_err_once("handle without data\n");288return -EIO;289}290291return simple_read_from_buffer(buf, size, off, blob->data, blob->len);292}293294int papr_rtas_common_handle_release(struct inode *inode,295struct file *file)296{297const struct papr_rtas_blob *blob = file->private_data;298299papr_rtas_blob_free(blob);300301return 0;302}303304loff_t papr_rtas_common_handle_seek(struct file *file, loff_t off,305int whence)306{307const struct papr_rtas_blob *blob = file->private_data;308309return fixed_size_llseek(file, off, whence, blob->len);310}311312313