Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753188AbdF2S3h (ORCPT ); Thu, 29 Jun 2017 14:29:37 -0400 Received: from mx0b-001b2d01.pphosted.com ([148.163.158.5]:35470 "EHLO mx0a-001b2d01.pphosted.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1752320AbdF2S3a (ORCPT ); Thu, 29 Jun 2017 14:29:30 -0400 Subject: Re: [PATCH V5] powerpc/powernv : Add support for OPAL-OCC command/response interface To: Cyril Bur , linuxppc-dev@lists.ozlabs.org References: <1498455138-6402-1-git-send-email-shilpa.bhat@linux.vnet.ibm.com> <1498538113.8812.1.camel@gmail.com> Cc: linux-kernel@vger.kernel.org, benh@kernel.crashing.org, paulus@samba.org, mpe@ellerman.id.au, svaidy@linux.vnet.ibm.com, ego@linux.vnet.ibm.com From: Shilpasri G Bhat Date: Thu, 29 Jun 2017 23:59:17 +0530 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Thunderbird/45.7.0 MIME-Version: 1.0 In-Reply-To: <1498538113.8812.1.camel@gmail.com> Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 7bit X-TM-AS-MML: disable x-cbid: 17062918-0040-0000-0000-000003384C07 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 17062918-0041-0000-0000-00000CB34D53 Message-Id: X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10432:,, definitions=2017-06-29_12:,, signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 spamscore=0 suspectscore=2 malwarescore=0 phishscore=0 adultscore=0 bulkscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1703280000 definitions=main-1706290297 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 14868 Lines: 493 On 06/27/2017 10:05 AM, Cyril Bur wrote: > On Mon, 2017-06-26 at 11:02 +0530, Shilpasri G Bhat wrote: >> In P9, OCC (On-Chip-Controller) supports shared memory based >> commad-response interface. Within the shared memory there is an OPAL >> command buffer and OCC response buffer that can be used to send >> inband commands to OCC. This patch adds a platform driver to support >> the command/response interface between OCC and the host. >> > > I feel obliged to check that an occ request_id can be zero, I'm sure > its fine - just have to ask, zero is so often special. > > I should also point out I don't know must about how the OCC works or > anything so I would be best if there were other eyes on this. > > Provided zero is an ok request_id: Yes zero is a valid request_id which can be sent to OCC. > Reviewed-by: Cyril Bur > Thanks for reviewing this patch. Regards, Shilpa >> Signed-off-by: Shilpasri G Bhat >> --- >> The skiboot patch for the interface is posted here: >> https://lists.ozlabs.org/pipermail/skiboot/2017-June/007960.html >> >> Changes from V4: >> - Add token as a parameter to the opal_occ_command() >> - Use per-occ counter for command request_id instead of using async >> token. >> >> arch/powerpc/include/asm/opal-api.h | 41 +++- >> arch/powerpc/include/asm/opal.h | 3 + >> arch/powerpc/platforms/powernv/Makefile | 2 +- >> arch/powerpc/platforms/powernv/opal-occ.c | 303 +++++++++++++++++++++++++ >> arch/powerpc/platforms/powernv/opal-wrappers.S | 1 + >> arch/powerpc/platforms/powernv/opal.c | 8 + >> 6 files changed, 356 insertions(+), 2 deletions(-) >> create mode 100644 arch/powerpc/platforms/powernv/opal-occ.c >> >> diff --git a/arch/powerpc/include/asm/opal-api.h b/arch/powerpc/include/asm/opal-api.h >> index cb3e624..011d86c 100644 >> --- a/arch/powerpc/include/asm/opal-api.h >> +++ b/arch/powerpc/include/asm/opal-api.h >> @@ -42,6 +42,10 @@ >> #define OPAL_I2C_STOP_ERR -24 >> #define OPAL_XIVE_PROVISIONING -31 >> #define OPAL_XIVE_FREE_ACTIVE -32 >> +#define OPAL_OCC_INVALID_STATE -33 >> +#define OPAL_OCC_BUSY -34 >> +#define OPAL_OCC_CMD_TIMEOUT -35 >> +#define OPAL_OCC_RSP_MISMATCH -36 >> >> /* API Tokens (in r0) */ >> #define OPAL_INVALID_CALL -1 >> @@ -190,7 +194,8 @@ >> #define OPAL_NPU_INIT_CONTEXT 146 >> #define OPAL_NPU_DESTROY_CONTEXT 147 >> #define OPAL_NPU_MAP_LPAR 148 >> -#define OPAL_LAST 148 >> +#define OPAL_OCC_COMMAND 149 >> +#define OPAL_LAST 149 >> >> /* Device tree flags */ >> >> @@ -829,6 +834,40 @@ struct opal_prd_msg_header { >> >> struct opal_prd_msg; >> >> +enum occ_cmd { >> + OCC_CMD_AMESTER_PASS_THRU = 0, >> + OCC_CMD_CLEAR_SENSOR_DATA, >> + OCC_CMD_SET_POWER_CAP, >> + OCC_CMD_SET_POWER_SHIFTING_RATIO, >> + OCC_CMD_SELECT_SENSOR_GROUPS, >> + OCC_CMD_LAST >> +}; >> + >> +struct opal_occ_cmd_rsp_msg { >> + __be64 cdata; >> + __be64 rdata; >> + __be16 cdata_size; >> + __be16 rdata_size; >> + u8 cmd; >> + u8 request_id; >> + u8 status; >> +}; >> + >> +struct opal_occ_cmd_data { >> + __be16 size; >> + u8 cmd; >> + u8 data[]; >> +}; >> + >> +struct opal_occ_rsp_data { >> + __be16 size; >> + u8 status; >> + u8 data[]; >> +}; >> + >> +#define MAX_OPAL_CMD_DATA_LENGTH 4090 >> +#define MAX_OCC_RSP_DATA_LENGTH 8698 >> + >> #define OCC_RESET 0 >> #define OCC_LOAD 1 >> #define OCC_THROTTLE 2 >> diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h >> index 03ed493..84659bd 100644 >> --- a/arch/powerpc/include/asm/opal.h >> +++ b/arch/powerpc/include/asm/opal.h >> @@ -346,6 +346,9 @@ static inline int opal_get_async_rc(struct opal_msg msg) >> >> void opal_wake_poller(void); >> >> +int64_t opal_occ_command(int chip_id, struct opal_occ_cmd_rsp_msg *msg, >> + int token, bool retry); >> + >> #endif /* __ASSEMBLY__ */ >> >> #endif /* _ASM_POWERPC_OPAL_H */ >> diff --git a/arch/powerpc/platforms/powernv/Makefile b/arch/powerpc/platforms/powernv/Makefile >> index b5d98cb..f5f0902 100644 >> --- a/arch/powerpc/platforms/powernv/Makefile >> +++ b/arch/powerpc/platforms/powernv/Makefile >> @@ -2,7 +2,7 @@ obj-y += setup.o opal-wrappers.o opal.o opal-async.o idle.o >> obj-y += opal-rtc.o opal-nvram.o opal-lpc.o opal-flash.o >> obj-y += rng.o opal-elog.o opal-dump.o opal-sysparam.o opal-sensor.o >> obj-y += opal-msglog.o opal-hmi.o opal-power.o opal-irqchip.o >> -obj-y += opal-kmsg.o >> +obj-y += opal-kmsg.o opal-occ.o >> >> obj-$(CONFIG_SMP) += smp.o subcore.o subcore-asm.o >> obj-$(CONFIG_PCI) += pci.o pci-ioda.o npu-dma.o >> diff --git a/arch/powerpc/platforms/powernv/opal-occ.c b/arch/powerpc/platforms/powernv/opal-occ.c >> new file mode 100644 >> index 0000000..440304f >> --- /dev/null >> +++ b/arch/powerpc/platforms/powernv/opal-occ.c >> @@ -0,0 +1,303 @@ >> +/* >> + * Copyright IBM Corporation 2017 >> + * >> + * This program is free software; you can redistribute it and/or modify >> + * it under the terms of the GNU General Public License version 2 as >> + * published by the Free Software Foundation. >> + * >> + * This program is distributed in the hope that it will be useful, >> + * but WITHOUT ANY WARRANTY; without even the implied warranty of >> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >> + * GNU General Public License for more details. >> + */ >> + >> +#define pr_fmt(fmt) "opal-occ: " fmt >> + >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> + >> +struct occ { >> + struct miscdevice dev; >> + struct opal_occ_rsp_data *rsp; >> + atomic_t session; >> + atomic_t cmd_in_progress; >> + atomic_t rsp_consumed; >> + int id; >> + u8 request_id; >> +} *occs; >> +static int nr_occs; >> + >> +static int __send_occ_command(struct opal_occ_cmd_rsp_msg *msg, >> + int chip_id, int token, bool retry) >> +{ >> + struct opal_msg async_msg; >> + int rc; >> + >> + rc = opal_occ_command(chip_id, msg, token, retry); >> + if (rc == OPAL_ASYNC_COMPLETION) { >> + rc = opal_async_wait_response(token, &async_msg); >> + if (rc) { >> + pr_devel("Failed to wait for async response %d\n", rc); >> + return rc; >> + } >> + } >> + >> + return rc ? rc : opal_get_async_rc(async_msg); >> +} >> + >> +static int send_occ_command(struct opal_occ_cmd_rsp_msg *msg, struct occ *occ) >> +{ >> + int token, rc; >> + >> + token = opal_async_get_token_interruptible(); >> + if (token < 0) { >> + pr_devel("Failed to get the token for OCC command %d (%d)\n", >> + msg->cmd, token); >> + return token; >> + } >> + >> + msg->request_id = occ->request_id++; >> + rc = __send_occ_command(msg, occ->id, token, false); >> + >> + switch (rc) { >> + case OPAL_OCC_CMD_TIMEOUT: >> + case OPAL_OCC_RSP_MISMATCH: >> + pr_devel("Failed OCC command with %d. Retrying it again\n", rc); >> + msg->request_id = occ->request_id++; >> + rc = __send_occ_command(msg, occ->id, token, true); >> + break; >> + default: >> + break; >> + } >> + >> + opal_async_release_token(token); >> + return opal_error_code(rc); >> +} >> + >> +static int opal_occ_cmd_prepare(struct opal_occ_cmd_data *cmd, struct occ *occ) >> +{ >> + struct opal_occ_cmd_rsp_msg msg; >> + int rc; >> + >> + msg.cmd = cmd->cmd; >> + msg.cdata = cpu_to_be64(__pa(cmd->data)); >> + msg.cdata_size = cpu_to_be16(cmd->size); >> + msg.rdata = cpu_to_be64(__pa(occ->rsp->data)); >> + >> + rc = send_occ_command(&msg, occ); >> + if (rc) { >> + pr_info("Failed OCC command %d with %d\n", cmd->cmd, rc); >> + return rc; >> + } >> + >> + occ->rsp->size = be16_to_cpu(msg.rdata_size); >> + occ->rsp->status = msg.status; >> + if (occ->rsp->size > MAX_OCC_RSP_DATA_LENGTH) { >> + pr_devel("Bigger OCC response size, clipping to %d\n", >> + MAX_OCC_RSP_DATA_LENGTH); >> + occ->rsp->size = MAX_OCC_RSP_DATA_LENGTH; >> + } >> + >> + atomic_set(&occ->rsp_consumed, 1); >> + return rc; >> +} >> + >> +static ssize_t opal_occ_write(struct file *file, const char __user *buf, >> + size_t count, loff_t *ppos) >> +{ >> + struct miscdevice *dev = file->private_data; >> + struct occ *occ = container_of(dev, struct occ, dev); >> + struct opal_occ_cmd_data *cmd; >> + int rc; >> + >> + if (count < sizeof(*cmd)) >> + return -EINVAL; >> + >> + if (atomic_cmpxchg(&occ->cmd_in_progress, 0, 1)) >> + return -EBUSY; >> + >> + cmd = kmalloc(count, GFP_KERNEL); >> + if (!cmd) { >> + rc = -ENOMEM; >> + goto out; >> + } >> + >> + rc = copy_from_user(cmd, buf, count); >> + if (rc) { >> + pr_err("Failed to copy OCC command request message\n"); >> + rc = -EFAULT; >> + goto free_cmd; >> + } >> + >> + if (cmd->size > MAX_OPAL_CMD_DATA_LENGTH) { >> + rc = -EINVAL; >> + goto free_cmd; >> + } >> + >> + rc = opal_occ_cmd_prepare(cmd, occ); >> + if (!rc) >> + rc = count; >> + >> +free_cmd: >> + kfree(cmd); >> +out: >> + atomic_set(&occ->cmd_in_progress, 0); >> + return rc; >> +} >> + >> +static ssize_t opal_occ_read(struct file *file, char __user *buf, >> + size_t count, loff_t *ppos) >> +{ >> + struct miscdevice *dev = file->private_data; >> + struct occ *occ = container_of(dev, struct occ, dev); >> + int rc; >> + >> + if (count < sizeof(*occ->rsp) + occ->rsp->size) >> + return -EINVAL; >> + >> + if (atomic_cmpxchg(&occ->cmd_in_progress, 0, 1)) >> + return -EBUSY; >> + >> + if (!atomic_cmpxchg(&occ->rsp_consumed, 1, 0)) { >> + rc = -EBUSY; >> + goto out; >> + } >> + >> + rc = copy_to_user((void __user *)buf, occ->rsp, >> + sizeof(occ->rsp) + occ->rsp->size); >> + if (rc) { >> + atomic_set(&occ->rsp_consumed, 1); >> + pr_err("Failed to copy OCC response data to user\n"); >> + } >> + >> +out: >> + atomic_set(&occ->cmd_in_progress, 0); >> + return rc ? rc : sizeof(*occ->rsp) + occ->rsp->size; >> +} >> + >> +static int opal_occ_open(struct inode *inode, struct file *file) >> +{ >> + struct miscdevice *dev = file->private_data; >> + struct occ *occ = container_of(dev, struct occ, dev); >> + >> + return atomic_cmpxchg(&occ->session, 0, 1) ? -EBUSY : 0; >> +} >> + >> +static int opal_occ_release(struct inode *inode, struct file *file) >> +{ >> + struct miscdevice *dev = file->private_data; >> + struct occ *occ = container_of(dev, struct occ, dev); >> + >> + atomic_set(&occ->session, 0); >> + >> + return 0; >> +} >> + >> +static const struct file_operations opal_occ_fops = { >> + .open = opal_occ_open, >> + .read = opal_occ_read, >> + .write = opal_occ_write, >> + .release = opal_occ_release, >> + .owner = THIS_MODULE, >> +}; >> + >> +#define MAX_POSSIBLE_CHIPS 256 >> + >> +static int opal_occ_probe(struct platform_device *pdev) >> +{ >> + unsigned int chip[MAX_POSSIBLE_CHIPS]; >> + unsigned int cpu; >> + unsigned int prev_chip_id = UINT_MAX; >> + int i, rc; >> + >> + for_each_possible_cpu(cpu) { >> + unsigned int id = cpu_to_chip_id(cpu); >> + >> + if (prev_chip_id != id) { >> + int j = nr_occs; >> + >> + while (--j >= 0) >> + if (chip[j] == id) >> + continue; >> + >> + prev_chip_id = id; >> + chip[nr_occs++] = id; >> + WARN_ON_ONCE(nr_occs >= MAX_POSSIBLE_CHIPS - 1); >> + } >> + } >> + >> + occs = kcalloc(nr_occs, sizeof(*occs), GFP_KERNEL); >> + if (!occs) >> + return -ENOMEM; >> + >> + for (i = 0; i < nr_occs; i++) { >> + char name[10]; >> + >> + occs[i].id = chip[i]; >> + occs[i].dev.minor = MISC_DYNAMIC_MINOR; >> + snprintf(name, 10, "occ%d", chip[i]); >> + occs[i].dev.name = name; >> + occs[i].dev.fops = &opal_occ_fops; >> + occs[i].rsp = kmalloc(sizeof(occs[i].rsp) + >> + MAX_OCC_RSP_DATA_LENGTH, >> + GFP_KERNEL); >> + if (!occs[i].rsp) { >> + rc = -ENOMEM; >> + goto free_occs; >> + } >> + >> + rc = misc_register(&occs[i].dev); >> + if (rc) >> + goto free_occ_rsp_data; >> + } >> + >> + return 0; >> + >> +free_occ_rsp_data: >> + kfree(occs[i].rsp); >> +free_occs: >> + while (--i >= 0) { >> + kfree(occs[i].rsp); >> + misc_deregister(&occs[i].dev); >> + } >> + kfree(occs); >> + >> + return rc; >> +} >> + >> +static int opal_occ_remove(struct platform_device *pdev) >> +{ >> + int i; >> + >> + for (i = 0; i < nr_occs; i++) { >> + kfree(occs[i].rsp); >> + misc_deregister(&occs[i].dev); >> + } >> + >> + kfree(occs); >> + return 0; >> +} >> + >> +static const struct of_device_id opal_occ_match[] = { >> + { .compatible = "ibm,opal-occ-cmd-rsp-interface" }, >> + { }, >> +}; >> + >> +static struct platform_driver opal_occ_driver = { >> + .driver = { >> + .name = "opal-occ", >> + .of_match_table = opal_occ_match, >> + }, >> + .probe = opal_occ_probe, >> + .remove = opal_occ_remove, >> +}; >> + >> +module_platform_driver(opal_occ_driver); >> + >> +MODULE_DESCRIPTION("PowerNV OPAL-OCC driver"); >> +MODULE_LICENSE("GPL"); >> diff --git a/arch/powerpc/platforms/powernv/opal-wrappers.S b/arch/powerpc/platforms/powernv/opal-wrappers.S >> index f620572..e6bf18d 100644 >> --- a/arch/powerpc/platforms/powernv/opal-wrappers.S >> +++ b/arch/powerpc/platforms/powernv/opal-wrappers.S >> @@ -310,3 +310,4 @@ OPAL_CALL(opal_xive_dump, OPAL_XIVE_DUMP); >> OPAL_CALL(opal_npu_init_context, OPAL_NPU_INIT_CONTEXT); >> OPAL_CALL(opal_npu_destroy_context, OPAL_NPU_DESTROY_CONTEXT); >> OPAL_CALL(opal_npu_map_lpar, OPAL_NPU_MAP_LPAR); >> +OPAL_CALL(opal_occ_command, OPAL_OCC_COMMAND); >> diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c >> index 59684b4..d87c61b 100644 >> --- a/arch/powerpc/platforms/powernv/opal.c >> +++ b/arch/powerpc/platforms/powernv/opal.c >> @@ -815,6 +815,9 @@ static int __init opal_init(void) >> opal_pdev_init("ibm,opal-flash"); >> opal_pdev_init("ibm,opal-prd"); >> >> + /* Initialize platform device: OCC_OPAL command-response interface */ >> + opal_pdev_init("ibm,opal-occ-cmd-rsp-interface"); >> + >> /* Initialise platform device: oppanel interface */ >> opal_pdev_init("ibm,opal-oppanel"); >> >> @@ -859,6 +862,7 @@ void opal_shutdown(void) >> EXPORT_SYMBOL_GPL(opal_flash_write); >> EXPORT_SYMBOL_GPL(opal_flash_erase); >> EXPORT_SYMBOL_GPL(opal_prd_msg); >> +EXPORT_SYMBOL_GPL(opal_occ_command); >> >> /* Convert a region of vmalloc memory to an opal sg list */ >> struct opal_sg_list *opal_vmalloc_to_sg_list(void *vmalloc_addr, >> @@ -937,6 +941,10 @@ int opal_error_code(int rc) >> case OPAL_UNSUPPORTED: return -EIO; >> case OPAL_HARDWARE: return -EIO; >> case OPAL_INTERNAL_ERROR: return -EIO; >> + case OPAL_OCC_BUSY: return -EBUSY; >> + case OPAL_OCC_INVALID_STATE: >> + case OPAL_OCC_CMD_TIMEOUT: >> + case OPAL_OCC_RSP_MISMATCH: return -EIO; >> default: >> pr_err("%s: unexpected OPAL error %d\n", __func__, rc); >> return -EIO; >