vlib: clean up r2 plugin registration relocator
[vpp.git] / src / vppinfra / interrupt.h
1 /* SPDX-License-Identifier: Apache-2.0
2  * Copyright (c) 2023 Cisco Systems, Inc.
3  */
4
5 #ifndef included_clib_interrupt_h
6 #define included_clib_interrupt_h
7
8 #include <vppinfra/clib.h>
9 #include <vppinfra/vec.h>
10
11 typedef struct
12 {
13   CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
14   u32 n_int;
15   u32 uwords_allocated;
16   u32 uwords_used;
17   uword *local;
18   uword *remote;
19 } clib_interrupt_header_t;
20
21 void clib_interrupt_init (void **data, u32 n_interrupts);
22 void clib_interrupt_resize (void **data, u32 n_interrupts);
23
24 static_always_inline void
25 clib_interrupt_free (void **data)
26 {
27   if (data[0])
28     {
29       clib_mem_free (data[0]);
30       data[0] = 0;
31     }
32 }
33
34 static_always_inline int
35 clib_interrupt_get_n_int (void *d)
36 {
37   clib_interrupt_header_t *h = d;
38   if (h)
39     return h->n_int;
40   return 0;
41 }
42
43 static_always_inline void
44 clib_interrupt_set (void *in, int int_num)
45 {
46   clib_interrupt_header_t *h = in;
47   u32 off = int_num >> log2_uword_bits;
48   uword bit = 1ULL << (int_num & pow2_mask (log2_uword_bits));
49
50   ASSERT (int_num < h->n_int);
51
52   h->local[off] |= bit;
53 }
54
55 static_always_inline void
56 clib_interrupt_set_atomic (void *in, int int_num)
57 {
58   clib_interrupt_header_t *h = in;
59   u32 off = int_num >> log2_uword_bits;
60   uword bit = 1ULL << (int_num & pow2_mask (log2_uword_bits));
61
62   ASSERT (int_num < h->n_int);
63
64   __atomic_fetch_or (h->remote + off, bit, __ATOMIC_RELAXED);
65 }
66
67 static_always_inline void
68 clib_interrupt_clear (void *in, int int_num)
69 {
70   clib_interrupt_header_t *h = in;
71   u32 off = int_num >> log2_uword_bits;
72   uword bit = 1ULL << (int_num & pow2_mask (log2_uword_bits));
73   uword *loc = h->local;
74   uword *rem = h->remote;
75   uword v;
76
77   ASSERT (int_num < h->n_int);
78
79   v = loc[off] | __atomic_exchange_n (rem + off, 0, __ATOMIC_SEQ_CST);
80   loc[off] = v & ~bit;
81 }
82
83 static_always_inline int
84 clib_interrupt_get_next_and_clear (void *in, int last)
85 {
86   clib_interrupt_header_t *h = in;
87   uword bit, v;
88   uword *loc = h->local;
89   uword *rem = h->remote;
90   u32 off, n_uwords = h->uwords_used;
91
92   ASSERT (last >= -1 && last < (int) h->n_int);
93
94   off = (last + 1) >> log2_uword_bits;
95
96   if (off >= n_uwords)
97     return -1;
98
99   v = loc[off] | __atomic_exchange_n (rem + off, 0, __ATOMIC_SEQ_CST);
100   loc[off] = v;
101
102   v &= ~pow2_mask ((last + 1) & pow2_mask (log2_uword_bits));
103
104   while (v == 0)
105     {
106       if (++off == n_uwords)
107         return -1;
108
109       v = loc[off] | __atomic_exchange_n (rem + off, 0, __ATOMIC_SEQ_CST);
110       loc[off] = v;
111     }
112
113   bit = get_lowest_set_bit (v);
114   loc[off] &= ~bit;
115   return get_lowest_set_bit_index (bit) + (int) (off << log2_uword_bits);
116 }
117
118 static_always_inline int
119 clib_interrupt_is_any_pending (void *in)
120 {
121   clib_interrupt_header_t *h = in;
122   u32 n_uwords = h->uwords_used;
123   uword *loc = h->local;
124   uword *rem = h->remote;
125
126   for (u32 i = 0; i < n_uwords; i++)
127     if (loc[i])
128       return 1;
129
130   for (u32 i = 0; i < n_uwords; i++)
131     if (rem[i])
132       return 1;
133
134   return 0;
135 }
136
137 #endif /* included_clib_interrupt_h */