Path: blob/master/arch/powerpc/platforms/pseries/papr-platform-dump.c
52072 views
// SPDX-License-Identifier: GPL-2.0-only12#define pr_fmt(fmt) "papr-platform-dump: " fmt34#include <linux/anon_inodes.h>5#include <linux/file.h>6#include <linux/fs.h>7#include <linux/init.h>8#include <linux/kernel.h>9#include <linux/miscdevice.h>10#include <asm/machdep.h>11#include <asm/rtas-work-area.h>12#include <asm/rtas.h>13#include <uapi/asm/papr-platform-dump.h>1415/*16* Function-specific return values for ibm,platform-dump, derived from17* PAPR+ v2.13 7.3.3.4.1 "ibm,platform-dump RTAS Call".18*/19#define RTAS_IBM_PLATFORM_DUMP_COMPLETE 0 /* Complete dump retrieved. */20#define RTAS_IBM_PLATFORM_DUMP_CONTINUE 1 /* Continue dump */21#define RTAS_NOT_AUTHORIZED -9002 /* Not Authorized */2223#define RTAS_IBM_PLATFORM_DUMP_START 2 /* Linux status to start dump */2425/**26* struct ibm_platform_dump_params - Parameters (in and out) for27* ibm,platform-dump28* @work_area: In: work area buffer for results.29* @buf_length: In: work area buffer length in bytes30* @dump_tag_hi: In: Most-significant 32 bits of a Dump_Tag representing31* an id of the dump being processed.32* @dump_tag_lo: In: Least-significant 32 bits of a Dump_Tag representing33* an id of the dump being processed.34* @sequence_hi: In: Sequence number in most-significant 32 bits.35* Out: Next sequence number in most-significant 32 bits.36* @sequence_lo: In: Sequence number in Least-significant 32 bits37* Out: Next sequence number in Least-significant 32 bits.38* @bytes_ret_hi: Out: Bytes written in most-significant 32 bits.39* @bytes_ret_lo: Out: Bytes written in Least-significant 32 bits.40* @status: Out: RTAS call status.41* @list: Maintain the list of dumps are in progress. Can42* retrieve multiple dumps with different dump IDs at43* the same time but not with the same dump ID. This list44* is used to determine whether the dump for the same ID45* is in progress.46*/47struct ibm_platform_dump_params {48struct rtas_work_area *work_area;49u32 buf_length;50u32 dump_tag_hi;51u32 dump_tag_lo;52u32 sequence_hi;53u32 sequence_lo;54u32 bytes_ret_hi;55u32 bytes_ret_lo;56s32 status;57struct list_head list;58};5960/*61* Multiple dumps with different dump IDs can be retrieved at the same62* time, but not with dame dump ID. platform_dump_list_mutex and63* platform_dump_list are used to prevent this behavior.64*/65static DEFINE_MUTEX(platform_dump_list_mutex);66static LIST_HEAD(platform_dump_list);6768/**69* rtas_ibm_platform_dump() - Call ibm,platform-dump to fill a work area70* buffer.71* @params: See &struct ibm_platform_dump_params.72* @buf_addr: Address of dump buffer (work_area)73* @buf_length: Length of the buffer in bytes (min. 1024)74*75* Calls ibm,platform-dump until it errors or successfully deposits data76* into the supplied work area. Handles RTAS retry statuses. Maps RTAS77* error statuses to reasonable errno values.78*79* Can request multiple dumps with different dump IDs at the same time,80* but not with the same dump ID which is prevented with the check in81* the ioctl code (papr_platform_dump_create_handle()).82*83* The caller should inspect @params.status to determine whether more84* calls are needed to complete the sequence.85*86* Context: May sleep.87* Return: -ve on error, 0 for dump complete and 1 for continue dump88*/89static int rtas_ibm_platform_dump(struct ibm_platform_dump_params *params,90phys_addr_t buf_addr, u32 buf_length)91{92u32 rets[4];93s32 fwrc;94int ret = 0;9596do {97fwrc = rtas_call(rtas_function_token(RTAS_FN_IBM_PLATFORM_DUMP),986, 5,99rets,100params->dump_tag_hi,101params->dump_tag_lo,102params->sequence_hi,103params->sequence_lo,104buf_addr,105buf_length);106} while (rtas_busy_delay(fwrc));107108switch (fwrc) {109case RTAS_HARDWARE_ERROR:110ret = -EIO;111break;112case RTAS_NOT_AUTHORIZED:113ret = -EPERM;114break;115case RTAS_IBM_PLATFORM_DUMP_CONTINUE:116case RTAS_IBM_PLATFORM_DUMP_COMPLETE:117params->sequence_hi = rets[0];118params->sequence_lo = rets[1];119params->bytes_ret_hi = rets[2];120params->bytes_ret_lo = rets[3];121break;122default:123ret = -EIO;124pr_err_ratelimited("unexpected ibm,platform-dump status %d\n",125fwrc);126break;127}128129params->status = fwrc;130return ret;131}132133/*134* Platform dump is used with multiple RTAS calls to retrieve the135* complete dump for the provided dump ID. Once the complete dump is136* retrieved, the hypervisor returns dump complete status (0) for the137* last RTAS call and expects the caller issues one more call with138* NULL buffer to invalidate the dump so that the hypervisor can remove139* the dump.140*141* After the specific dump is invalidated in the hypervisor, expect the142* dump complete status for the new sequence - the user space initiates143* new request for the same dump ID.144*/145static ssize_t papr_platform_dump_handle_read(struct file *file,146char __user *buf, size_t size, loff_t *off)147{148struct ibm_platform_dump_params *params = file->private_data;149u64 total_bytes;150s32 fwrc;151152/*153* Dump already completed with the previous read calls.154* In case if the user space issues further reads, returns155* -EINVAL.156*/157if (!params->buf_length) {158pr_warn_once("Platform dump completed for dump ID %llu\n",159(u64) (((u64)params->dump_tag_hi << 32) |160params->dump_tag_lo));161return -EINVAL;162}163164/*165* The hypervisor returns status 0 if no more data available to166* download. The dump will be invalidated with ioctl (see below).167*/168if (params->status == RTAS_IBM_PLATFORM_DUMP_COMPLETE) {169params->buf_length = 0;170/*171* Returns 0 to the user space so that user172* space read stops.173*/174return 0;175}176177if (size < SZ_1K) {178pr_err_once("Buffer length should be minimum 1024 bytes\n");179return -EINVAL;180} else if (size > params->buf_length) {181/*182* Allocate 4K work area. So if the user requests > 4K,183* resize the buffer length.184*/185size = params->buf_length;186}187188fwrc = rtas_ibm_platform_dump(params,189rtas_work_area_phys(params->work_area),190size);191if (fwrc < 0)192return fwrc;193194total_bytes = (u64) (((u64)params->bytes_ret_hi << 32) |195params->bytes_ret_lo);196197/*198* Kernel or firmware bug, do not continue.199*/200if (WARN(total_bytes > size, "possible write beyond end of work area"))201return -EFAULT;202203if (copy_to_user(buf, rtas_work_area_raw_buf(params->work_area),204total_bytes))205return -EFAULT;206207return total_bytes;208}209210static int papr_platform_dump_handle_release(struct inode *inode,211struct file *file)212{213struct ibm_platform_dump_params *params = file->private_data;214215if (params->work_area)216rtas_work_area_free(params->work_area);217218mutex_lock(&platform_dump_list_mutex);219list_del(¶ms->list);220mutex_unlock(&platform_dump_list_mutex);221222kfree(params);223file->private_data = NULL;224return 0;225}226227/*228* This ioctl is used to invalidate the dump assuming the user space229* issue this ioctl after obtain the complete dump.230* Issue the last RTAS call with NULL buffer to invalidate the dump231* which means dump will be freed in the hypervisor.232*/233static long papr_platform_dump_invalidate_ioctl(struct file *file,234unsigned int ioctl, unsigned long arg)235{236struct ibm_platform_dump_params *params;237u64 __user *argp = (void __user *)arg;238u64 param_dump_tag, dump_tag;239240if (ioctl != PAPR_PLATFORM_DUMP_IOC_INVALIDATE)241return -ENOIOCTLCMD;242243if (get_user(dump_tag, argp))244return -EFAULT;245246/*247* private_data is freeded during release(), so should not248* happen.249*/250if (!file->private_data) {251pr_err("No valid FD to invalidate dump for the ID(%llu)\n",252dump_tag);253return -EINVAL;254}255256params = file->private_data;257param_dump_tag = (u64) (((u64)params->dump_tag_hi << 32) |258params->dump_tag_lo);259if (dump_tag != param_dump_tag) {260pr_err("Invalid dump ID(%llu) to invalidate dump\n",261dump_tag);262return -EINVAL;263}264265if (params->status != RTAS_IBM_PLATFORM_DUMP_COMPLETE) {266pr_err("Platform dump is not complete, but requested "267"to invalidate dump for ID(%llu)\n",268dump_tag);269return -EINPROGRESS;270}271272return rtas_ibm_platform_dump(params, 0, 0);273}274275static const struct file_operations papr_platform_dump_handle_ops = {276.read = papr_platform_dump_handle_read,277.release = papr_platform_dump_handle_release,278.unlocked_ioctl = papr_platform_dump_invalidate_ioctl,279};280281/**282* papr_platform_dump_create_handle() - Create a fd-based handle for283* reading platform dump284*285* Handler for PAPR_PLATFORM_DUMP_IOC_CREATE_HANDLE ioctl command286* Allocates RTAS parameter struct and work area and attached to the287* file descriptor for reading by user space with the multiple RTAS288* calls until the dump is completed. This memory allocation is freed289* when the file is released.290*291* Multiple dump requests with different IDs are allowed at the same292* time, but not with the same dump ID. So if the user space is293* already opened file descriptor for the specific dump ID, return294* -EALREADY for the next request.295*296* @dump_tag: Dump ID for the dump requested to retrieve from the297* hypervisor298*299* Return: The installed fd number if successful, -ve errno otherwise.300*/301static long papr_platform_dump_create_handle(u64 dump_tag)302{303struct ibm_platform_dump_params *params;304u64 param_dump_tag;305int fd;306307/*308* Return failure if the user space is already opened FD for309* the specific dump ID. This check will prevent multiple dump310* requests for the same dump ID at the same time. Generally311* should not expect this, but in case.312*/313list_for_each_entry(params, &platform_dump_list, list) {314param_dump_tag = (u64) (((u64)params->dump_tag_hi << 32) |315params->dump_tag_lo);316if (dump_tag == param_dump_tag) {317pr_err("Platform dump for ID(%llu) is already in progress\n",318dump_tag);319return -EALREADY;320}321}322323params = kzalloc(sizeof(struct ibm_platform_dump_params),324GFP_KERNEL_ACCOUNT);325if (!params)326return -ENOMEM;327328params->work_area = rtas_work_area_alloc(SZ_4K);329params->buf_length = SZ_4K;330params->dump_tag_hi = (u32)(dump_tag >> 32);331params->dump_tag_lo = (u32)(dump_tag & 0x00000000ffffffffULL);332params->status = RTAS_IBM_PLATFORM_DUMP_START;333334fd = FD_ADD(O_RDONLY | O_CLOEXEC,335anon_inode_getfile_fmode("[papr-platform-dump]",336&papr_platform_dump_handle_ops,337(void *)params, O_RDONLY,338FMODE_LSEEK | FMODE_PREAD));339if (fd < 0) {340rtas_work_area_free(params->work_area);341kfree(params);342return fd;343}344345list_add(¶ms->list, &platform_dump_list);346347pr_info("%s (%d) initiated platform dump for dump tag %llu\n",348current->comm, current->pid, dump_tag);349return fd;350}351352/*353* Top-level ioctl handler for /dev/papr-platform-dump.354*/355static long papr_platform_dump_dev_ioctl(struct file *filp,356unsigned int ioctl,357unsigned long arg)358{359u64 __user *argp = (void __user *)arg;360u64 dump_tag;361long ret;362363if (get_user(dump_tag, argp))364return -EFAULT;365366switch (ioctl) {367case PAPR_PLATFORM_DUMP_IOC_CREATE_HANDLE:368mutex_lock(&platform_dump_list_mutex);369ret = papr_platform_dump_create_handle(dump_tag);370mutex_unlock(&platform_dump_list_mutex);371break;372default:373ret = -ENOIOCTLCMD;374break;375}376return ret;377}378379static const struct file_operations papr_platform_dump_ops = {380.unlocked_ioctl = papr_platform_dump_dev_ioctl,381};382383static struct miscdevice papr_platform_dump_dev = {384.minor = MISC_DYNAMIC_MINOR,385.name = "papr-platform-dump",386.fops = &papr_platform_dump_ops,387};388389static __init int papr_platform_dump_init(void)390{391if (!rtas_function_implemented(RTAS_FN_IBM_PLATFORM_DUMP))392return -ENODEV;393394return misc_register(&papr_platform_dump_dev);395}396machine_device_initcall(pseries, papr_platform_dump_init);397398399