xref: /linux/include/linux/pds/pds_intr.h (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
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