diff options
author | Ge Bian <bian@google.com> | 2022-11-14 21:05:12 -0800 |
---|---|---|
committer | Holmes Chou <holmeschou@google.com> | 2023-02-12 23:46:58 +0000 |
commit | c4ad1d45477ee6fa957fc973eff6a0d88e0e44e5 (patch) | |
tree | 48a09d9ec06c31f865bd0e68a7595772836abbf2 | |
parent | 5e94527f78cc1163db07b06e65ca7f318c346f77 (diff) | |
download | lwis-c4ad1d45477ee6fa957fc973eff6a0d88e0e44e5.tar.gz |
LWIS: Reorganize the code to parse interrupts.
Bug: 246887680
Test: manually check with preview.
Change-Id: I7c98b0c16789f4889e2bc6ae424e80c23e91dc6e
Signed-off-by: Ge Bian <bian@google.com>
-rw-r--r-- | lwis_dt.c | 171 | ||||
-rw-r--r-- | lwis_interrupt.c | 67 | ||||
-rw-r--r-- | lwis_interrupt.h | 25 |
3 files changed, 143 insertions, 120 deletions
@@ -412,6 +412,77 @@ static int parse_critical_irq_events(struct device_node *event_info, u64** irq_e return critical_irq_events_num; } +static int parse_interrupts_event_info(struct lwis_interrupt_list *list, int index, + struct device_node *event_info) +{ + int irq_events_num; + int int_reg_bits_num; + int critical_events_num = 0; + u64 *irq_events; + u32 *int_reg_bits; + u64 *critical_events = NULL; + int ret = 0; + + irq_events_num = of_property_count_elems_of_size(event_info, "irq-events", 8); + if (irq_events_num <= 0) { + pr_err("Error getting irq-events: %d\n", irq_events_num); + ret = -EINVAL; + return ret; + } + + int_reg_bits_num = of_property_count_elems_of_size(event_info, "int-reg-bits", 4); + if (irq_events_num != int_reg_bits_num || int_reg_bits_num <= 0) { + pr_err("Error getting int-reg-bits: %d\n", int_reg_bits_num); + ret = -EINVAL; + return ret; + } + + irq_events = kmalloc(sizeof(u64) * irq_events_num, GFP_KERNEL); + if (IS_ERR_OR_NULL(irq_events)) { + ret = -ENOMEM; + return ret; + } + + int_reg_bits = kmalloc(sizeof(u32) * int_reg_bits_num, GFP_KERNEL); + if (IS_ERR_OR_NULL(int_reg_bits)) { + ret = -ENOMEM; + kfree(irq_events); + return ret; + } + + irq_events_num = of_property_read_variable_u64_array(event_info, "irq-events", irq_events, + irq_events_num, irq_events_num); + if (irq_events_num != int_reg_bits_num) { + pr_err("Error getting irq-events: %d\n", irq_events_num); + ret = irq_events_num; + goto event_info_exit; + } + + int_reg_bits_num = of_property_read_variable_u32_array( + event_info, "int-reg-bits", int_reg_bits, int_reg_bits_num, int_reg_bits_num); + if (irq_events_num != int_reg_bits_num) { + pr_err("Error getting int-reg-bits: %d\n", int_reg_bits_num); + ret = int_reg_bits_num; + goto event_info_exit; + } + + critical_events_num = parse_critical_irq_events(event_info, &critical_events); + + ret = lwis_interrupt_set_event_info(list, index, (int64_t *)irq_events, irq_events_num, + int_reg_bits, int_reg_bits_num, + (int64_t *)critical_events, critical_events_num); + if (ret) { + pr_err("Error setting event info for interrupt %d %d\n", index, ret); + goto event_info_exit; + } + +event_info_exit: + kfree(critical_events); + kfree(irq_events); + kfree(int_reg_bits); + return ret; +} + static int parse_interrupts(struct lwis_device *lwis_dev) { int i; @@ -441,9 +512,9 @@ static int parse_interrupts(struct lwis_device *lwis_dev) for (i = 0; i < count; ++i) { of_property_read_string_index(dev_node, "interrupt-names", i, &name); - ret = lwis_interrupt_get(lwis_dev->irqs, i, (char *)name, plat_dev); + ret = lwis_interrupt_init(lwis_dev->irqs, i, (char *)name); if (ret) { - pr_err("Cannot set irq %s\n", name); + pr_err("Cannot initialize irq %s\n", name); goto error_get_irq; } } @@ -464,12 +535,6 @@ static int parse_interrupts(struct lwis_device *lwis_dev) u64 irq_reset_reg; u64 irq_mask_reg; u64 irq_overflow_reg = 0; - int irq_events_num; - int int_reg_bits_num; - int critical_events_num = 0; - u64 *irq_events; - u32 *int_reg_bits; - u64 *critical_events = NULL; int irq_reg_bid = -1; int irq_reg_bid_count; /* To match default value of reg-addr/value-bitwidth. */ @@ -477,60 +542,9 @@ static int parse_interrupts(struct lwis_device *lwis_dev) int j; struct device_node *event_info = of_node_get(it.node); - irq_events_num = of_property_count_elems_of_size(event_info, "irq-events", 8); - if (irq_events_num <= 0) { - pr_err("Error getting irq-events: %d\n", irq_events_num); - ret = -EINVAL; - goto error_event_infos; - } - - int_reg_bits_num = of_property_count_elems_of_size(event_info, "int-reg-bits", 4); - if (irq_events_num != int_reg_bits_num || int_reg_bits_num <= 0) { - pr_err("Error getting int-reg-bits: %d\n", int_reg_bits_num); - ret = -EINVAL; - goto error_event_infos; - } - - irq_events = kmalloc(sizeof(u64) * irq_events_num, GFP_KERNEL); - if (IS_ERR_OR_NULL(irq_events)) { - ret = -ENOMEM; - goto error_event_infos; - } - - int_reg_bits = kmalloc(sizeof(u32) * int_reg_bits_num, GFP_KERNEL); - if (IS_ERR_OR_NULL(int_reg_bits)) { - ret = -ENOMEM; - kfree(irq_events); - goto error_event_infos; - } - - irq_events_num = of_property_read_variable_u64_array( - event_info, "irq-events", irq_events, irq_events_num, irq_events_num); - if (irq_events_num != int_reg_bits_num) { - pr_err("Error getting irq-events: %d\n", irq_events_num); - ret = irq_events_num; - kfree(irq_events); - kfree(int_reg_bits); - goto error_event_infos; - } - - int_reg_bits_num = - of_property_read_variable_u32_array(event_info, "int-reg-bits", - int_reg_bits, int_reg_bits_num, - int_reg_bits_num); - if (irq_events_num != int_reg_bits_num) { - pr_err("Error getting int-reg-bits: %d\n", int_reg_bits_num); - ret = int_reg_bits_num; - kfree(irq_events); - kfree(int_reg_bits); - goto error_event_infos; - } - ret = of_property_read_string(event_info, "irq-reg-space", &irq_reg_space); if (ret) { pr_err("Error getting irq-reg-space from dt: %d\n", ret); - kfree(irq_events); - kfree(int_reg_bits); goto error_event_infos; } @@ -538,8 +552,6 @@ static int parse_interrupts(struct lwis_device *lwis_dev) if (irq_reg_bid_count <= 0) { pr_err("Error getting reg-names from dt: %d\n", irq_reg_bid_count); - kfree(irq_events); - kfree(int_reg_bits); goto error_event_infos; } for (j = 0; j < irq_reg_bid_count; j++) { @@ -556,32 +568,24 @@ static int parse_interrupts(struct lwis_device *lwis_dev) } if (irq_reg_bid < 0) { pr_err("Could not find a reg bid for %s\n", irq_reg_space); - kfree(irq_events); - kfree(int_reg_bits); goto error_event_infos; } ret = of_property_read_u64(event_info, "irq-src-reg", &irq_src_reg); if (ret) { pr_err("Error getting irq-src-reg from dt: %d\n", ret); - kfree(irq_events); - kfree(int_reg_bits); goto error_event_infos; } ret = of_property_read_u64(event_info, "irq-reset-reg", &irq_reset_reg); if (ret) { pr_err("Error getting irq-reset-reg from dt: %d\n", ret); - kfree(irq_events); - kfree(int_reg_bits); goto error_event_infos; } ret = of_property_read_u64(event_info, "irq-mask-reg", &irq_mask_reg); if (ret) { pr_err("Error getting irq-mask-reg from dt: %d\n", ret); - kfree(irq_events); - kfree(int_reg_bits); goto error_event_infos; } @@ -591,30 +595,25 @@ static int parse_interrupts(struct lwis_device *lwis_dev) of_property_read_u32(event_info, "irq-reg-bitwidth", &irq_reg_bitwidth); - critical_events_num = parse_critical_irq_events(event_info, &critical_events); + lwis_interrupt_set_basic_info(lwis_dev->irqs, i, irq_reg_space, irq_reg_bid, + irq_src_reg, irq_reset_reg, irq_mask_reg, + irq_overflow_reg, irq_mask_reg_toggle, + irq_reg_bitwidth); - ret = lwis_interrupt_set_event_info( - lwis_dev->irqs, i, irq_reg_space, irq_reg_bid, (int64_t *)irq_events, - irq_events_num, int_reg_bits, int_reg_bits_num, irq_src_reg, irq_reset_reg, - irq_mask_reg, irq_overflow_reg, irq_mask_reg_toggle, irq_reg_bitwidth, - (int64_t *)critical_events, critical_events_num); + ret = lwis_interrupt_get(lwis_dev->irqs, i, plat_dev); if (ret) { - pr_err("Error setting event info for interrupt %d %d\n", i, ret); - if (critical_events) { - kfree(critical_events); - } - kfree(irq_events); - kfree(int_reg_bits); + pr_err("Cannot set irq %s\n", name); + goto error_event_infos; + } + + ret = parse_interrupts_event_info(lwis_dev->irqs, i, event_info); + if (ret) { + pr_err("Cannot set event info %s\n", name); goto error_event_infos; } of_node_put(event_info); i++; - if (critical_events) { - kfree(critical_events); - } - kfree(irq_events); - kfree(int_reg_bits); } #ifdef LWIS_DT_DEBUG diff --git a/lwis_interrupt.c b/lwis_interrupt.c index f5ec28c..2647a4f 100644 --- a/lwis_interrupt.c +++ b/lwis_interrupt.c @@ -85,30 +85,37 @@ void lwis_interrupt_list_free(struct lwis_interrupt_list *list) kfree(list->irq); } -int lwis_interrupt_get(struct lwis_interrupt_list *list, int index, char *name, - struct platform_device *plat_dev) +int lwis_interrupt_init(struct lwis_interrupt_list *list, int index, char *name) { - int irq; - int ret = 0; - if (!list || index < 0 || index >= list->count) { return -EINVAL; } - irq = platform_get_irq(plat_dev, index); - if (irq <= 0) { - pr_err("Error retriving interrupt %s at %d\n", name, index); - return -EINVAL; - } - /* Initialize the spinlock */ spin_lock_init(&list->irq[index].lock); - list->irq[index].irq = irq; strscpy(list->irq[index].name, name, IRQ_FULL_NAME_LENGTH); snprintf(list->irq[index].full_name, IRQ_FULL_NAME_LENGTH, "lwis-%s:%s", list->lwis_dev->name, name); list->irq[index].has_events = false; list->irq[index].lwis_dev = list->lwis_dev; + return 0; +} + +int lwis_interrupt_get(struct lwis_interrupt_list *list, int index, + struct platform_device *plat_dev) +{ + int irq; + int ret = 0; + unsigned long flags; + + irq = platform_get_irq(plat_dev, index); + if (irq <= 0) { + pr_err("Error retrieving interrupt %s at %d\n", list->irq[index].full_name, index); + return -EINVAL; + } + + spin_lock_irqsave(&list->irq[index].lock, flags); + list->irq[index].irq = irq; ret = request_irq(irq, lwis_interrupt_event_isr, IRQF_SHARED, list->irq[index].full_name, &list->irq[index]); @@ -121,6 +128,7 @@ int lwis_interrupt_get(struct lwis_interrupt_list *list, int index, char *name, dev_warn(list->lwis_dev->dev, "Interrupt %s cannot set affinity.\n", list->irq[index].full_name); } + spin_unlock_irqrestore(&list->irq[index].lock, flags); return 0; } @@ -371,23 +379,13 @@ static irqreturn_t lwis_interrupt_gpios_event_isr(int irq_number, void *data) return IRQ_HANDLED; } -int lwis_interrupt_set_event_info(struct lwis_interrupt_list *list, int index, - const char *irq_reg_space, int irq_reg_bid, int64_t *irq_events, - size_t irq_events_num, uint32_t *int_reg_bits, - size_t int_reg_bits_num, int64_t irq_src_reg, - int64_t irq_reset_reg, int64_t irq_mask_reg, - int64_t irq_overflow_reg, bool mask_toggled, - int irq_reg_access_size, int64_t *critical_events, - size_t critical_events_num) +void lwis_interrupt_set_basic_info(struct lwis_interrupt_list *list, int index, + const char *irq_reg_space, int irq_reg_bid, int64_t irq_src_reg, + int64_t irq_reset_reg, int64_t irq_mask_reg, + int64_t irq_overflow_reg, bool mask_toggled, + int irq_reg_access_size) { - int i, j; unsigned long flags; - bool is_critical = false; - - if (int_reg_bits_num != irq_events_num) { - pr_err("reg bits num != irq event num.\n"); - return -EINVAL; - } /* Protect the structure */ spin_lock_irqsave(&list->irq[index].lock, flags); @@ -404,6 +402,21 @@ int lwis_interrupt_set_event_info(struct lwis_interrupt_list *list, int index, /* Initialize an empty list for enabled events */ INIT_LIST_HEAD(&list->irq[index].enabled_event_infos); spin_unlock_irqrestore(&list->irq[index].lock, flags); +} + +int lwis_interrupt_set_event_info(struct lwis_interrupt_list *list, int index, int64_t *irq_events, + size_t irq_events_num, uint32_t *int_reg_bits, + size_t int_reg_bits_num, int64_t *critical_events, + size_t critical_events_num) +{ + int i, j; + unsigned long flags; + bool is_critical = false; + + if (int_reg_bits_num != irq_events_num) { + pr_err("reg bits num != irq event num.\n"); + return -EINVAL; + } /* Build the hash table of events we can emit */ for (i = 0; i < irq_events_num; i++) { diff --git a/lwis_interrupt.h b/lwis_interrupt.h index 99700f4..f3bdda0 100644 --- a/lwis_interrupt.h +++ b/lwis_interrupt.h @@ -79,10 +79,15 @@ struct lwis_interrupt_list *lwis_interrupt_list_alloc(struct lwis_device *lwis_d void lwis_interrupt_list_free(struct lwis_interrupt_list *list); /* + * lwis_interrupt_init: Initialize the interrupt by index. + */ +int lwis_interrupt_init(struct lwis_interrupt_list *list, int index, char *name); + +/* * lwis_interrupt_get: Register the interrupt by index. * Returns: 0 if success, -ve if error */ -int lwis_interrupt_get(struct lwis_interrupt_list *list, int index, char *name, +int lwis_interrupt_get(struct lwis_interrupt_list *list, int index, struct platform_device *plat_dev); /* @@ -93,6 +98,16 @@ int lwis_interrupt_get_gpio_irq(struct lwis_interrupt_list *list, int index, cha int gpio_irq); /* + * lwis_interrupt_set_basic_info: Provides basic register info for a given + * interrupt based on index + */ +void lwis_interrupt_set_basic_info(struct lwis_interrupt_list *list, int index, + const char *irq_reg_space, int irq_reg_bid, int64_t irq_src_reg, + int64_t irq_reset_reg, int64_t irq_mask_reg, + int64_t irq_overflow_reg, bool mask_toggled, + int irq_reg_access_size); + +/* * lwis_interrupt_set_event_info: Provides event-info structure for a given * interrupt based on index * @@ -100,13 +115,9 @@ int lwis_interrupt_get_gpio_irq(struct lwis_interrupt_list *list, int index, cha * Does not free irq_reg_space * Returns: 0 on success */ -int lwis_interrupt_set_event_info(struct lwis_interrupt_list *list, int index, - const char *irq_reg_space, int irq_reg_bid, int64_t *irq_events, +int lwis_interrupt_set_event_info(struct lwis_interrupt_list *list, int index, int64_t *irq_events, size_t irq_events_num, uint32_t *int_reg_bits, - size_t int_reg_bits_num, int64_t irq_src_reg, - int64_t irq_reset_reg, int64_t irq_mask_reg, - int64_t irq_overflow_reg, bool mask_toggled, - int irq_reg_access_size, int64_t *critical_events, + size_t int_reg_bits_num, int64_t *critical_events, size_t critical_events_num); /* |