Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause 2 : : * Copyright(C) 2021 Marvell. 3 : : */ 4 : : 5 : : #include <fcntl.h> 6 : : #include <pthread.h> 7 : : #include <sys/ioctl.h> 8 : : #include <sys/mman.h> 9 : : #include <sys/queue.h> 10 : : #include <unistd.h> 11 : : 12 : : #include <rte_rawdev_pmd.h> 13 : : 14 : : #include <roc_api.h> 15 : : 16 : : #include "cnxk_gpio.h" 17 : : 18 : : #define OTX_IOC_MAGIC 0xF2 19 : : #define OTX_IOC_SET_GPIO_HANDLER \ 20 : : _IOW(OTX_IOC_MAGIC, 1, struct otx_gpio_usr_data) 21 : : #define OTX_IOC_CLR_GPIO_HANDLER \ 22 : : _IO(OTX_IOC_MAGIC, 2) 23 : : 24 : : struct otx_gpio_usr_data { 25 : : uint64_t isr_base; 26 : : uint64_t sp; 27 : : uint64_t cpu; 28 : : uint64_t gpio_num; 29 : : }; 30 : : 31 : : struct cnxk_gpio_irq_stack { 32 : : LIST_ENTRY(cnxk_gpio_irq_stack) next; 33 : : void *sp_buffer; 34 : : int cpu; 35 : : int inuse; 36 : : }; 37 : : 38 : : struct cnxk_gpio_irqchip { 39 : : int fd; 40 : : /* serialize access to this struct */ 41 : : pthread_mutex_t lock; 42 : : LIST_HEAD(, cnxk_gpio_irq_stack) stacks; 43 : : 44 : : struct cnxk_gpiochip *gpiochip; 45 : : }; 46 : : 47 : : static struct cnxk_gpio_irqchip *irqchip; 48 : : 49 : : static void 50 : 0 : cnxk_gpio_irq_stack_free(int cpu) 51 : : { 52 : : struct cnxk_gpio_irq_stack *stack; 53 : : 54 [ # # ]: 0 : LIST_FOREACH(stack, &irqchip->stacks, next) { 55 [ # # ]: 0 : if (stack->cpu == cpu) 56 : : break; 57 : : } 58 : : 59 [ # # ]: 0 : if (!stack) 60 : : return; 61 : : 62 [ # # ]: 0 : if (stack->inuse) 63 : 0 : stack->inuse--; 64 : : 65 [ # # ]: 0 : if (stack->inuse == 0) { 66 [ # # ]: 0 : LIST_REMOVE(stack, next); 67 : 0 : rte_free(stack->sp_buffer); 68 : 0 : rte_free(stack); 69 : : } 70 : : } 71 : : 72 : : static void * 73 : 0 : cnxk_gpio_irq_stack_alloc(int cpu) 74 : : { 75 : : #define ARM_STACK_ALIGNMENT (2 * sizeof(void *)) 76 : : #define IRQ_STACK_SIZE 0x200000 77 : : 78 : : struct cnxk_gpio_irq_stack *stack; 79 : : 80 [ # # ]: 0 : LIST_FOREACH(stack, &irqchip->stacks, next) { 81 [ # # ]: 0 : if (stack->cpu == cpu) 82 : : break; 83 : : } 84 : : 85 [ # # ]: 0 : if (stack) { 86 : 0 : stack->inuse++; 87 : 0 : return (char *)stack->sp_buffer + IRQ_STACK_SIZE; 88 : : } 89 : : 90 : 0 : stack = rte_malloc(NULL, sizeof(*stack), 0); 91 [ # # ]: 0 : if (!stack) 92 : : return NULL; 93 : : 94 : 0 : stack->sp_buffer = 95 : 0 : rte_zmalloc(NULL, IRQ_STACK_SIZE * 2, ARM_STACK_ALIGNMENT); 96 [ # # ]: 0 : if (!stack->sp_buffer) { 97 : 0 : rte_free(stack); 98 : 0 : return NULL; 99 : : } 100 : : 101 : 0 : stack->cpu = cpu; 102 : 0 : stack->inuse = 1; 103 [ # # ]: 0 : LIST_INSERT_HEAD(&irqchip->stacks, stack, next); 104 : : 105 : 0 : return (char *)stack->sp_buffer + IRQ_STACK_SIZE; 106 : : } 107 : : 108 : : static void 109 : 0 : cnxk_gpio_irq_handler(int gpio_num) 110 : : { 111 : 0 : struct cnxk_gpiochip *gpiochip = irqchip->gpiochip; 112 : : struct cnxk_gpio *gpio; 113 : : 114 [ # # ]: 0 : if (gpio_num >= gpiochip->num_gpios) 115 : 0 : goto out; 116 : : 117 : 0 : gpio = gpiochip->gpios[gpio_num]; 118 [ # # ]: 0 : if (likely(gpio->handler)) 119 : 0 : gpio->handler(gpio_num, gpio->data); 120 : : 121 : 0 : out: 122 : : roc_atf_ret(); 123 : 0 : } 124 : : 125 : : int 126 : 0 : cnxk_gpio_irq_init(struct cnxk_gpiochip *gpiochip) 127 : : { 128 [ # # ]: 0 : if (irqchip) 129 : : return 0; 130 : : 131 : 0 : irqchip = rte_zmalloc(NULL, sizeof(*irqchip), 0); 132 [ # # ]: 0 : if (!irqchip) 133 : : return -ENOMEM; 134 : : 135 : 0 : irqchip->fd = open("/dev/otx-gpio-ctr", O_RDWR | O_SYNC); 136 [ # # ]: 0 : if (irqchip->fd < 0) { 137 : 0 : rte_free(irqchip); 138 : 0 : return -errno; 139 : : } 140 : : 141 : 0 : pthread_mutex_init(&irqchip->lock, NULL); 142 : 0 : LIST_INIT(&irqchip->stacks); 143 : 0 : irqchip->gpiochip = gpiochip; 144 : : 145 : 0 : return 0; 146 : : } 147 : : 148 : : void 149 : 0 : cnxk_gpio_irq_fini(void) 150 : : { 151 [ # # ]: 0 : if (!irqchip) 152 : : return; 153 : : 154 : 0 : close(irqchip->fd); 155 : 0 : rte_free(irqchip); 156 : 0 : irqchip = NULL; 157 : : } 158 : : 159 : : int 160 : 0 : cnxk_gpio_irq_request(int gpio, int cpu) 161 : : { 162 : : struct otx_gpio_usr_data data; 163 : : void *sp; 164 : : int ret; 165 : : 166 : 0 : pthread_mutex_lock(&irqchip->lock); 167 : : 168 : 0 : sp = cnxk_gpio_irq_stack_alloc(cpu); 169 [ # # ]: 0 : if (!sp) { 170 : : ret = -ENOMEM; 171 : 0 : goto out_unlock; 172 : : } 173 : : 174 : 0 : data.isr_base = (uint64_t)cnxk_gpio_irq_handler; 175 : 0 : data.sp = (uint64_t)sp; 176 : 0 : data.cpu = (uint64_t)cpu; 177 : 0 : data.gpio_num = (uint64_t)gpio; 178 : : 179 : 0 : mlockall(MCL_CURRENT | MCL_FUTURE); 180 : 0 : ret = ioctl(irqchip->fd, OTX_IOC_SET_GPIO_HANDLER, &data); 181 [ # # ]: 0 : if (ret) { 182 : 0 : ret = -errno; 183 : 0 : goto out_free_stack; 184 : : } 185 : : 186 : 0 : pthread_mutex_unlock(&irqchip->lock); 187 : : 188 : 0 : return 0; 189 : : 190 : : out_free_stack: 191 : 0 : cnxk_gpio_irq_stack_free(cpu); 192 : 0 : out_unlock: 193 : 0 : pthread_mutex_unlock(&irqchip->lock); 194 : : 195 : 0 : return ret; 196 : : } 197 : : 198 : : int 199 : 0 : cnxk_gpio_irq_free(int gpio) 200 : : { 201 : : int ret; 202 : : 203 : 0 : pthread_mutex_lock(&irqchip->lock); 204 : : 205 : 0 : ret = ioctl(irqchip->fd, OTX_IOC_CLR_GPIO_HANDLER, gpio); 206 [ # # ]: 0 : if (ret) { 207 : 0 : pthread_mutex_unlock(&irqchip->lock); 208 : 0 : return -errno; 209 : : } 210 : : 211 : 0 : cnxk_gpio_irq_stack_free(irqchip->gpiochip->gpios[gpio]->cpu); 212 : : 213 : 0 : pthread_mutex_unlock(&irqchip->lock); 214 : : 215 : 0 : return 0; 216 : : }