From patchwork Sun Nov 28 15:44:41 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tomasz Duszynski X-Patchwork-Id: 104737 X-Patchwork-Delegate: jerinj@marvell.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id B80E7A0548; Sun, 28 Nov 2021 16:47:06 +0100 (CET) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id A43D342794; Sun, 28 Nov 2021 16:46:29 +0100 (CET) Received: from mx0b-0016f401.pphosted.com (mx0a-0016f401.pphosted.com [67.231.148.174]) by mails.dpdk.org (Postfix) with ESMTP id 7D7CE42777 for ; Sun, 28 Nov 2021 16:46:23 +0100 (CET) Received: from pps.filterd (m0045849.ppops.net [127.0.0.1]) by mx0a-0016f401.pphosted.com (8.16.1.2/8.16.1.2) with ESMTP id 1ASCbSpg016875; Sun, 28 Nov 2021 07:46:22 -0800 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=marvell.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding : content-type; s=pfpt0220; bh=4So139tN91TWxI2Es5tnQYe6bAVusaiDpAdo3738R3s=; b=Zvn5vids3PnL0KOwwGPFs4zz6Lh4c8vTF4lr38VRSE33rMc1R1Z2x1bIaS7aPR2SQFe9 196gX0/1OmrWsKu4LIzgqkmhzhhI4wNnSaeoplfHO9iRKhLuobTV/j9mldn9VoMaTU5x X4LP8jLTJzoqI39zMCTrRnfXCcXebUVF1+a5odFd4xVX7QyETLHiAKXJidq+w10dz17k qY5QodVtp5J+n55It7N7v7DwPHWFJc+rTBKNojpnkCoHo6c9HMBFok0o7O5Ty8vu6x0/ yj47Rknbpc1J95iJlPWcrFcDgxq145bIgBjqoNdAuYSfNn3mdowS6FXtD2s0XthxwdHa pA== Received: from dc5-exch02.marvell.com ([199.233.59.182]) by mx0a-0016f401.pphosted.com (PPS) with ESMTPS id 3ckjwvb4gk-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-SHA384 bits=256 verify=NOT); Sun, 28 Nov 2021 07:46:22 -0800 Received: from DC5-EXCH01.marvell.com (10.69.176.38) by DC5-EXCH02.marvell.com (10.69.176.39) with Microsoft SMTP Server (TLS) id 15.0.1497.18; Sun, 28 Nov 2021 07:46:20 -0800 Received: from maili.marvell.com (10.69.176.80) by DC5-EXCH01.marvell.com (10.69.176.38) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Sun, 28 Nov 2021 07:46:20 -0800 Received: from localhost.localdomain (unknown [10.28.34.39]) by maili.marvell.com (Postfix) with ESMTP id 72C333F70C4; Sun, 28 Nov 2021 07:46:19 -0800 (PST) From: Tomasz Duszynski To: CC: , , Tomasz Duszynski Subject: [PATCH v2 09/10] raw/cnxk_gpio: support custom irq handlers Date: Sun, 28 Nov 2021 16:44:41 +0100 Message-ID: <20211128154442.4029049-10-tduszynski@marvell.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20211128154442.4029049-1-tduszynski@marvell.com> References: <20211117002155.293267-1-tduszynski@marvell.com> <20211128154442.4029049-1-tduszynski@marvell.com> MIME-Version: 1.0 X-Proofpoint-ORIG-GUID: Yh1QQweXJr0ggrFuHyH-rags--4lQlp0 X-Proofpoint-GUID: Yh1QQweXJr0ggrFuHyH-rags--4lQlp0 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.205,Aquarius:18.0.790,Hydra:6.0.425,FMLib:17.0.607.475 definitions=2021-11-28_06,2021-11-28_01,2020-04-07_01 X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Add support for custom interrupt handlers. Custom interrupt handlers bypass kernel completely and are meant for fast and low latency access to GPIO state. Signed-off-by: Tomasz Duszynski --- doc/guides/rawdevs/cnxk_gpio.rst | 21 +++ drivers/raw/cnxk_gpio/cnxk_gpio.c | 37 ++++ drivers/raw/cnxk_gpio/cnxk_gpio.h | 8 + drivers/raw/cnxk_gpio/cnxk_gpio_irq.c | 216 ++++++++++++++++++++++ drivers/raw/cnxk_gpio/meson.build | 1 + drivers/raw/cnxk_gpio/rte_pmd_cnxk_gpio.h | 116 ++++++++++++ 6 files changed, 399 insertions(+) create mode 100644 drivers/raw/cnxk_gpio/cnxk_gpio_irq.c diff --git a/doc/guides/rawdevs/cnxk_gpio.rst b/doc/guides/rawdevs/cnxk_gpio.rst index f6c3c942c5..ad93ec0d44 100644 --- a/doc/guides/rawdevs/cnxk_gpio.rst +++ b/doc/guides/rawdevs/cnxk_gpio.rst @@ -161,3 +161,24 @@ Payload contains an integer set to 0 or 1. The latter means inverted logic is turned on. Consider using ``rte_pmd_gpio_get_pin_active_low()`` wrapper. + +Request interrupt +~~~~~~~~~~~~~~~~~ + +Message is used to install custom interrupt handler. + +Message must have type set to ``CNXK_GPIO_MSG_TYPE_REGISTER_IRQ``. + +Payload needs to be set to ``struct cnxk_gpio_irq`` which describes interrupt +being requested. + +Consider using ``rte_pmd_gpio_register_gpio()`` wrapper. + +Free interrupt +~~~~~~~~~~~~~~ + +Message is used to remove installed interrupt handler. + +Message must have type set to ``CNXK_GPIO_MSG_TYPE_UNREGISTER_IRQ``. + +Consider using ``rte_pmd_gpio_unregister_gpio()`` wrapper. diff --git a/drivers/raw/cnxk_gpio/cnxk_gpio.c b/drivers/raw/cnxk_gpio/cnxk_gpio.c index c09bc5d56e..d39d203245 100644 --- a/drivers/raw/cnxk_gpio/cnxk_gpio.c +++ b/drivers/raw/cnxk_gpio/cnxk_gpio.c @@ -335,6 +335,28 @@ cnxk_gpio_name_to_dir(const char *name) return cnxk_gpio_dir_name[i].dir; } +static int +cnxk_gpio_register_irq(struct cnxk_gpio *gpio, struct cnxk_gpio_irq *irq) +{ + int ret; + + ret = cnxk_gpio_irq_request(gpio->num - gpio->gpiochip->base, irq->cpu); + if (ret) + return ret; + + gpio->handler = irq->handler; + gpio->data = irq->data; + gpio->cpu = irq->cpu; + + return 0; +} + +static int +cnxk_gpio_unregister_irq(struct cnxk_gpio *gpio) +{ + return cnxk_gpio_irq_free(gpio->num - gpio->gpiochip->base); +} + static int cnxk_gpio_process_buf(struct cnxk_gpio *gpio, struct rte_rawdev_buf *rbuf) { @@ -416,6 +438,13 @@ cnxk_gpio_process_buf(struct cnxk_gpio *gpio, struct rte_rawdev_buf *rbuf) *(int *)rsp = val; break; + case CNXK_GPIO_MSG_TYPE_REGISTER_IRQ: + ret = cnxk_gpio_register_irq(gpio, + (struct cnxk_gpio_irq *)msg->data); + break; + case CNXK_GPIO_MSG_TYPE_UNREGISTER_IRQ: + ret = cnxk_gpio_unregister_irq(gpio); + break; default: return -EINVAL; } @@ -519,6 +548,10 @@ cnxk_gpio_probe(struct rte_vdev_device *dev) if (ret) goto out; + ret = cnxk_gpio_irq_init(gpiochip); + if (ret) + goto out; + /* read gpio base */ snprintf(buf, sizeof(buf), "%s/gpiochip%d/base", CNXK_GPIO_CLASS_PATH, gpiochip->num); @@ -577,10 +610,14 @@ cnxk_gpio_remove(struct rte_vdev_device *dev) if (!gpio) continue; + if (gpio->handler) + cnxk_gpio_unregister_irq(gpio); + cnxk_gpio_queue_release(rawdev, gpio->num); } rte_free(gpiochip->gpios); + cnxk_gpio_irq_fini(); rte_rawdev_pmd_release(rawdev); return 0; diff --git a/drivers/raw/cnxk_gpio/cnxk_gpio.h b/drivers/raw/cnxk_gpio/cnxk_gpio.h index 6b54ebe6e6..c052ca5735 100644 --- a/drivers/raw/cnxk_gpio/cnxk_gpio.h +++ b/drivers/raw/cnxk_gpio/cnxk_gpio.h @@ -11,6 +11,9 @@ struct cnxk_gpio { struct cnxk_gpiochip *gpiochip; void *rsp; int num; + void (*handler)(int gpio, void *data); + void *data; + int cpu; }; struct cnxk_gpiochip { @@ -20,4 +23,9 @@ struct cnxk_gpiochip { struct cnxk_gpio **gpios; }; +int cnxk_gpio_irq_init(struct cnxk_gpiochip *gpiochip); +void cnxk_gpio_irq_fini(void); +int cnxk_gpio_irq_request(int gpio, int cpu); +int cnxk_gpio_irq_free(int gpio); + #endif /* _CNXK_GPIO_H_ */ diff --git a/drivers/raw/cnxk_gpio/cnxk_gpio_irq.c b/drivers/raw/cnxk_gpio/cnxk_gpio_irq.c new file mode 100644 index 0000000000..2fa8e69899 --- /dev/null +++ b/drivers/raw/cnxk_gpio/cnxk_gpio_irq.c @@ -0,0 +1,216 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(C) 2021 Marvell. + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include "cnxk_gpio.h" + +#define OTX_IOC_MAGIC 0xF2 +#define OTX_IOC_SET_GPIO_HANDLER \ + _IOW(OTX_IOC_MAGIC, 1, struct otx_gpio_usr_data) +#define OTX_IOC_CLR_GPIO_HANDLER \ + _IO(OTX_IOC_MAGIC, 2) + +struct otx_gpio_usr_data { + uint64_t isr_base; + uint64_t sp; + uint64_t cpu; + uint64_t gpio_num; +}; + +struct cnxk_gpio_irq_stack { + LIST_ENTRY(cnxk_gpio_irq_stack) next; + void *sp_buffer; + int cpu; + int inuse; +}; + +struct cnxk_gpio_irqchip { + int fd; + /* serialize access to this struct */ + pthread_mutex_t lock; + LIST_HEAD(, cnxk_gpio_irq_stack) stacks; + + struct cnxk_gpiochip *gpiochip; +}; + +static struct cnxk_gpio_irqchip *irqchip; + +static void +cnxk_gpio_irq_stack_free(int cpu) +{ + struct cnxk_gpio_irq_stack *stack; + + LIST_FOREACH(stack, &irqchip->stacks, next) { + if (stack->cpu == cpu) + break; + } + + if (!stack) + return; + + if (stack->inuse) + stack->inuse--; + + if (stack->inuse == 0) { + LIST_REMOVE(stack, next); + rte_free(stack->sp_buffer); + rte_free(stack); + } +} + +static void * +cnxk_gpio_irq_stack_alloc(int cpu) +{ +#define ARM_STACK_ALIGNMENT (2 * sizeof(void *)) +#define IRQ_STACK_SIZE 0x200000 + + struct cnxk_gpio_irq_stack *stack; + + LIST_FOREACH(stack, &irqchip->stacks, next) { + if (stack->cpu == cpu) + break; + } + + if (stack) { + stack->inuse++; + return (char *)stack->sp_buffer + IRQ_STACK_SIZE; + } + + stack = rte_malloc(NULL, sizeof(*stack), 0); + if (!stack) + return NULL; + + stack->sp_buffer = + rte_zmalloc(NULL, IRQ_STACK_SIZE * 2, ARM_STACK_ALIGNMENT); + if (!stack->sp_buffer) { + rte_free(stack); + return NULL; + } + + stack->cpu = cpu; + stack->inuse = 1; + LIST_INSERT_HEAD(&irqchip->stacks, stack, next); + + return (char *)stack->sp_buffer + IRQ_STACK_SIZE; +} + +static void +cnxk_gpio_irq_handler(int gpio_num) +{ + struct cnxk_gpiochip *gpiochip = irqchip->gpiochip; + struct cnxk_gpio *gpio; + + if (gpio_num >= gpiochip->num_gpios) + goto out; + + gpio = gpiochip->gpios[gpio_num]; + if (likely(gpio->handler)) + gpio->handler(gpio_num, gpio->data); + +out: + roc_atf_ret(); +} + +int +cnxk_gpio_irq_init(struct cnxk_gpiochip *gpiochip) +{ + if (irqchip) + return 0; + + irqchip = rte_zmalloc(NULL, sizeof(*irqchip), 0); + if (!irqchip) + return -ENOMEM; + + irqchip->fd = open("/dev/otx-gpio-ctr", O_RDWR | O_SYNC); + if (irqchip->fd < 0) { + rte_free(irqchip); + return -errno; + } + + pthread_mutex_init(&irqchip->lock, NULL); + LIST_INIT(&irqchip->stacks); + irqchip->gpiochip = gpiochip; + + return 0; +} + +void +cnxk_gpio_irq_fini(void) +{ + if (!irqchip) + return; + + close(irqchip->fd); + rte_free(irqchip); + irqchip = NULL; +} + +int +cnxk_gpio_irq_request(int gpio, int cpu) +{ + struct otx_gpio_usr_data data; + void *sp; + int ret; + + pthread_mutex_lock(&irqchip->lock); + + sp = cnxk_gpio_irq_stack_alloc(cpu); + if (!sp) { + ret = -ENOMEM; + goto out_unlock; + } + + data.isr_base = (uint64_t)cnxk_gpio_irq_handler; + data.sp = (uint64_t)sp; + data.cpu = (uint64_t)cpu; + data.gpio_num = (uint64_t)gpio; + + mlockall(MCL_CURRENT | MCL_FUTURE); + ret = ioctl(irqchip->fd, OTX_IOC_SET_GPIO_HANDLER, &data); + if (ret) { + ret = -errno; + goto out_free_stack; + } + + pthread_mutex_unlock(&irqchip->lock); + + return 0; + +out_free_stack: + cnxk_gpio_irq_stack_free(cpu); +out_unlock: + pthread_mutex_unlock(&irqchip->lock); + + return ret; +} + +int +cnxk_gpio_irq_free(int gpio) +{ + int ret; + + pthread_mutex_lock(&irqchip->lock); + + ret = ioctl(irqchip->fd, OTX_IOC_CLR_GPIO_HANDLER, gpio); + if (ret) { + pthread_mutex_unlock(&irqchip->lock); + return -errno; + } + + cnxk_gpio_irq_stack_free(irqchip->gpiochip->gpios[gpio]->cpu); + + pthread_mutex_unlock(&irqchip->lock); + + return 0; +} diff --git a/drivers/raw/cnxk_gpio/meson.build b/drivers/raw/cnxk_gpio/meson.build index 3fbfdd838c..9b55f029c7 100644 --- a/drivers/raw/cnxk_gpio/meson.build +++ b/drivers/raw/cnxk_gpio/meson.build @@ -5,5 +5,6 @@ deps += ['bus_vdev', 'common_cnxk', 'rawdev', 'kvargs'] sources = files( 'cnxk_gpio.c', + 'cnxk_gpio_irq.c', ) headers = files('rte_pmd_cnxk_gpio.h') diff --git a/drivers/raw/cnxk_gpio/rte_pmd_cnxk_gpio.h b/drivers/raw/cnxk_gpio/rte_pmd_cnxk_gpio.h index 7c3dc225ca..e3096dc14f 100644 --- a/drivers/raw/cnxk_gpio/rte_pmd_cnxk_gpio.h +++ b/drivers/raw/cnxk_gpio/rte_pmd_cnxk_gpio.h @@ -40,6 +40,10 @@ enum cnxk_gpio_msg_type { CNXK_GPIO_MSG_TYPE_GET_PIN_DIR, /** Type used to read inverted logic state */ CNXK_GPIO_MSG_TYPE_GET_PIN_ACTIVE_LOW, + /** Type used to register interrupt handler */ + CNXK_GPIO_MSG_TYPE_REGISTER_IRQ, + /** Type used to remove interrupt handler */ + CNXK_GPIO_MSG_TYPE_UNREGISTER_IRQ, }; /** Available edges */ @@ -66,6 +70,25 @@ enum cnxk_gpio_pin_dir { CNXK_GPIO_PIN_DIR_LOW, }; +/** + * GPIO interrupt handler + * + * @param gpio + * Zero-based GPIO number + * @param data + * Cookie passed to interrupt handler + */ +typedef void (*cnxk_gpio_irq_handler_t)(int gpio, void *data); + +struct cnxk_gpio_irq { + /** Interrupt handler */ + cnxk_gpio_irq_handler_t handler; + /** User data passed to irq handler */ + void *data; + /** CPU which will run irq handler */ + int cpu; +}; + struct cnxk_gpio_msg { /** Message type */ enum cnxk_gpio_msg_type type; @@ -306,6 +329,99 @@ rte_pmd_gpio_get_pin_active_low(uint16_t dev_id, int gpio, int *val) return __rte_pmd_gpio_enq_deq(dev_id, gpio, &msg, val, sizeof(*val)); } +/** + * Attach interrupt handler to GPIO + * + * @param dev_id + * The identifier of the device + * @param gpio + * Zero-based GPIO number + * @param cpu + * CPU which will be handling interrupt + * @param handler + * Interrupt handler to be executed + * @param data + * Data to be passed to interrupt handler + * + * @return + * Returns 0 on success, negative error code otherwise + */ +static __rte_always_inline int +rte_pmd_gpio_register_irq(uint16_t dev_id, int gpio, int cpu, + cnxk_gpio_irq_handler_t handler, void *data) +{ + struct cnxk_gpio_irq irq = { + .handler = handler, + .data = data, + .cpu = cpu, + }; + struct cnxk_gpio_msg msg = { + .type = CNXK_GPIO_MSG_TYPE_REGISTER_IRQ, + .data = &irq, + }; + + return __rte_pmd_gpio_enq_deq(dev_id, gpio, &msg, NULL, 0); +} + +/** + * Detach interrupt handler from GPIO + * + * @param dev_id + * The identifier of the device + * @param gpio + * Zero-based GPIO number + * + * @return + * Returns 0 on success, negative error code otherwise + */ +static __rte_always_inline int +rte_pmd_gpio_unregister_irq(uint16_t dev_id, int gpio) +{ + struct cnxk_gpio_msg msg = { + .type = CNXK_GPIO_MSG_TYPE_UNREGISTER_IRQ, + .data = &gpio, + }; + + return __rte_pmd_gpio_enq_deq(dev_id, gpio, &msg, NULL, 0); +} + +/** + * Enable interrupt + * + * @param dev_id + * The identifier of the device + * @param gpio + * Zero-based GPIO number + * @param edge + * Edge that should trigger interrupt + * + * @return + * Returns 0 on success, negative error code otherwise + */ +static __rte_always_inline int +rte_pmd_gpio_enable_interrupt(uint16_t dev_id, int gpio, + enum cnxk_gpio_pin_edge edge) +{ + return rte_pmd_gpio_set_pin_edge(dev_id, gpio, edge); +} + +/** + * Disable interrupt + * + * @param dev_id + * The identifier of the device + * @param gpio + * Zero-based GPIO number + * + * @return + * Returns 0 on success, negative error code otherwise + */ +static __rte_always_inline int +rte_pmd_gpio_disable_interrupt(uint16_t dev_id, int gpio) +{ + return rte_pmd_gpio_set_pin_edge(dev_id, gpio, CNXK_GPIO_PIN_EDGE_NONE); +} + #ifdef __cplusplus } #endif