/* SPDX-License-Identifier: (GPL-2.0 OR Linux-OpenIB) OR BSD-2-Clause */ /* Copyright(c) 2023 Advanced Micro Devices, Inc. */ #ifndef _PDS_INTR_H_ #define _PDS_INTR_H_ /* * Interrupt control register * @coal_init: Coalescing timer initial value, in * device units. Use @identity->intr_coal_mult * and @identity->intr_coal_div to convert from * usecs to device units: * * coal_init = coal_usecs * coal_mutl / coal_div * * When an interrupt is sent the interrupt * coalescing timer current value * (@coalescing_curr) is initialized with this * value and begins counting down. No more * interrupts are sent until the coalescing * timer reaches 0. When @coalescing_init=0 * interrupt coalescing is effectively disabled * and every interrupt assert results in an * interrupt. Reset value: 0 * @mask: Interrupt mask. When @mask=1 the interrupt * resource will not send an interrupt. When * @mask=0 the interrupt resource will send an * interrupt if an interrupt event is pending * or on the next interrupt assertion event. * Reset value: 1 * @credits: Interrupt credits. This register indicates * how many interrupt events the hardware has * sent. When written by software this * register atomically decrements @int_credits * by the value written. When @int_credits * becomes 0 then the "pending interrupt" bit * in the Interrupt Status register is cleared * by the hardware and any pending but unsent * interrupts are cleared. * !!!IMPORTANT!!! This is a signed register. * @flags: Interrupt control flags * @unmask -- When this bit is written with a 1 * the interrupt resource will set mask=0. * @coal_timer_reset -- When this * bit is written with a 1 the * @coalescing_curr will be reloaded with * @coalescing_init to reset the coalescing * timer. * @mask_on_assert: Automatically mask on assertion. When * @mask_on_assert=1 the interrupt resource * will set @mask=1 whenever an interrupt is * sent. When using interrupts in Legacy * Interrupt mode the driver must select * @mask_on_assert=0 for proper interrupt * operation. * @coalescing_curr: Coalescing timer current value, in * microseconds. When this value reaches 0 * the interrupt resource is again eligible to * send an interrupt. If an interrupt event * is already pending when @coalescing_curr * reaches 0 the pending interrupt will be * sent, otherwise an interrupt will be sent * on the next interrupt assertion event. */ struct pds_core_intr { u32 coal_init; u32 mask; u16 credits; u16 flags; #define PDS_CORE_INTR_F_UNMASK 0x0001 #define PDS_CORE_INTR_F_TIMER_RESET 0x0002 u32 mask_on_assert; u32 coalescing_curr; u32 rsvd6[3]; }; #ifndef __CHECKER__ static_assert(sizeof(struct pds_core_intr) == 32); #endif /* __CHECKER__ */ #define PDS_CORE_INTR_CTRL_REGS_MAX 2048 #define PDS_CORE_INTR_CTRL_COAL_MAX 0x3F #define PDS_CORE_INTR_INDEX_NOT_ASSIGNED -1 struct pds_core_intr_status { u32 status[2]; }; /** * enum pds_core_intr_mask_vals - valid values for mask and mask_assert. * @PDS_CORE_INTR_MASK_CLEAR: unmask interrupt. * @PDS_CORE_INTR_MASK_SET: mask interrupt. */ enum pds_core_intr_mask_vals { PDS_CORE_INTR_MASK_CLEAR = 0, PDS_CORE_INTR_MASK_SET = 1, }; /** * enum pds_core_intr_credits_bits - Bitwise composition of credits values. * @PDS_CORE_INTR_CRED_COUNT: bit mask of credit count, no shift needed. * @PDS_CORE_INTR_CRED_COUNT_SIGNED: bit mask of credit count, including sign bit. * @PDS_CORE_INTR_CRED_UNMASK: unmask the interrupt. * @PDS_CORE_INTR_CRED_RESET_COALESCE: reset the coalesce timer. * @PDS_CORE_INTR_CRED_REARM: unmask the and reset the timer. */ enum pds_core_intr_credits_bits { PDS_CORE_INTR_CRED_COUNT = 0x7fffu, PDS_CORE_INTR_CRED_COUNT_SIGNED = 0xffffu, PDS_CORE_INTR_CRED_UNMASK = 0x10000u, PDS_CORE_INTR_CRED_RESET_COALESCE = 0x20000u, PDS_CORE_INTR_CRED_REARM = (PDS_CORE_INTR_CRED_UNMASK | PDS_CORE_INTR_CRED_RESET_COALESCE), }; static inline void pds_core_intr_coal_init(struct pds_core_intr __iomem *intr_ctrl, u32 coal) { iowrite32(coal, &intr_ctrl->coal_init); } static inline void pds_core_intr_mask(struct pds_core_intr __iomem *intr_ctrl, u32 mask) { iowrite32(mask, &intr_ctrl->mask); } static inline void pds_core_intr_credits(struct pds_core_intr __iomem *intr_ctrl, u32 cred, u32 flags) { if (WARN_ON_ONCE(cred > PDS_CORE_INTR_CRED_COUNT)) { cred = ioread32(&intr_ctrl->credits); cred &= PDS_CORE_INTR_CRED_COUNT_SIGNED; } iowrite32(cred | flags, &intr_ctrl->credits); } static inline void pds_core_intr_clean_flags(struct pds_core_intr __iomem *intr_ctrl, u32 flags) { u32 cred; cred = ioread32(&intr_ctrl->credits); cred &= PDS_CORE_INTR_CRED_COUNT_SIGNED; cred |= flags; iowrite32(cred, &intr_ctrl->credits); } static inline void pds_core_intr_clean(struct pds_core_intr __iomem *intr_ctrl) { pds_core_intr_clean_flags(intr_ctrl, PDS_CORE_INTR_CRED_RESET_COALESCE); } static inline void pds_core_intr_mask_assert(struct pds_core_intr __iomem *intr_ctrl, u32 mask) { iowrite32(mask, &intr_ctrl->mask_on_assert); } #endif /* _PDS_INTR_H_ */