summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGe Bian <bian@google.com>2022-11-14 21:05:12 -0800
committerHolmes Chou <holmeschou@google.com>2023-02-12 23:46:58 +0000
commitc4ad1d45477ee6fa957fc973eff6a0d88e0e44e5 (patch)
tree48a09d9ec06c31f865bd0e68a7595772836abbf2
parent5e94527f78cc1163db07b06e65ca7f318c346f77 (diff)
downloadlwis-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.c171
-rw-r--r--lwis_interrupt.c67
-rw-r--r--lwis_interrupt.h25
3 files changed, 143 insertions, 120 deletions
diff --git a/lwis_dt.c b/lwis_dt.c
index fefbcf2..9604813 100644
--- a/lwis_dt.c
+++ b/lwis_dt.c
@@ -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);
/*