1 /* SPDX-License-Identifier: (GPL-2.0 OR Linux-OpenIB) OR BSD-2-Clause */
2 /* Copyright(c) 2023 Advanced Micro Devices, Inc. */
3
4 #ifndef _PDS_INTR_H_
5 #define _PDS_INTR_H_
6
7 /*
8 * Interrupt control register
9 * @coal_init: Coalescing timer initial value, in
10 * device units. Use @identity->intr_coal_mult
11 * and @identity->intr_coal_div to convert from
12 * usecs to device units:
13 *
14 * coal_init = coal_usecs * coal_mutl / coal_div
15 *
16 * When an interrupt is sent the interrupt
17 * coalescing timer current value
18 * (@coalescing_curr) is initialized with this
19 * value and begins counting down. No more
20 * interrupts are sent until the coalescing
21 * timer reaches 0. When @coalescing_init=0
22 * interrupt coalescing is effectively disabled
23 * and every interrupt assert results in an
24 * interrupt. Reset value: 0
25 * @mask: Interrupt mask. When @mask=1 the interrupt
26 * resource will not send an interrupt. When
27 * @mask=0 the interrupt resource will send an
28 * interrupt if an interrupt event is pending
29 * or on the next interrupt assertion event.
30 * Reset value: 1
31 * @credits: Interrupt credits. This register indicates
32 * how many interrupt events the hardware has
33 * sent. When written by software this
34 * register atomically decrements @int_credits
35 * by the value written. When @int_credits
36 * becomes 0 then the "pending interrupt" bit
37 * in the Interrupt Status register is cleared
38 * by the hardware and any pending but unsent
39 * interrupts are cleared.
40 * !!!IMPORTANT!!! This is a signed register.
41 * @flags: Interrupt control flags
42 * @unmask -- When this bit is written with a 1
43 * the interrupt resource will set mask=0.
44 * @coal_timer_reset -- When this
45 * bit is written with a 1 the
46 * @coalescing_curr will be reloaded with
47 * @coalescing_init to reset the coalescing
48 * timer.
49 * @mask_on_assert: Automatically mask on assertion. When
50 * @mask_on_assert=1 the interrupt resource
51 * will set @mask=1 whenever an interrupt is
52 * sent. When using interrupts in Legacy
53 * Interrupt mode the driver must select
54 * @mask_on_assert=0 for proper interrupt
55 * operation.
56 * @coalescing_curr: Coalescing timer current value, in
57 * microseconds. When this value reaches 0
58 * the interrupt resource is again eligible to
59 * send an interrupt. If an interrupt event
60 * is already pending when @coalescing_curr
61 * reaches 0 the pending interrupt will be
62 * sent, otherwise an interrupt will be sent
63 * on the next interrupt assertion event.
64 */
65 struct pds_core_intr {
66 u32 coal_init;
67 u32 mask;
68 u16 credits;
69 u16 flags;
70 #define PDS_CORE_INTR_F_UNMASK 0x0001
71 #define PDS_CORE_INTR_F_TIMER_RESET 0x0002
72 u32 mask_on_assert;
73 u32 coalescing_curr;
74 u32 rsvd6[3];
75 };
76
77 #ifndef __CHECKER__
78 static_assert(sizeof(struct pds_core_intr) == 32);
79 #endif /* __CHECKER__ */
80
81 #define PDS_CORE_INTR_CTRL_REGS_MAX 2048
82 #define PDS_CORE_INTR_CTRL_COAL_MAX 0x3F
83 #define PDS_CORE_INTR_INDEX_NOT_ASSIGNED -1
84
85 struct pds_core_intr_status {
86 u32 status[2];
87 };
88
89 /**
90 * enum pds_core_intr_mask_vals - valid values for mask and mask_assert.
91 * @PDS_CORE_INTR_MASK_CLEAR: unmask interrupt.
92 * @PDS_CORE_INTR_MASK_SET: mask interrupt.
93 */
94 enum pds_core_intr_mask_vals {
95 PDS_CORE_INTR_MASK_CLEAR = 0,
96 PDS_CORE_INTR_MASK_SET = 1,
97 };
98
99 /**
100 * enum pds_core_intr_credits_bits - Bitwise composition of credits values.
101 * @PDS_CORE_INTR_CRED_COUNT: bit mask of credit count, no shift needed.
102 * @PDS_CORE_INTR_CRED_COUNT_SIGNED: bit mask of credit count, including sign bit.
103 * @PDS_CORE_INTR_CRED_UNMASK: unmask the interrupt.
104 * @PDS_CORE_INTR_CRED_RESET_COALESCE: reset the coalesce timer.
105 * @PDS_CORE_INTR_CRED_REARM: unmask the and reset the timer.
106 */
107 enum pds_core_intr_credits_bits {
108 PDS_CORE_INTR_CRED_COUNT = 0x7fffu,
109 PDS_CORE_INTR_CRED_COUNT_SIGNED = 0xffffu,
110 PDS_CORE_INTR_CRED_UNMASK = 0x10000u,
111 PDS_CORE_INTR_CRED_RESET_COALESCE = 0x20000u,
112 PDS_CORE_INTR_CRED_REARM = (PDS_CORE_INTR_CRED_UNMASK |
113 PDS_CORE_INTR_CRED_RESET_COALESCE),
114 };
115
116 static inline void
pds_core_intr_coal_init(struct pds_core_intr __iomem * intr_ctrl,u32 coal)117 pds_core_intr_coal_init(struct pds_core_intr __iomem *intr_ctrl, u32 coal)
118 {
119 iowrite32(coal, &intr_ctrl->coal_init);
120 }
121
122 static inline void
pds_core_intr_mask(struct pds_core_intr __iomem * intr_ctrl,u32 mask)123 pds_core_intr_mask(struct pds_core_intr __iomem *intr_ctrl, u32 mask)
124 {
125 iowrite32(mask, &intr_ctrl->mask);
126 }
127
128 static inline void
pds_core_intr_credits(struct pds_core_intr __iomem * intr_ctrl,u32 cred,u32 flags)129 pds_core_intr_credits(struct pds_core_intr __iomem *intr_ctrl,
130 u32 cred, u32 flags)
131 {
132 if (WARN_ON_ONCE(cred > PDS_CORE_INTR_CRED_COUNT)) {
133 cred = ioread32(&intr_ctrl->credits);
134 cred &= PDS_CORE_INTR_CRED_COUNT_SIGNED;
135 }
136
137 iowrite32(cred | flags, &intr_ctrl->credits);
138 }
139
140 static inline void
pds_core_intr_clean_flags(struct pds_core_intr __iomem * intr_ctrl,u32 flags)141 pds_core_intr_clean_flags(struct pds_core_intr __iomem *intr_ctrl, u32 flags)
142 {
143 u32 cred;
144
145 cred = ioread32(&intr_ctrl->credits);
146 cred &= PDS_CORE_INTR_CRED_COUNT_SIGNED;
147 cred |= flags;
148 iowrite32(cred, &intr_ctrl->credits);
149 }
150
151 static inline void
pds_core_intr_clean(struct pds_core_intr __iomem * intr_ctrl)152 pds_core_intr_clean(struct pds_core_intr __iomem *intr_ctrl)
153 {
154 pds_core_intr_clean_flags(intr_ctrl, PDS_CORE_INTR_CRED_RESET_COALESCE);
155 }
156
157 static inline void
pds_core_intr_mask_assert(struct pds_core_intr __iomem * intr_ctrl,u32 mask)158 pds_core_intr_mask_assert(struct pds_core_intr __iomem *intr_ctrl, u32 mask)
159 {
160 iowrite32(mask, &intr_ctrl->mask_on_assert);
161 }
162
163 #endif /* _PDS_INTR_H_ */
164