summaryrefslogtreecommitdiffstats
path: root/include/linux/pds/pds_intr.h
blob: 56277c37248c340868f57b5744eaa7a51cda6492 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
/* 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_ */