Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

platform/surface: aggregator: Add event item allocation caching

Event items are used for completing Surface Aggregator EC events, i.e.
placing event command data and payload on a workqueue for later
processing to avoid doing said processing directly on the receiver
thread. This means that event items are allocated for each incoming
event, regardless of that event being transmitted via sequenced or
unsequenced packets.

On the Surface Book 3 and Surface Laptop 3, touchpad HID input events
(unsequenced), can constitute a larger amount of traffic, and therefore
allocation of event items. This warrants caching event items to reduce
memory fragmentation. The size of the cached objects is specifically
tuned to accommodate keyboard and touchpad input events and their
payloads on those devices. As a result, this effectively also covers
most other event types. In case of a larger event payload, event item
allocation will fall back to kzalloc().

Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
Link: https://lore.kernel.org/r/20201221183959.1186143-4-luzmaximilian@gmail.com
Signed-off-by: Hans de Goede <hdegoede@redhat.com>

authored by

Maximilian Luz and committed by
Hans de Goede
3a7081f6 44b84ee7

+101 -10
+78 -8
drivers/platform/surface/aggregator/controller.c
··· 513 513 */ 514 514 #define SSAM_CPLT_WQ_BATCH 10 515 515 516 + /* 517 + * SSAM_EVENT_ITEM_CACHE_PAYLOAD_LEN - Maximum payload length for a cached 518 + * &struct ssam_event_item. 519 + * 520 + * This length has been chosen to be accommodate standard touchpad and 521 + * keyboard input events. Events with larger payloads will be allocated 522 + * separately. 523 + */ 524 + #define SSAM_EVENT_ITEM_CACHE_PAYLOAD_LEN 32 525 + 526 + static struct kmem_cache *ssam_event_item_cache; 527 + 528 + /** 529 + * ssam_event_item_cache_init() - Initialize the event item cache. 530 + */ 531 + int ssam_event_item_cache_init(void) 532 + { 533 + const unsigned int size = sizeof(struct ssam_event_item) 534 + + SSAM_EVENT_ITEM_CACHE_PAYLOAD_LEN; 535 + const unsigned int align = __alignof__(struct ssam_event_item); 536 + struct kmem_cache *cache; 537 + 538 + cache = kmem_cache_create("ssam_event_item", size, align, 0, NULL); 539 + if (!cache) 540 + return -ENOMEM; 541 + 542 + ssam_event_item_cache = cache; 543 + return 0; 544 + } 545 + 546 + /** 547 + * ssam_event_item_cache_destroy() - Deinitialize the event item cache. 548 + */ 549 + void ssam_event_item_cache_destroy(void) 550 + { 551 + kmem_cache_destroy(ssam_event_item_cache); 552 + ssam_event_item_cache = NULL; 553 + } 554 + 555 + static void __ssam_event_item_free_cached(struct ssam_event_item *item) 556 + { 557 + kmem_cache_free(ssam_event_item_cache, item); 558 + } 559 + 560 + static void __ssam_event_item_free_generic(struct ssam_event_item *item) 561 + { 562 + kfree(item); 563 + } 564 + 565 + /** 566 + * ssam_event_item_free() - Free the provided event item. 567 + * @item: The event item to free. 568 + */ 569 + static void ssam_event_item_free(struct ssam_event_item *item) 570 + { 571 + item->ops.free(item); 572 + } 573 + 516 574 /** 517 575 * ssam_event_item_alloc() - Allocate an event item with the given payload size. 518 576 * @len: The event payload length. 519 577 * @flags: The flags used for allocation. 520 578 * 521 - * Allocate an event item with the given payload size. Sets the item 522 - * operations and payload length values. The item free callback (``ops.free``) 523 - * should not be overwritten after this call. 579 + * Allocate an event item with the given payload size, preferring allocation 580 + * from the event item cache if the payload is small enough (i.e. smaller than 581 + * %SSAM_EVENT_ITEM_CACHE_PAYLOAD_LEN). Sets the item operations and payload 582 + * length values. The item free callback (``ops.free``) should not be 583 + * overwritten after this call. 524 584 * 525 585 * Return: Returns the newly allocated event item. 526 586 */ ··· 588 528 { 589 529 struct ssam_event_item *item; 590 530 591 - item = kzalloc(struct_size(item, event.data, len), flags); 592 - if (!item) 593 - return NULL; 531 + if (len <= SSAM_EVENT_ITEM_CACHE_PAYLOAD_LEN) { 532 + item = kmem_cache_alloc(ssam_event_item_cache, flags); 533 + if (!item) 534 + return NULL; 535 + 536 + item->ops.free = __ssam_event_item_free_cached; 537 + } else { 538 + item = kzalloc(struct_size(item, event.data, len), flags); 539 + if (!item) 540 + return NULL; 541 + 542 + item->ops.free = __ssam_event_item_free_generic; 543 + } 594 544 595 545 item->event.length = len; 596 546 return item; ··· 762 692 return; 763 693 764 694 ssam_nf_call(nf, dev, item->rqid, &item->event); 765 - kfree(item); 695 + ssam_event_item_free(item); 766 696 } while (--iterations); 767 697 768 698 if (!ssam_event_queue_is_empty(queue)) ··· 970 900 memcpy(&item->event.data[0], data->ptr, data->len); 971 901 972 902 if (WARN_ON(ssam_cplt_submit_event(&ctrl->cplt, item))) 973 - kfree(item); 903 + ssam_event_item_free(item); 974 904 } 975 905 976 906 static const struct ssh_rtl_ops ssam_rtl_ops = {
+9
drivers/platform/surface/aggregator/controller.h
··· 80 80 * struct ssam_event_item - Struct for event queuing and completion. 81 81 * @node: The node in the queue. 82 82 * @rqid: The request ID of the event. 83 + * @ops: Instance specific functions. 84 + * @ops.free: Callback for freeing this event item. 83 85 * @event: Actual event data. 84 86 */ 85 87 struct ssam_event_item { 86 88 struct list_head node; 87 89 u16 rqid; 90 + 91 + struct { 92 + void (*free)(struct ssam_event_item *event); 93 + } ops; 88 94 89 95 struct ssam_event event; /* must be last */ 90 96 }; ··· 278 272 279 273 int ssam_controller_suspend(struct ssam_controller *ctrl); 280 274 int ssam_controller_resume(struct ssam_controller *ctrl); 275 + 276 + int ssam_event_item_cache_init(void); 277 + void ssam_event_item_cache_destroy(void); 281 278 282 279 #endif /* _SURFACE_AGGREGATOR_CONTROLLER_H */
+14 -2
drivers/platform/surface/aggregator/core.c
··· 790 790 791 791 status = ssh_ctrl_packet_cache_init(); 792 792 if (status) 793 - return status; 793 + goto err_cpkg; 794 + 795 + status = ssam_event_item_cache_init(); 796 + if (status) 797 + goto err_evitem; 794 798 795 799 status = serdev_device_driver_register(&ssam_serial_hub); 796 800 if (status) 797 - ssh_ctrl_packet_cache_destroy(); 801 + goto err_register; 798 802 803 + return 0; 804 + 805 + err_register: 806 + ssam_event_item_cache_destroy(); 807 + err_evitem: 808 + ssh_ctrl_packet_cache_destroy(); 809 + err_cpkg: 799 810 return status; 800 811 } 801 812 module_init(ssam_core_init); ··· 814 803 static void __exit ssam_core_exit(void) 815 804 { 816 805 serdev_device_driver_unregister(&ssam_serial_hub); 806 + ssam_event_item_cache_destroy(); 817 807 ssh_ctrl_packet_cache_destroy(); 818 808 } 819 809 module_exit(ssam_core_exit);