/* * Google LWIS Interrupt Handler * * Copyright (c) 2018 Google, LLC * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ #ifndef LWIS_INTERRUPT_H_ #define LWIS_INTERRUPT_H_ #include #include #include #include #define EVENT_INFO_HASH_BITS 8 #define IRQ_FULL_NAME_LENGTH 32 #define LEAF_NODE_HASH_BITS 8 enum lwis_interrupt_types { REGULAR_INTERRUPT, AGGREGATE_INTERRUPT, LEAF_INTERRUPT, GPIO_HW_INTERRUPT, FAKEEVENT_INTERRUPT }; /* * struct lwis_interrupt_leaf_node * This is to represent aggregate interrupt's leaf node */ struct lwis_interrupt_leaf_node { uint32_t int_reg_bit; int count; int32_t *leaf_irq_indexes; struct list_head node; }; struct lwis_interrupt { int irq; /* IRQ name */ char name[IRQ_FULL_NAME_LENGTH]; /* Full name consists of both device and irq name */ char full_name[IRQ_FULL_NAME_LENGTH]; /* Device that owns this interrupt */ struct lwis_device *lwis_dev; /* Spinlock to lock acccess to this struct */ spinlock_t lock; /* Flag if the event info has been set */ bool has_events; /* BID of the register space where the status/reset/mask for this ISR * can be accessed */ int irq_reg_bid; /* Offset of the source register */ int64_t irq_src_reg; /* Offset of the clear/reset register */ int64_t irq_reset_reg; /* Offset of the mask register */ int64_t irq_mask_reg; /* Offset of the overflow register */ int64_t irq_overflow_reg; /* IRQ register access size, in case it is different from the bus * bitwidth */ int irq_reg_access_size; /* If mask_reg actually disable the interrupts. */ bool mask_toggled; /* Type of the interrupt */ int32_t irq_type; /* Hash table of event info */ /* GUARDED_BY(lock) */ DECLARE_HASHTABLE(event_infos, EVENT_INFO_HASH_BITS); /* List of enabled events */ /* GUARDED_BY(lock) */ struct list_head enabled_event_infos; /* Select the interrupt line behavior */ int irq_gpios_types; /* List of aggregate interrupt leaf nodes */ /* GUARDED_BY(lock) */ struct list_head leaf_nodes; /* Store the combined IRQ mask value */ uint64_t mask_value; /* If IRQ mask value is written */ bool has_mask_value; }; /* * struct lwis_interrupt_list * This is to store the list of interrupts the LWIS device uses */ struct lwis_interrupt_list { struct lwis_interrupt *irq; int count; /* Device that owns this interrupt list */ struct lwis_device *lwis_dev; }; /* * lwis_interrupt_list_alloc: Allocate an instance of the lwis_interrupt_list * and initialize the data structures according to the number of interrupts * specified. */ struct lwis_interrupt_list *lwis_interrupt_list_alloc(struct lwis_device *lwis_dev, int count); /* * lwis_interrupt_free_leaves: Deallocate the leaf_nodes in lwis_interrupt structure. */ void lwis_interrupt_free_leaves(struct lwis_interrupt *irq); /* * lwis_interrupt_list_free: Deallocate the lwis_interrupt_list structure. */ 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, struct platform_device *plat_dev); /* * lwis_interrupt_get_gpio_irq: Register the GPIO interrupt by index * Returns: 0 if success, -ve if error */ int lwis_interrupt_get_gpio_irq(struct lwis_interrupt_list *list, int index, char *name, int gpio_irq, int32_t irq_gpios_types); /* * 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, int32_t irq_type); /* * lwis_interrupt_set_event_info: Provides event-info structure for a given * interrupt based on index * * Takes ownership of (and later frees) irq_events and int_reg_bits * Does not free irq_reg_space * Returns: 0 on success */ 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); /* * lwis_interrupt_add_leaf: Provides one leaf node information for the aggregate interrupt * * Returns: 0 on success */ int lwis_interrupt_add_leaf(struct lwis_interrupt_list *list, int index, uint32_t int_reg_bit, int count, int32_t *leaf_indexes); /* * lwis_interrupt_set_gpios_event_info: Provides event-info structure for a given * interrupt based on index * * Returns: 0 on success */ int lwis_interrupt_set_gpios_event_info(struct lwis_interrupt_list *list, int index, int64_t irq_event); /* * lwis_interrupt_write_combined_mask_value: Handles writing combined mask value * * Locks: May lock list->irq[index].lock * Alloc: No * Returns: 0 on success */ int lwis_interrupt_write_combined_mask_value(struct lwis_interrupt_list *list); /* * lwis_interrupt_event_enable: Handles masking and unmasking interrupts when * an event is enabled or disabled * * Locks: May lock list->irq[index].lock * Alloc: No * Returns: 0 on success (event enabled/disabled) * -EINVAL if event not known to this list */ int lwis_interrupt_event_enable(struct lwis_interrupt_list *list, int64_t event_id, bool enabled); /* * lwis_interrupt_print: Debug function to print all the interrupts in the * supplied list. */ void lwis_interrupt_print(struct lwis_interrupt_list *list); int lwis_fake_event_inject(void *data); #endif /* LWIS_INTERRUPT_H_ */