Path: blob/master/arch/powerpc/platforms/pseries/papr-platform-dump.c
26481 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;305struct file *file;306long err;307int fd;308309/*310* Return failure if the user space is already opened FD for311* the specific dump ID. This check will prevent multiple dump312* requests for the same dump ID at the same time. Generally313* should not expect this, but in case.314*/315list_for_each_entry(params, &platform_dump_list, list) {316param_dump_tag = (u64) (((u64)params->dump_tag_hi << 32) |317params->dump_tag_lo);318if (dump_tag == param_dump_tag) {319pr_err("Platform dump for ID(%llu) is already in progress\n",320dump_tag);321return -EALREADY;322}323}324325params = kzalloc(sizeof(struct ibm_platform_dump_params),326GFP_KERNEL_ACCOUNT);327if (!params)328return -ENOMEM;329330params->work_area = rtas_work_area_alloc(SZ_4K);331params->buf_length = SZ_4K;332params->dump_tag_hi = (u32)(dump_tag >> 32);333params->dump_tag_lo = (u32)(dump_tag & 0x00000000ffffffffULL);334params->status = RTAS_IBM_PLATFORM_DUMP_START;335336fd = get_unused_fd_flags(O_RDONLY | O_CLOEXEC);337if (fd < 0) {338err = fd;339goto free_area;340}341342file = anon_inode_getfile_fmode("[papr-platform-dump]",343&papr_platform_dump_handle_ops,344(void *)params, O_RDONLY,345FMODE_LSEEK | FMODE_PREAD);346if (IS_ERR(file)) {347err = PTR_ERR(file);348goto put_fd;349}350351fd_install(fd, file);352353list_add(¶ms->list, &platform_dump_list);354355pr_info("%s (%d) initiated platform dump for dump tag %llu\n",356current->comm, current->pid, dump_tag);357return fd;358put_fd:359put_unused_fd(fd);360free_area:361rtas_work_area_free(params->work_area);362kfree(params);363return err;364}365366/*367* Top-level ioctl handler for /dev/papr-platform-dump.368*/369static long papr_platform_dump_dev_ioctl(struct file *filp,370unsigned int ioctl,371unsigned long arg)372{373u64 __user *argp = (void __user *)arg;374u64 dump_tag;375long ret;376377if (get_user(dump_tag, argp))378return -EFAULT;379380switch (ioctl) {381case PAPR_PLATFORM_DUMP_IOC_CREATE_HANDLE:382mutex_lock(&platform_dump_list_mutex);383ret = papr_platform_dump_create_handle(dump_tag);384mutex_unlock(&platform_dump_list_mutex);385break;386default:387ret = -ENOIOCTLCMD;388break;389}390return ret;391}392393static const struct file_operations papr_platform_dump_ops = {394.unlocked_ioctl = papr_platform_dump_dev_ioctl,395};396397static struct miscdevice papr_platform_dump_dev = {398.minor = MISC_DYNAMIC_MINOR,399.name = "papr-platform-dump",400.fops = &papr_platform_dump_ops,401};402403static __init int papr_platform_dump_init(void)404{405if (!rtas_function_implemented(RTAS_FN_IBM_PLATFORM_DUMP))406return -ENODEV;407408return misc_register(&papr_platform_dump_dev);409}410machine_device_initcall(pseries, papr_platform_dump_init);411412413