1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Generic Counter character device interface 4 * Copyright (C) 2020 William Breathitt Gray 5 */ 6 #include <linux/cdev.h> 7 #include <linux/counter.h> 8 #include <linux/err.h> 9 #include <linux/errno.h> 10 #include <linux/export.h> 11 #include <linux/fs.h> 12 #include <linux/kfifo.h> 13 #include <linux/list.h> 14 #include <linux/mutex.h> 15 #include <linux/nospec.h> 16 #include <linux/poll.h> 17 #include <linux/slab.h> 18 #include <linux/spinlock.h> 19 #include <linux/timekeeping.h> 20 #include <linux/types.h> 21 #include <linux/uaccess.h> 22 #include <linux/wait.h> 23 24 #include "counter-chrdev.h" 25 26 struct counter_comp_node { 27 struct list_head l; 28 struct counter_component component; 29 struct counter_comp comp; 30 void *parent; 31 }; 32 33 #define counter_comp_read_is_equal(a, b) \ 34 (a.action_read == b.action_read || \ 35 a.device_u8_read == b.device_u8_read || \ 36 a.count_u8_read == b.count_u8_read || \ 37 a.signal_u8_read == b.signal_u8_read || \ 38 a.device_u32_read == b.device_u32_read || \ 39 a.count_u32_read == b.count_u32_read || \ 40 a.signal_u32_read == b.signal_u32_read || \ 41 a.device_u64_read == b.device_u64_read || \ 42 a.count_u64_read == b.count_u64_read || \ 43 a.signal_u64_read == b.signal_u64_read || \ 44 a.signal_array_u32_read == b.signal_array_u32_read || \ 45 a.device_array_u64_read == b.device_array_u64_read || \ 46 a.count_array_u64_read == b.count_array_u64_read || \ 47 a.signal_array_u64_read == b.signal_array_u64_read) 48 49 #define counter_comp_read_is_set(comp) \ 50 (comp.action_read || \ 51 comp.device_u8_read || \ 52 comp.count_u8_read || \ 53 comp.signal_u8_read || \ 54 comp.device_u32_read || \ 55 comp.count_u32_read || \ 56 comp.signal_u32_read || \ 57 comp.device_u64_read || \ 58 comp.count_u64_read || \ 59 comp.signal_u64_read || \ 60 comp.signal_array_u32_read || \ 61 comp.device_array_u64_read || \ 62 comp.count_array_u64_read || \ 63 comp.signal_array_u64_read) 64 65 static ssize_t counter_chrdev_read(struct file *filp, char __user *buf, 66 size_t len, loff_t *f_ps) 67 { 68 struct counter_device *const counter = filp->private_data; 69 int err; 70 unsigned int copied; 71 72 if (!counter->ops) 73 return -ENODEV; 74 75 if (len < sizeof(struct counter_event)) 76 return -EINVAL; 77 78 do { 79 if (kfifo_is_empty(&counter->events)) { 80 if (filp->f_flags & O_NONBLOCK) 81 return -EAGAIN; 82 83 err = wait_event_interruptible(counter->events_wait, 84 !kfifo_is_empty(&counter->events) || 85 !counter->ops); 86 if (err < 0) 87 return err; 88 if (!counter->ops) 89 return -ENODEV; 90 } 91 92 if (mutex_lock_interruptible(&counter->events_out_lock)) 93 return -ERESTARTSYS; 94 err = kfifo_to_user(&counter->events, buf, len, &copied); 95 mutex_unlock(&counter->events_out_lock); 96 if (err < 0) 97 return err; 98 } while (!copied); 99 100 return copied; 101 } 102 103 static __poll_t counter_chrdev_poll(struct file *filp, 104 struct poll_table_struct *pollt) 105 { 106 struct counter_device *const counter = filp->private_data; 107 __poll_t events = 0; 108 109 if (!counter->ops) 110 return events; 111 112 poll_wait(filp, &counter->events_wait, pollt); 113 114 if (!kfifo_is_empty(&counter->events)) 115 events = EPOLLIN | EPOLLRDNORM; 116 117 return events; 118 } 119 120 static void counter_events_list_free(struct list_head *const events_list) 121 { 122 struct counter_event_node *p, *n; 123 struct counter_comp_node *q, *o; 124 125 list_for_each_entry_safe(p, n, events_list, l) { 126 /* Free associated component nodes */ 127 list_for_each_entry_safe(q, o, &p->comp_list, l) { 128 list_del(&q->l); 129 kfree(q); 130 } 131 132 /* Free event node */ 133 list_del(&p->l); 134 kfree(p); 135 } 136 } 137 138 static int counter_set_event_node(struct counter_device *const counter, 139 struct counter_watch *const watch, 140 const struct counter_comp_node *const cfg) 141 { 142 struct counter_event_node *event_node; 143 int err = 0; 144 struct counter_comp_node *comp_node; 145 146 /* Search for event in the list */ 147 list_for_each_entry(event_node, &counter->next_events_list, l) 148 if (event_node->event == watch->event && 149 event_node->channel == watch->channel) 150 break; 151 152 /* If event is not already in the list */ 153 if (&event_node->l == &counter->next_events_list) { 154 /* Allocate new event node */ 155 event_node = kmalloc(sizeof(*event_node), GFP_KERNEL); 156 if (!event_node) 157 return -ENOMEM; 158 159 /* Configure event node and add to the list */ 160 event_node->event = watch->event; 161 event_node->channel = watch->channel; 162 INIT_LIST_HEAD(&event_node->comp_list); 163 list_add(&event_node->l, &counter->next_events_list); 164 } 165 166 /* Check if component watch has already been set before */ 167 list_for_each_entry(comp_node, &event_node->comp_list, l) 168 if (comp_node->parent == cfg->parent && 169 counter_comp_read_is_equal(comp_node->comp, cfg->comp)) { 170 err = -EINVAL; 171 goto exit_free_event_node; 172 } 173 174 /* Allocate component node */ 175 comp_node = kmalloc(sizeof(*comp_node), GFP_KERNEL); 176 if (!comp_node) { 177 err = -ENOMEM; 178 goto exit_free_event_node; 179 } 180 *comp_node = *cfg; 181 182 /* Add component node to event node */ 183 list_add_tail(&comp_node->l, &event_node->comp_list); 184 185 exit_free_event_node: 186 /* Free event node if no one else is watching */ 187 if (list_empty(&event_node->comp_list)) { 188 list_del(&event_node->l); 189 kfree(event_node); 190 } 191 192 return err; 193 } 194 195 static int counter_enable_events(struct counter_device *const counter) 196 { 197 unsigned long flags; 198 int err = 0; 199 200 mutex_lock(&counter->n_events_list_lock); 201 spin_lock_irqsave(&counter->events_list_lock, flags); 202 203 counter_events_list_free(&counter->events_list); 204 list_replace_init(&counter->next_events_list, 205 &counter->events_list); 206 207 if (counter->ops->events_configure) 208 err = counter->ops->events_configure(counter); 209 210 spin_unlock_irqrestore(&counter->events_list_lock, flags); 211 mutex_unlock(&counter->n_events_list_lock); 212 213 return err; 214 } 215 216 static int counter_disable_events(struct counter_device *const counter) 217 { 218 unsigned long flags; 219 int err = 0; 220 221 spin_lock_irqsave(&counter->events_list_lock, flags); 222 223 counter_events_list_free(&counter->events_list); 224 225 if (counter->ops->events_configure) 226 err = counter->ops->events_configure(counter); 227 228 spin_unlock_irqrestore(&counter->events_list_lock, flags); 229 230 mutex_lock(&counter->n_events_list_lock); 231 232 counter_events_list_free(&counter->next_events_list); 233 234 mutex_unlock(&counter->n_events_list_lock); 235 236 return err; 237 } 238 239 static int counter_get_ext(const struct counter_comp *const ext, 240 const size_t num_ext, const size_t component_id, 241 size_t *const ext_idx, size_t *const id) 242 { 243 struct counter_array *element; 244 245 *id = 0; 246 for (*ext_idx = 0; *ext_idx < num_ext; (*ext_idx)++) { 247 if (*id == component_id) 248 return 0; 249 250 if (ext[*ext_idx].type == COUNTER_COMP_ARRAY) { 251 element = ext[*ext_idx].priv; 252 253 if (component_id - *id < element->length) 254 return 0; 255 256 *id += element->length; 257 } else 258 (*id)++; 259 } 260 261 return -EINVAL; 262 } 263 264 static int counter_add_watch(struct counter_device *const counter, 265 const unsigned long arg) 266 { 267 void __user *const uwatch = (void __user *)arg; 268 struct counter_watch watch; 269 struct counter_comp_node comp_node = {}; 270 size_t parent, id; 271 struct counter_comp *ext; 272 size_t num_ext; 273 size_t ext_idx, ext_id; 274 int err = 0; 275 276 if (copy_from_user(&watch, uwatch, sizeof(watch))) 277 return -EFAULT; 278 279 if (watch.component.type == COUNTER_COMPONENT_NONE) 280 goto no_component; 281 282 parent = watch.component.parent; 283 284 /* Configure parent component info for comp node */ 285 switch (watch.component.scope) { 286 case COUNTER_SCOPE_DEVICE: 287 ext = counter->ext; 288 num_ext = counter->num_ext; 289 break; 290 case COUNTER_SCOPE_SIGNAL: 291 if (parent >= counter->num_signals) 292 return -EINVAL; 293 parent = array_index_nospec(parent, counter->num_signals); 294 295 comp_node.parent = counter->signals + parent; 296 297 ext = counter->signals[parent].ext; 298 num_ext = counter->signals[parent].num_ext; 299 break; 300 case COUNTER_SCOPE_COUNT: 301 if (parent >= counter->num_counts) 302 return -EINVAL; 303 parent = array_index_nospec(parent, counter->num_counts); 304 305 comp_node.parent = counter->counts + parent; 306 307 ext = counter->counts[parent].ext; 308 num_ext = counter->counts[parent].num_ext; 309 break; 310 default: 311 return -EINVAL; 312 } 313 314 id = watch.component.id; 315 316 /* Configure component info for comp node */ 317 switch (watch.component.type) { 318 case COUNTER_COMPONENT_SIGNAL: 319 if (watch.component.scope != COUNTER_SCOPE_SIGNAL) 320 return -EINVAL; 321 322 comp_node.comp.type = COUNTER_COMP_SIGNAL_LEVEL; 323 comp_node.comp.signal_u32_read = counter->ops->signal_read; 324 break; 325 case COUNTER_COMPONENT_COUNT: 326 if (watch.component.scope != COUNTER_SCOPE_COUNT) 327 return -EINVAL; 328 329 comp_node.comp.type = COUNTER_COMP_U64; 330 comp_node.comp.count_u64_read = counter->ops->count_read; 331 break; 332 case COUNTER_COMPONENT_FUNCTION: 333 if (watch.component.scope != COUNTER_SCOPE_COUNT) 334 return -EINVAL; 335 336 comp_node.comp.type = COUNTER_COMP_FUNCTION; 337 comp_node.comp.count_u32_read = counter->ops->function_read; 338 break; 339 case COUNTER_COMPONENT_SYNAPSE_ACTION: 340 if (watch.component.scope != COUNTER_SCOPE_COUNT) 341 return -EINVAL; 342 if (id >= counter->counts[parent].num_synapses) 343 return -EINVAL; 344 id = array_index_nospec(id, counter->counts[parent].num_synapses); 345 346 comp_node.comp.type = COUNTER_COMP_SYNAPSE_ACTION; 347 comp_node.comp.action_read = counter->ops->action_read; 348 comp_node.comp.priv = counter->counts[parent].synapses + id; 349 break; 350 case COUNTER_COMPONENT_EXTENSION: 351 err = counter_get_ext(ext, num_ext, id, &ext_idx, &ext_id); 352 if (err < 0) 353 return err; 354 355 comp_node.comp = ext[ext_idx]; 356 break; 357 default: 358 return -EINVAL; 359 } 360 if (!counter_comp_read_is_set(comp_node.comp)) 361 return -EOPNOTSUPP; 362 363 no_component: 364 mutex_lock(&counter->n_events_list_lock); 365 366 if (counter->ops->watch_validate) { 367 err = counter->ops->watch_validate(counter, &watch); 368 if (err < 0) 369 goto err_exit; 370 } 371 372 comp_node.component = watch.component; 373 374 err = counter_set_event_node(counter, &watch, &comp_node); 375 376 err_exit: 377 mutex_unlock(&counter->n_events_list_lock); 378 379 return err; 380 } 381 382 static long counter_chrdev_ioctl(struct file *filp, unsigned int cmd, 383 unsigned long arg) 384 { 385 struct counter_device *const counter = filp->private_data; 386 int ret = -ENODEV; 387 388 mutex_lock(&counter->ops_exist_lock); 389 390 if (!counter->ops) 391 goto out_unlock; 392 393 switch (cmd) { 394 case COUNTER_ADD_WATCH_IOCTL: 395 ret = counter_add_watch(counter, arg); 396 break; 397 case COUNTER_ENABLE_EVENTS_IOCTL: 398 ret = counter_enable_events(counter); 399 break; 400 case COUNTER_DISABLE_EVENTS_IOCTL: 401 ret = counter_disable_events(counter); 402 break; 403 default: 404 ret = -ENOIOCTLCMD; 405 break; 406 } 407 408 out_unlock: 409 mutex_unlock(&counter->ops_exist_lock); 410 411 return ret; 412 } 413 414 static int counter_chrdev_open(struct inode *inode, struct file *filp) 415 { 416 struct counter_device *const counter = container_of(inode->i_cdev, 417 typeof(*counter), 418 chrdev); 419 420 get_device(&counter->dev); 421 filp->private_data = counter; 422 423 return nonseekable_open(inode, filp); 424 } 425 426 static int counter_chrdev_release(struct inode *inode, struct file *filp) 427 { 428 struct counter_device *const counter = filp->private_data; 429 int ret = 0; 430 431 mutex_lock(&counter->ops_exist_lock); 432 433 if (!counter->ops) { 434 /* Free any lingering held memory */ 435 counter_events_list_free(&counter->events_list); 436 counter_events_list_free(&counter->next_events_list); 437 ret = -ENODEV; 438 goto out_unlock; 439 } 440 441 ret = counter_disable_events(counter); 442 if (ret < 0) { 443 mutex_unlock(&counter->ops_exist_lock); 444 return ret; 445 } 446 447 out_unlock: 448 mutex_unlock(&counter->ops_exist_lock); 449 450 put_device(&counter->dev); 451 452 return ret; 453 } 454 455 static const struct file_operations counter_fops = { 456 .owner = THIS_MODULE, 457 .read = counter_chrdev_read, 458 .poll = counter_chrdev_poll, 459 .unlocked_ioctl = counter_chrdev_ioctl, 460 .open = counter_chrdev_open, 461 .release = counter_chrdev_release, 462 }; 463 464 int counter_chrdev_add(struct counter_device *const counter) 465 { 466 /* Initialize Counter events lists */ 467 INIT_LIST_HEAD(&counter->events_list); 468 INIT_LIST_HEAD(&counter->next_events_list); 469 spin_lock_init(&counter->events_list_lock); 470 mutex_init(&counter->n_events_list_lock); 471 init_waitqueue_head(&counter->events_wait); 472 spin_lock_init(&counter->events_in_lock); 473 mutex_init(&counter->events_out_lock); 474 475 /* Initialize character device */ 476 cdev_init(&counter->chrdev, &counter_fops); 477 478 /* Allocate Counter events queue */ 479 return kfifo_alloc(&counter->events, 64, GFP_KERNEL); 480 } 481 482 void counter_chrdev_remove(struct counter_device *const counter) 483 { 484 kfifo_free(&counter->events); 485 } 486 487 static int counter_get_array_data(struct counter_device *const counter, 488 const enum counter_scope scope, 489 void *const parent, 490 const struct counter_comp *const comp, 491 const size_t idx, u64 *const value) 492 { 493 const struct counter_array *const element = comp->priv; 494 u32 value_u32 = 0; 495 int ret; 496 497 switch (element->type) { 498 case COUNTER_COMP_SIGNAL_POLARITY: 499 if (scope != COUNTER_SCOPE_SIGNAL) 500 return -EINVAL; 501 ret = comp->signal_array_u32_read(counter, parent, idx, 502 &value_u32); 503 *value = value_u32; 504 return ret; 505 case COUNTER_COMP_U64: 506 switch (scope) { 507 case COUNTER_SCOPE_DEVICE: 508 return comp->device_array_u64_read(counter, idx, value); 509 case COUNTER_SCOPE_SIGNAL: 510 return comp->signal_array_u64_read(counter, parent, idx, 511 value); 512 case COUNTER_SCOPE_COUNT: 513 return comp->count_array_u64_read(counter, parent, idx, 514 value); 515 default: 516 return -EINVAL; 517 } 518 default: 519 return -EINVAL; 520 } 521 } 522 523 static int counter_get_data(struct counter_device *const counter, 524 const struct counter_comp_node *const comp_node, 525 u64 *const value) 526 { 527 const struct counter_comp *const comp = &comp_node->comp; 528 const enum counter_scope scope = comp_node->component.scope; 529 const size_t id = comp_node->component.id; 530 struct counter_signal *const signal = comp_node->parent; 531 struct counter_count *const count = comp_node->parent; 532 u8 value_u8 = 0; 533 u32 value_u32 = 0; 534 const struct counter_comp *ext; 535 size_t num_ext; 536 size_t ext_idx, ext_id; 537 int ret; 538 539 if (comp_node->component.type == COUNTER_COMPONENT_NONE) 540 return 0; 541 542 switch (comp->type) { 543 case COUNTER_COMP_U8: 544 case COUNTER_COMP_BOOL: 545 switch (scope) { 546 case COUNTER_SCOPE_DEVICE: 547 ret = comp->device_u8_read(counter, &value_u8); 548 break; 549 case COUNTER_SCOPE_SIGNAL: 550 ret = comp->signal_u8_read(counter, signal, &value_u8); 551 break; 552 case COUNTER_SCOPE_COUNT: 553 ret = comp->count_u8_read(counter, count, &value_u8); 554 break; 555 default: 556 return -EINVAL; 557 } 558 *value = value_u8; 559 return ret; 560 case COUNTER_COMP_SIGNAL_LEVEL: 561 case COUNTER_COMP_FUNCTION: 562 case COUNTER_COMP_ENUM: 563 case COUNTER_COMP_COUNT_DIRECTION: 564 case COUNTER_COMP_COUNT_MODE: 565 case COUNTER_COMP_SIGNAL_POLARITY: 566 switch (scope) { 567 case COUNTER_SCOPE_DEVICE: 568 ret = comp->device_u32_read(counter, &value_u32); 569 break; 570 case COUNTER_SCOPE_SIGNAL: 571 ret = comp->signal_u32_read(counter, signal, 572 &value_u32); 573 break; 574 case COUNTER_SCOPE_COUNT: 575 ret = comp->count_u32_read(counter, count, &value_u32); 576 break; 577 default: 578 return -EINVAL; 579 } 580 *value = value_u32; 581 return ret; 582 case COUNTER_COMP_U64: 583 switch (scope) { 584 case COUNTER_SCOPE_DEVICE: 585 return comp->device_u64_read(counter, value); 586 case COUNTER_SCOPE_SIGNAL: 587 return comp->signal_u64_read(counter, signal, value); 588 case COUNTER_SCOPE_COUNT: 589 return comp->count_u64_read(counter, count, value); 590 default: 591 return -EINVAL; 592 } 593 case COUNTER_COMP_SYNAPSE_ACTION: 594 ret = comp->action_read(counter, count, comp->priv, &value_u32); 595 *value = value_u32; 596 return ret; 597 case COUNTER_COMP_ARRAY: 598 switch (scope) { 599 case COUNTER_SCOPE_DEVICE: 600 ext = counter->ext; 601 num_ext = counter->num_ext; 602 break; 603 case COUNTER_SCOPE_SIGNAL: 604 ext = signal->ext; 605 num_ext = signal->num_ext; 606 break; 607 case COUNTER_SCOPE_COUNT: 608 ext = count->ext; 609 num_ext = count->num_ext; 610 break; 611 default: 612 return -EINVAL; 613 } 614 ret = counter_get_ext(ext, num_ext, id, &ext_idx, &ext_id); 615 if (ret < 0) 616 return ret; 617 618 return counter_get_array_data(counter, scope, comp_node->parent, 619 comp, id - ext_id, value); 620 default: 621 return -EINVAL; 622 } 623 } 624 625 /** 626 * counter_push_event - queue event for userspace reading 627 * @counter: pointer to Counter structure 628 * @event: triggered event 629 * @channel: event channel 630 * 631 * Note: If no one is watching for the respective event, it is silently 632 * discarded. 633 */ 634 void counter_push_event(struct counter_device *const counter, const u8 event, 635 const u8 channel) 636 { 637 struct counter_event ev; 638 unsigned int copied = 0; 639 unsigned long flags; 640 struct counter_event_node *event_node; 641 struct counter_comp_node *comp_node; 642 643 ev.timestamp = ktime_get_ns(); 644 ev.watch.event = event; 645 ev.watch.channel = channel; 646 647 /* Could be in an interrupt context, so use a spin lock */ 648 spin_lock_irqsave(&counter->events_list_lock, flags); 649 650 /* Search for event in the list */ 651 list_for_each_entry(event_node, &counter->events_list, l) 652 if (event_node->event == event && 653 event_node->channel == channel) 654 break; 655 656 /* If event is not in the list */ 657 if (&event_node->l == &counter->events_list) 658 goto exit_early; 659 660 /* Read and queue relevant comp for userspace */ 661 list_for_each_entry(comp_node, &event_node->comp_list, l) { 662 ev.watch.component = comp_node->component; 663 ev.status = -counter_get_data(counter, comp_node, &ev.value); 664 665 copied += kfifo_in_spinlocked_noirqsave(&counter->events, &ev, 666 1, &counter->events_in_lock); 667 } 668 669 exit_early: 670 spin_unlock_irqrestore(&counter->events_list_lock, flags); 671 672 if (copied) 673 wake_up_poll(&counter->events_wait, EPOLLIN); 674 } 675 EXPORT_SYMBOL_NS_GPL(counter_push_event, COUNTER); 676