1/*
2 * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 */
6
7#pragma once
8
9#include <basic_types.h>
10
11
12
13/**
14 * irq_t is an identifier that represents a hardware interrupt.
15 * irq handler capabilities refer to an irq_t which is then used by the
16 * kernel to track irq state. An irq_t is also used to interface with an
17 * interrupt controller driver using the functions below.
18 * For most configurations an irq_t is a word_t type and the irq_t values
19 * directly map to harware irq numbers and are also used as indexes into the
20 * kernel's irq cnode that it uses for tracking state.
21 * However on SMP configurations where there can be multiple irq_t identifiers
22 * for a single hardware irq number, such as when there are core local interrupts,
23 * irq_t cannot be assumed to be only a hardware irq number.
24 * In this case, irq_t can be defined as a struct containing additional information.
25 *
26 * Macros are provided to hide this structural difference across configurations:
27 * CORE_IRQ_TO_IRQT: converts from a core id and hw irq number to an irq_t
28 * IRQT_TO_IDX: converts an irq_t to an index in the irq cnode. It is also used
29 *   to encode the irq_t as a single word_t type for sending over IPIs.
30 * IDX_TO_IRQT: converts an index in the irq cnode to an irq_t
31 * IRQT_TO_CORE: extracts the core out of an irq_t
32 * IRQT_TO_IRQL extracts a hw irq out of an irq_t.
33 *
34 * It is expected that interrupt controller drivers that support SMP provide
35 * implementations of these Macros.
36 * Currently only Arm SMP configurations use this scheme.
37 */
38#if defined(ENABLE_SMP_SUPPORT) && defined(CONFIG_ARCH_ARM)
39typedef struct {
40    word_t irq;
41    word_t target_core;
42} irq_t;
43#else
44typedef word_t irq_t;
45#define CORE_IRQ_TO_IRQT(tgt, irq) (irq)
46#define IRQT_TO_IDX(irq) (irq)
47#define IDX_TO_IRQT(idx) (idx)
48#define IRQT_TO_CORE(irqt) 0
49#define IRQT_TO_IRQ(irqt) (irqt)
50#endif
51
52/**
53 * Return a currently pending IRQ.
54 *
55 * This function can be called multiple times and needs to return the same IRQ
56 * until ackInterrupt is called. getActiveIRQ returns irqInvalid if no interrupt
57 * is pending. It is assumed that if isIRQPending is true, then getActiveIRQ
58 * will not return irqInvalid. irqInvalid is a per platform constant that cannot
59 * correspond to an actual IRQ raised by the platform.
60 *
61 * @return     The active IRQ. irqInvalid if no IRQ is pending.
62 */
63static inline irq_t getActiveIRQ(void);
64
65/**
66 * Checks if an IRQ is currently pending in the hardware.
67 *
68 * isIRQPending is used to determine whether to preempt long running operations
69 * at various preemption points throughout the kernel. If this returns true, it
70 * means that if the Kernel were to return to user mode, it would then
71 * immediately take an interrupt.
72 *
73 * @return     True if irq pending, False otherwise.
74 */
75static inline bool_t isIRQPending(void);
76
77/**
78 * maskInterrupt disables and enables IRQs.
79 *
80 * When an IRQ is disabled, it should not raise an interrupt on the processor.
81 *
82 * @param[in]  disable  True to disable IRQ, False to enable IRQ
83 * @param[in]  irq      The irq to modify
84 */
85static inline void maskInterrupt(bool_t disable, irq_t irq);
86
87/**
88 * Acks the interrupt
89 *
90 * ackInterrupt is used by the kernel to indicate it has processed the interrupt
91 * delivery and getActiveIRQ is now able to return a different IRQ number. Note
92 * that this is called after a notification has been signalled to user level,
93 * but before user level has handled the cause and does not imply that the cause
94 * of the interrupt has been handled.
95 *
96 * @param[in]  irq   irq to ack
97 */
98static inline void ackInterrupt(irq_t irq);
99
100/**
101 * Called when getActiveIRQ returns irqInvalid while the kernel is handling an
102 * interrupt entry. An implementation is not required to do anything here, but
103 * can report the spurious IRQ or try prevent it from reoccuring.
104 */
105static inline void handleSpuriousIRQ(void);
106
107/**
108 * Handle a platform-reserved IRQ.
109 *
110 * Platform specific implementation for handling IRQs for interrupts that are
111 * reserved and not made available to user-level. Will be called if getActiveIRQ
112 * returns an IRQ number that is reserved. After this function returns,
113 * ackInterrupt will likely be immediately called after.
114 *
115 * @param[in]  irq   The irq
116 */
117static inline void handleReservedIRQ(irq_t irq);
118
119