6
6
* Author: Tanmay Inamdar <[email protected] >
7
7
8
8
*/
9
+ #include <linux/bitfield.h>
9
10
#include <linux/cpu.h>
10
11
#include <linux/interrupt.h>
11
12
#include <linux/irqdomain.h>
22
23
#define IDX_PER_GROUP 8
23
24
#define IRQS_PER_IDX 16
24
25
#define NR_HW_IRQS 16
25
- #define NR_MSI_VEC (IDX_PER_GROUP * IRQS_PER_IDX * NR_HW_IRQS)
26
+ #define NR_MSI_BITS (IDX_PER_GROUP * IRQS_PER_IDX * NR_HW_IRQS)
27
+ #define NR_MSI_VEC (NR_MSI_BITS / num_possible_cpus())
28
+
29
+ #define MSI_GROUP_MASK GENMASK(22, 19)
30
+ #define MSI_INDEX_MASK GENMASK(18, 16)
31
+ #define MSI_INTR_MASK GENMASK(19, 16)
32
+
33
+ #define MSInRx_HWIRQ_MASK GENMASK(6, 4)
34
+ #define DATA_HWIRQ_MASK GENMASK(3, 0)
26
35
27
36
struct xgene_msi {
28
37
struct irq_domain * inner_domain ;
@@ -37,8 +46,26 @@ struct xgene_msi {
37
46
static struct xgene_msi * xgene_msi_ctrl ;
38
47
39
48
/*
40
- * X-Gene v1 has 16 groups of MSI termination registers MSInIRx, where
41
- * n is group number (0..F), x is index of registers in each group (0..7)
49
+ * X-Gene v1 has 16 frames of MSI termination registers MSInIRx, where n is
50
+ * frame number (0..15), x is index of registers in each frame (0..7). Each
51
+ * 32b register is at the beginning of a 64kB region, each frame occupying
52
+ * 512kB (and the whole thing 8MB of PA space).
53
+ *
54
+ * Each register supports 16 MSI vectors (0..15) to generate interrupts. A
55
+ * write to the MSInIRx from the PCI side generates an interrupt. A read
56
+ * from the MSInRx on the CPU side returns a bitmap of the pending MSIs in
57
+ * the lower 16 bits. A side effect of this read is that all pending
58
+ * interrupts are acknowledged and cleared).
59
+ *
60
+ * Additionally, each MSI termination frame has 1 MSIINTn register (n is
61
+ * 0..15) to indicate the MSI pending status caused by any of its 8
62
+ * termination registers, reported as a bitmap in the lower 8 bits. Each 32b
63
+ * register is at the beginning of a 64kB region (and overall occupying an
64
+ * extra 1MB).
65
+ *
66
+ * There is one GIC IRQ assigned for each MSI termination frame, 16 in
67
+ * total.
68
+ *
42
69
* The register layout is as follows:
43
70
* MSI0IR0 base_addr
44
71
* MSI0IR1 base_addr + 0x10000
@@ -59,107 +86,74 @@ static struct xgene_msi *xgene_msi_ctrl;
59
86
* MSIINT1 base_addr + 0x810000
60
87
* ... ...
61
88
* MSIINTF base_addr + 0x8F0000
62
- *
63
- * Each index register supports 16 MSI vectors (0..15) to generate interrupt.
64
- * There are total 16 GIC IRQs assigned for these 16 groups of MSI termination
65
- * registers.
66
- *
67
- * Each MSI termination group has 1 MSIINTn register (n is 0..15) to indicate
68
- * the MSI pending status caused by 1 of its 8 index registers.
69
89
*/
70
90
71
91
/* MSInIRx read helper */
72
- static u32 xgene_msi_ir_read (struct xgene_msi * msi ,
73
- u32 msi_grp , u32 msir_idx )
92
+ static u32 xgene_msi_ir_read (struct xgene_msi * msi , u32 msi_grp , u32 msir_idx )
74
93
{
75
94
return readl_relaxed (msi -> msi_regs + MSI_IR0 +
76
- (msi_grp << 19 ) + (msir_idx << 16 ));
95
+ (FIELD_PREP (MSI_GROUP_MASK , msi_grp ) |
96
+ FIELD_PREP (MSI_INDEX_MASK , msir_idx )));
77
97
}
78
98
79
99
/* MSIINTn read helper */
80
100
static u32 xgene_msi_int_read (struct xgene_msi * msi , u32 msi_grp )
81
101
{
82
- return readl_relaxed (msi -> msi_regs + MSI_INT0 + (msi_grp << 16 ));
102
+ return readl_relaxed (msi -> msi_regs + MSI_INT0 +
103
+ FIELD_PREP (MSI_INTR_MASK , msi_grp ));
83
104
}
84
105
85
106
/*
86
- * With 2048 MSI vectors supported, the MSI message can be constructed using
87
- * following scheme:
88
- * - Divide into 8 256-vector groups
89
- * Group 0: 0-255
90
- * Group 1: 256-511
91
- * Group 2: 512-767
92
- * ...
93
- * Group 7: 1792-2047
94
- * - Each 256-vector group is divided into 16 16-vector groups
95
- * As an example: 16 16-vector groups for 256-vector group 0-255 is
96
- * Group 0: 0-15
97
- * Group 1: 16-32
98
- * ...
99
- * Group 15: 240-255
100
- * - The termination address of MSI vector in 256-vector group n and 16-vector
101
- * group x is the address of MSIxIRn
102
- * - The data for MSI vector in 16-vector group x is x
107
+ * In order to allow an MSI to be moved from one CPU to another without
108
+ * having to repaint both the address and the data (which cannot be done
109
+ * atomically), we statically partitions the MSI frames between CPUs. Given
110
+ * that XGene-1 has 8 CPUs, each CPU gets two frames assigned to it
111
+ *
112
+ * We adopt the convention that when an MSI is moved, it is configured to
113
+ * target the same register number in the congruent frame assigned to the
114
+ * new target CPU. This reserves a given MSI across all CPUs, and reduces
115
+ * the MSI capacity from 2048 to 256.
116
+ *
117
+ * Effectively, this amounts to:
118
+ * - hwirq[7]::cpu[2:0] is the target frame number (n in MSInIRx)
119
+ * - hwirq[6:4] is the register index in any given frame (x in MSInIRx)
120
+ * - hwirq[3:0] is the MSI data
103
121
*/
104
- static u32 hwirq_to_reg_set ( unsigned long hwirq )
122
+ static irq_hw_number_t compute_hwirq ( u8 frame , u8 index , u8 data )
105
123
{
106
- return (hwirq / (NR_HW_IRQS * IRQS_PER_IDX ));
107
- }
108
-
109
- static u32 hwirq_to_group (unsigned long hwirq )
110
- {
111
- return (hwirq % NR_HW_IRQS );
112
- }
113
-
114
- static u32 hwirq_to_msi_data (unsigned long hwirq )
115
- {
116
- return ((hwirq / NR_HW_IRQS ) % IRQS_PER_IDX );
124
+ return (FIELD_PREP (BIT (7 ), FIELD_GET (BIT (3 ), frame )) |
125
+ FIELD_PREP (MSInRx_HWIRQ_MASK , index ) |
126
+ FIELD_PREP (DATA_HWIRQ_MASK , data ));
117
127
}
118
128
119
129
static void xgene_compose_msi_msg (struct irq_data * data , struct msi_msg * msg )
120
130
{
121
131
struct xgene_msi * msi = irq_data_get_irq_chip_data (data );
122
- u32 reg_set = hwirq_to_reg_set ( data -> hwirq ) ;
123
- u32 group = hwirq_to_group ( data -> hwirq ) ;
124
- u64 target_addr = msi -> msi_addr + ((( 8 * group ) + reg_set ) << 16 ) ;
132
+ u64 target_addr ;
133
+ u32 frame , msir ;
134
+ int cpu ;
125
135
126
- msg -> address_hi = upper_32_bits (target_addr );
127
- msg -> address_lo = lower_32_bits (target_addr );
128
- msg -> data = hwirq_to_msi_data (data -> hwirq );
129
- }
136
+ cpu = cpumask_first (irq_data_get_effective_affinity_mask (data ));
137
+ msir = FIELD_GET (MSInRx_HWIRQ_MASK , data -> hwirq );
138
+ frame = FIELD_PREP (BIT (3 ), FIELD_GET (BIT (7 ), data -> hwirq )) | cpu ;
130
139
131
- /*
132
- * X-Gene v1 only has 16 MSI GIC IRQs for 2048 MSI vectors. To maintain
133
- * the expected behaviour of .set_affinity for each MSI interrupt, the 16
134
- * MSI GIC IRQs are statically allocated to 8 X-Gene v1 cores (2 GIC IRQs
135
- * for each core). The MSI vector is moved from 1 MSI GIC IRQ to another
136
- * MSI GIC IRQ to steer its MSI interrupt to correct X-Gene v1 core. As a
137
- * consequence, the total MSI vectors that X-Gene v1 supports will be
138
- * reduced to 256 (2048/8) vectors.
139
- */
140
- static int hwirq_to_cpu (unsigned long hwirq )
141
- {
142
- return (hwirq % num_possible_cpus ());
143
- }
140
+ target_addr = msi -> msi_addr ;
141
+ target_addr += (FIELD_PREP (MSI_GROUP_MASK , frame ) |
142
+ FIELD_PREP (MSI_INTR_MASK , msir ));
144
143
145
- static unsigned long hwirq_to_canonical_hwirq ( unsigned long hwirq )
146
- {
147
- return ( hwirq - hwirq_to_cpu ( hwirq ) );
144
+ msg -> address_hi = upper_32_bits ( target_addr );
145
+ msg -> address_lo = lower_32_bits ( target_addr );
146
+ msg -> data = FIELD_GET ( DATA_HWIRQ_MASK , data -> hwirq );
148
147
}
149
148
150
149
static int xgene_msi_set_affinity (struct irq_data * irqdata ,
151
150
const struct cpumask * mask , bool force )
152
151
{
153
152
int target_cpu = cpumask_first (mask );
154
- int curr_cpu ;
155
-
156
- curr_cpu = hwirq_to_cpu (irqdata -> hwirq );
157
- if (curr_cpu == target_cpu )
158
- return IRQ_SET_MASK_OK_DONE ;
159
153
160
- /* Update MSI number to target the new CPU */
161
- irqdata -> hwirq = hwirq_to_canonical_hwirq (irqdata -> hwirq ) + target_cpu ;
154
+ irq_data_update_effective_affinity (irqdata , cpumask_of (target_cpu ));
162
155
156
+ /* Force the core code to regenerate the message */
163
157
return IRQ_SET_MASK_OK ;
164
158
}
165
159
@@ -173,23 +167,20 @@ static int xgene_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
173
167
unsigned int nr_irqs , void * args )
174
168
{
175
169
struct xgene_msi * msi = domain -> host_data ;
176
- int msi_irq ;
170
+ irq_hw_number_t hwirq ;
177
171
178
172
mutex_lock (& msi -> bitmap_lock );
179
173
180
- msi_irq = bitmap_find_next_zero_area (msi -> bitmap , NR_MSI_VEC , 0 ,
181
- num_possible_cpus (), 0 );
182
- if (msi_irq < NR_MSI_VEC )
183
- bitmap_set (msi -> bitmap , msi_irq , num_possible_cpus ());
184
- else
185
- msi_irq = - ENOSPC ;
174
+ hwirq = find_first_zero_bit (msi -> bitmap , NR_MSI_VEC );
175
+ if (hwirq < NR_MSI_VEC )
176
+ set_bit (hwirq , msi -> bitmap );
186
177
187
178
mutex_unlock (& msi -> bitmap_lock );
188
179
189
- if (msi_irq < 0 )
190
- return msi_irq ;
180
+ if (hwirq >= NR_MSI_VEC )
181
+ return - ENOSPC ;
191
182
192
- irq_domain_set_info (domain , virq , msi_irq ,
183
+ irq_domain_set_info (domain , virq , hwirq ,
193
184
& xgene_msi_bottom_irq_chip , domain -> host_data ,
194
185
handle_simple_irq , NULL , NULL );
195
186
@@ -201,12 +192,10 @@ static void xgene_irq_domain_free(struct irq_domain *domain,
201
192
{
202
193
struct irq_data * d = irq_domain_get_irq_data (domain , virq );
203
194
struct xgene_msi * msi = irq_data_get_irq_chip_data (d );
204
- u32 hwirq ;
205
195
206
196
mutex_lock (& msi -> bitmap_lock );
207
197
208
- hwirq = hwirq_to_canonical_hwirq (d -> hwirq );
209
- bitmap_clear (msi -> bitmap , hwirq , num_possible_cpus ());
198
+ clear_bit (d -> hwirq , msi -> bitmap );
210
199
211
200
mutex_unlock (& msi -> bitmap_lock );
212
201
@@ -263,55 +252,30 @@ static void xgene_msi_isr(struct irq_desc *desc)
263
252
unsigned int * irqp = irq_desc_get_handler_data (desc );
264
253
struct irq_chip * chip = irq_desc_get_chip (desc );
265
254
struct xgene_msi * xgene_msi = xgene_msi_ctrl ;
266
- int msir_index , msir_val , hw_irq , ret ;
267
- u32 intr_index , grp_select , msi_grp ;
255
+ unsigned long grp_pending ;
256
+ int msir_idx ;
257
+ u32 msi_grp ;
268
258
269
259
chained_irq_enter (chip , desc );
270
260
271
261
msi_grp = irqp - xgene_msi -> gic_irq ;
272
262
273
- /*
274
- * MSIINTn (n is 0..F) indicates if there is a pending MSI interrupt
275
- * If bit x of this register is set (x is 0..7), one or more interrupts
276
- * corresponding to MSInIRx is set.
277
- */
278
- grp_select = xgene_msi_int_read (xgene_msi , msi_grp );
279
- while (grp_select ) {
280
- msir_index = ffs (grp_select ) - 1 ;
281
- /*
282
- * Calculate MSInIRx address to read to check for interrupts
283
- * (refer to termination address and data assignment
284
- * described in xgene_compose_msi_msg() )
285
- */
286
- msir_val = xgene_msi_ir_read (xgene_msi , msi_grp , msir_index );
287
- while (msir_val ) {
288
- intr_index = ffs (msir_val ) - 1 ;
289
- /*
290
- * Calculate MSI vector number (refer to the termination
291
- * address and data assignment described in
292
- * xgene_compose_msi_msg function)
293
- */
294
- hw_irq = (((msir_index * IRQS_PER_IDX ) + intr_index ) *
295
- NR_HW_IRQS ) + msi_grp ;
296
- /*
297
- * As we have multiple hw_irq that maps to single MSI,
298
- * always look up the virq using the hw_irq as seen from
299
- * CPU0
300
- */
301
- hw_irq = hwirq_to_canonical_hwirq (hw_irq );
302
- ret = generic_handle_domain_irq (xgene_msi -> inner_domain , hw_irq );
263
+ grp_pending = xgene_msi_int_read (xgene_msi , msi_grp );
264
+
265
+ for_each_set_bit (msir_idx , & grp_pending , IDX_PER_GROUP ) {
266
+ unsigned long msir ;
267
+ int intr_idx ;
268
+
269
+ msir = xgene_msi_ir_read (xgene_msi , msi_grp , msir_idx );
270
+
271
+ for_each_set_bit (intr_idx , & msir , IRQS_PER_IDX ) {
272
+ irq_hw_number_t hwirq ;
273
+ int ret ;
274
+
275
+ hwirq = compute_hwirq (msi_grp , msir_idx , intr_idx );
276
+ ret = generic_handle_domain_irq (xgene_msi -> inner_domain ,
277
+ hwirq );
303
278
WARN_ON_ONCE (ret );
304
- msir_val &= ~(1 << intr_index );
305
- }
306
- grp_select &= ~(1 << msir_index );
307
-
308
- if (!grp_select ) {
309
- /*
310
- * We handled all interrupts happened in this group,
311
- * resample this group MSI_INTx register in case
312
- * something else has been made pending in the meantime
313
- */
314
- grp_select = xgene_msi_int_read (xgene_msi , msi_grp );
315
279
}
316
280
}
317
281
0 commit comments