/* SPDX-License-Identifier: Apache-2.0 * Copyright (c) 2023 Cisco Systems, Inc. */ #ifndef included_clib_interrupt_h #define included_clib_interrupt_h #include #include typedef struct { CLIB_CACHE_LINE_ALIGN_MARK (cacheline0); u32 n_int; u32 uwords_allocated; u32 uwords_used; uword *local; uword *remote; } clib_interrupt_header_t; void clib_interrupt_init (void **data, u32 n_interrupts); void clib_interrupt_resize (void **data, u32 n_interrupts); static_always_inline void clib_interrupt_free (void **data) { if (data[0]) { clib_mem_free (data[0]); data[0] = 0; } } static_always_inline int clib_interrupt_get_n_int (void *d) { clib_interrupt_header_t *h = d; if (h) return h->n_int; return 0; } static_always_inline void clib_interrupt_set (void *in, int int_num) { clib_interrupt_header_t *h = in; u32 off = int_num >> log2_uword_bits; uword bit = 1ULL << (int_num & pow2_mask (log2_uword_bits)); ASSERT (int_num < h->n_int); h->local[off] |= bit; } static_always_inline void clib_interrupt_set_atomic (void *in, int int_num) { clib_interrupt_header_t *h = in; u32 off = int_num >> log2_uword_bits; uword bit = 1ULL << (int_num & pow2_mask (log2_uword_bits)); ASSERT (int_num < h->n_int); __atomic_fetch_or (h->remote + off, bit, __ATOMIC_RELAXED); } static_always_inline void clib_interrupt_clear (void *in, int int_num) { clib_interrupt_header_t *h = in; u32 off = int_num >> log2_uword_bits; uword bit = 1ULL << (int_num & pow2_mask (log2_uword_bits)); uword *loc = h->local; uword *rem = h->remote; uword v; ASSERT (int_num < h->n_int); v = loc[off] | __atomic_exchange_n (rem + off, 0, __ATOMIC_SEQ_CST); loc[off] = v & ~bit; } static_always_inline int clib_interrupt_get_next_and_clear (void *in, int last) { clib_interrupt_header_t *h = in; uword bit, v; uword *loc = h->local; uword *rem = h->remote; u32 off, n_uwords = h->uwords_used; ASSERT (last >= -1 && last < (int) h->n_int); off = (last + 1) >> log2_uword_bits; if (off >= n_uwords) return -1; v = loc[off] | __atomic_exchange_n (rem + off, 0, __ATOMIC_SEQ_CST); loc[off] = v; v &= ~pow2_mask ((last + 1) & pow2_mask (log2_uword_bits)); while (v == 0) { if (++off == n_uwords) return -1; v = loc[off] | __atomic_exchange_n (rem + off, 0, __ATOMIC_SEQ_CST); loc[off] = v; } bit = get_lowest_set_bit (v); loc[off] &= ~bit; return get_lowest_set_bit_index (bit) + (int) (off << log2_uword_bits); } static_always_inline int clib_interrupt_is_any_pending (void *in) { clib_interrupt_header_t *h = in; u32 n_uwords = h->uwords_used; uword *loc = h->local; uword *rem = h->remote; for (u32 i = 0; i < n_uwords; i++) if (loc[i]) return 1; for (u32 i = 0; i < n_uwords; i++) if (rem[i]) return 1; return 0; } #endif /* included_clib_interrupt_h */