164 lines
5.9 KiB
C
164 lines
5.9 KiB
C
/* 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_ */
|