1/*
2 * Copyright 2019, Data61
3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO)
4 * ABN 41 687 119 230.
5 *
6 * This software may be distributed and modified according to the terms of
7 * the BSD 2-Clause license. Note that NO WARRANTY is provided.
8 * See "LICENSE_BSD2.txt" for details.
9 *
10 * @TAG(DATA61_BSD)
11 */
12
13#pragma once
14
15#include <inttypes.h>
16#include <stdint.h>
17#include <errno.h>
18
19#define __PS_IRQ_VALID_ARGS(FUN) do {\
20    if (!irq_ops) return -EINVAL;\
21    if (!irq_ops->cookie) return -EINVAL;\
22    if (!irq_ops->FUN) return -ENOSYS;\
23} while(0)
24
25#define PS_INVALID_IRQ_ID -1
26
27typedef enum irq_type {
28    PS_NONE,
29    PS_MSI,
30    PS_IOAPIC,
31    PS_INTERRUPT,
32    PS_TRIGGER,
33    PS_PER_CPU,
34    PS_OTHER,
35} irq_type_t;
36
37typedef enum irq_trigger_type {
38    PS_LEVEL_TRIGGERED,
39    PS_EDGE_TRIGGERED,
40} irq_trigger_type_t;
41
42typedef struct {
43    irq_type_t type;
44    union {
45        struct {
46            long ioapic;
47            long pin;
48            long level;
49            long polarity;
50            long vector;
51        } ioapic;
52        struct {
53            long pci_bus;
54            long pci_dev;
55            long pci_func;
56            long handle;
57            long vector;
58        } msi;
59        struct {
60            long number;
61        } irq;
62        struct {
63            long number;
64            long trigger;
65        } trigger;
66        struct {
67            long number;
68            long trigger;
69            long cpu_idx;
70        } cpu;
71        void *other; /* Implementation-specific information. */
72    };
73} ps_irq_t;
74
75typedef int irq_id_t;
76
77/*
78 * Acknowledges an interrupt.
79 *
80 * @param ack_data Implementation specific structure containing information needed to ACK an interrupt.
81 *
82 * @return 0 on success, otherwise an error code
83 */
84typedef int (*ps_irq_acknowledge_fn_t)(void *ack_data);
85
86/*
87 * Callback type that is accepted by implementations of the IRQ interface. The
88 * callback is responsible for acknowledging the interrupt via the supplied
89 * acknowledge function.
90 *
91 * Note that the acknowledge function pointer and its token, 'ack_data' can be
92 * saved and called later. This might be useful in some contexts where you need
93 * to perform some maintenance before acknowledging the IRQ. The lifetime of
94 * the 'ack_data' token lasts until the acknowledge function is called. Thus
95 * you cannot call the acknowledge function again.
96 *
97 * @param data Pointer to data which is passed into the callback function
98 * @param acknowledge_fn Function pointer to an function used to acknowledge an interrupt
99 * @param ack_data Data to be passed to 'acknowledge_fn'
100 */
101typedef void (*irq_callback_fn_t)(void *data, ps_irq_acknowledge_fn_t acknowledge_fn, void *ack_data);
102
103/*
104 * Registers an interrupt with the interface and allocates data necessary to
105 * keep track of the interrupt. Also associates a callback function with the
106 * interrupt which is called when the interrupt arrives.
107 *
108 * Returns a valid IRQ ID on success that has a value >= 0, otherwise an error
109 * code with a value < 0.
110 *
111 * @param cookie Cookie for the IRQ interface
112 * @param irq Information about the interrupt that is to be registered
113 * @param callback Callback function that is called when the interrupt arrives
114 * @param callback_data Pointer that is to be passed into the callback function
115 *
116 * @return A valid IRQ ID on success that has a value >= 0, otherwise an error code
117 */
118typedef irq_id_t (*ps_irq_register_fn_t)(void *cookie, ps_irq_t irq, irq_callback_fn_t callback, void *callback_data);
119
120/*
121 * Unregisters a registered interrupt and deallocates any data that was
122 * associated with the registered interrupt.
123 *
124 * @param cookie Cookie for the IRQ interface
125 * @param irq_id An IRQ ID that was allocated by the IRQ interface
126 *
127 * @return 0 on success, otherwise an error code
128 */
129typedef int (*ps_irq_unregister_fn_t)(void *cookie, irq_id_t irq_id);
130
131typedef struct {
132    void *cookie;
133    ps_irq_register_fn_t irq_register_fn;
134    ps_irq_unregister_fn_t irq_unregister_fn;
135} ps_irq_ops_t;
136
137static inline int ps_irq_register(ps_irq_ops_t *irq_ops, ps_irq_t irq, irq_callback_fn_t callback, void *callback_data)
138{
139    __PS_IRQ_VALID_ARGS(irq_register_fn);
140    return irq_ops->irq_register_fn(irq_ops->cookie, irq, callback, callback_data);
141}
142
143static inline int ps_irq_unregister(ps_irq_ops_t *irq_ops, irq_id_t irq_id)
144{
145    __PS_IRQ_VALID_ARGS(irq_unregister_fn);
146    return irq_ops->irq_unregister_fn(irq_ops->cookie, irq_id);
147}
148