4
4
*
5
5
* Copyright (C) 2015 ARM Limited, All Rights Reserved.
6
6
* Author: Marc Zyngier <marc.zyngier@arm.com>
7
+ * Copyright (C) 2022 Linutronix GmbH
7
8
*/
8
9
9
10
#include <linux/device.h>
10
- #include <linux/idr.h>
11
- #include <linux/irq.h>
12
11
#include <linux/irqdomain.h>
13
12
#include <linux/msi.h>
14
- #include <linux/slab.h>
15
-
16
- /* Begin of removal area. Once everything is converted over. Cleanup the includes too! */
17
-
18
- #define DEV_ID_SHIFT 21
19
- #define MAX_DEV_MSIS (1 << (32 - DEV_ID_SHIFT))
20
-
21
- /*
22
- * Internal data structure containing a (made up, but unique) devid
23
- * and the callback to write the MSI message.
24
- */
25
- struct platform_msi_priv_data {
26
- struct device * dev ;
27
- void * host_data ;
28
- msi_alloc_info_t arg ;
29
- irq_write_msi_msg_t write_msg ;
30
- int devid ;
31
- };
32
-
33
- /* The devid allocator */
34
- static DEFINE_IDA (platform_msi_devid_ida );
35
-
36
- #ifdef GENERIC_MSI_DOMAIN_OPS
37
- /*
38
- * Convert an msi_desc to a globaly unique identifier (per-device
39
- * devid + msi_desc position in the msi_list).
40
- */
41
- static irq_hw_number_t platform_msi_calc_hwirq (struct msi_desc * desc )
42
- {
43
- u32 devid = desc -> dev -> msi .data -> platform_data -> devid ;
44
-
45
- return (devid << (32 - DEV_ID_SHIFT )) | desc -> msi_index ;
46
- }
47
-
48
- static void platform_msi_set_desc (msi_alloc_info_t * arg , struct msi_desc * desc )
49
- {
50
- arg -> desc = desc ;
51
- arg -> hwirq = platform_msi_calc_hwirq (desc );
52
- }
53
-
54
- static int platform_msi_init (struct irq_domain * domain ,
55
- struct msi_domain_info * info ,
56
- unsigned int virq , irq_hw_number_t hwirq ,
57
- msi_alloc_info_t * arg )
58
- {
59
- return irq_domain_set_hwirq_and_chip (domain , virq , hwirq ,
60
- info -> chip , info -> chip_data );
61
- }
62
-
63
- static void platform_msi_set_proxy_dev (msi_alloc_info_t * arg )
64
- {
65
- arg -> flags |= MSI_ALLOC_FLAGS_PROXY_DEVICE ;
66
- }
67
- #else
68
- #define platform_msi_set_desc NULL
69
- #define platform_msi_init NULL
70
- #define platform_msi_set_proxy_dev (x ) do {} while(0)
71
- #endif
72
-
73
- static void platform_msi_update_dom_ops (struct msi_domain_info * info )
74
- {
75
- struct msi_domain_ops * ops = info -> ops ;
76
-
77
- BUG_ON (!ops );
78
-
79
- if (ops -> msi_init == NULL )
80
- ops -> msi_init = platform_msi_init ;
81
- if (ops -> set_desc == NULL )
82
- ops -> set_desc = platform_msi_set_desc ;
83
- }
84
-
85
- static void platform_msi_write_msg (struct irq_data * data , struct msi_msg * msg )
86
- {
87
- struct msi_desc * desc = irq_data_get_msi_desc (data );
88
-
89
- desc -> dev -> msi .data -> platform_data -> write_msg (desc , msg );
90
- }
91
-
92
- static void platform_msi_update_chip_ops (struct msi_domain_info * info )
93
- {
94
- struct irq_chip * chip = info -> chip ;
95
-
96
- BUG_ON (!chip );
97
- if (!chip -> irq_mask )
98
- chip -> irq_mask = irq_chip_mask_parent ;
99
- if (!chip -> irq_unmask )
100
- chip -> irq_unmask = irq_chip_unmask_parent ;
101
- if (!chip -> irq_eoi )
102
- chip -> irq_eoi = irq_chip_eoi_parent ;
103
- if (!chip -> irq_set_affinity )
104
- chip -> irq_set_affinity = msi_domain_set_affinity ;
105
- if (!chip -> irq_write_msi_msg )
106
- chip -> irq_write_msi_msg = platform_msi_write_msg ;
107
- if (WARN_ON ((info -> flags & MSI_FLAG_LEVEL_CAPABLE ) &&
108
- !(chip -> flags & IRQCHIP_SUPPORTS_LEVEL_MSI )))
109
- info -> flags &= ~MSI_FLAG_LEVEL_CAPABLE ;
110
- }
111
-
112
- /**
113
- * platform_msi_create_irq_domain - Create a platform MSI interrupt domain
114
- * @fwnode: Optional fwnode of the interrupt controller
115
- * @info: MSI domain info
116
- * @parent: Parent irq domain
117
- *
118
- * Updates the domain and chip ops and creates a platform MSI
119
- * interrupt domain.
120
- *
121
- * Returns:
122
- * A domain pointer or NULL in case of failure.
123
- */
124
- struct irq_domain * platform_msi_create_irq_domain (struct fwnode_handle * fwnode ,
125
- struct msi_domain_info * info ,
126
- struct irq_domain * parent )
127
- {
128
- struct irq_domain * domain ;
129
-
130
- if (info -> flags & MSI_FLAG_USE_DEF_DOM_OPS )
131
- platform_msi_update_dom_ops (info );
132
- if (info -> flags & MSI_FLAG_USE_DEF_CHIP_OPS )
133
- platform_msi_update_chip_ops (info );
134
- info -> flags |= MSI_FLAG_DEV_SYSFS | MSI_FLAG_ALLOC_SIMPLE_MSI_DESCS |
135
- MSI_FLAG_FREE_MSI_DESCS ;
136
-
137
- domain = msi_create_irq_domain (fwnode , info , parent );
138
- if (domain )
139
- irq_domain_update_bus_token (domain , DOMAIN_BUS_PLATFORM_MSI );
140
-
141
- return domain ;
142
- }
143
- EXPORT_SYMBOL_GPL (platform_msi_create_irq_domain );
144
-
145
- static int platform_msi_alloc_priv_data (struct device * dev , unsigned int nvec ,
146
- irq_write_msi_msg_t write_msi_msg )
147
- {
148
- struct platform_msi_priv_data * datap ;
149
- int err ;
150
-
151
- /*
152
- * Limit the number of interrupts to 2048 per device. Should we
153
- * need to bump this up, DEV_ID_SHIFT should be adjusted
154
- * accordingly (which would impact the max number of MSI
155
- * capable devices).
156
- */
157
- if (!dev -> msi .domain || !write_msi_msg || !nvec || nvec > MAX_DEV_MSIS )
158
- return - EINVAL ;
159
-
160
- if (dev -> msi .domain -> bus_token != DOMAIN_BUS_PLATFORM_MSI ) {
161
- dev_err (dev , "Incompatible msi_domain, giving up\n" );
162
- return - EINVAL ;
163
- }
164
-
165
- err = msi_setup_device_data (dev );
166
- if (err )
167
- return err ;
168
-
169
- /* Already initialized? */
170
- if (dev -> msi .data -> platform_data )
171
- return - EBUSY ;
172
-
173
- datap = kzalloc (sizeof (* datap ), GFP_KERNEL );
174
- if (!datap )
175
- return - ENOMEM ;
176
-
177
- datap -> devid = ida_alloc_max (& platform_msi_devid_ida ,
178
- (1 << DEV_ID_SHIFT ) - 1 , GFP_KERNEL );
179
- if (datap -> devid < 0 ) {
180
- err = datap -> devid ;
181
- kfree (datap );
182
- return err ;
183
- }
184
-
185
- datap -> write_msg = write_msi_msg ;
186
- datap -> dev = dev ;
187
- dev -> msi .data -> platform_data = datap ;
188
- return 0 ;
189
- }
190
-
191
- static void platform_msi_free_priv_data (struct device * dev )
192
- {
193
- struct platform_msi_priv_data * data = dev -> msi .data -> platform_data ;
194
-
195
- dev -> msi .data -> platform_data = NULL ;
196
- ida_free (& platform_msi_devid_ida , data -> devid );
197
- kfree (data );
198
- }
199
-
200
- /**
201
- * platform_msi_domain_alloc_irqs - Allocate MSI interrupts for @dev
202
- * @dev: The device for which to allocate interrupts
203
- * @nvec: The number of interrupts to allocate
204
- * @write_msi_msg: Callback to write an interrupt message for @dev
205
- *
206
- * Returns:
207
- * Zero for success, or an error code in case of failure
208
- */
209
- static int platform_msi_domain_alloc_irqs (struct device * dev , unsigned int nvec ,
210
- irq_write_msi_msg_t write_msi_msg )
211
- {
212
- int err ;
213
-
214
- err = platform_msi_alloc_priv_data (dev , nvec , write_msi_msg );
215
- if (err )
216
- return err ;
217
-
218
- err = msi_domain_alloc_irqs_range (dev , MSI_DEFAULT_DOMAIN , 0 , nvec - 1 );
219
- if (err )
220
- platform_msi_free_priv_data (dev );
221
-
222
- return err ;
223
- }
224
-
225
- /**
226
- * platform_msi_get_host_data - Query the private data associated with
227
- * a platform-msi domain
228
- * @domain: The platform-msi domain
229
- *
230
- * Return: The private data provided when calling
231
- * platform_msi_create_device_domain().
232
- */
233
- void * platform_msi_get_host_data (struct irq_domain * domain )
234
- {
235
- struct platform_msi_priv_data * data = domain -> host_data ;
236
-
237
- return data -> host_data ;
238
- }
239
-
240
- static struct lock_class_key platform_device_msi_lock_class ;
241
-
242
- /**
243
- * __platform_msi_create_device_domain - Create a platform-msi device domain
244
- *
245
- * @dev: The device generating the MSIs
246
- * @nvec: The number of MSIs that need to be allocated
247
- * @is_tree: flag to indicate tree hierarchy
248
- * @write_msi_msg: Callback to write an interrupt message for @dev
249
- * @ops: The hierarchy domain operations to use
250
- * @host_data: Private data associated to this domain
251
- *
252
- * Return: An irqdomain for @nvec interrupts on success, NULL in case of error.
253
- *
254
- * This is for interrupt domains which stack on a platform-msi domain
255
- * created by platform_msi_create_irq_domain(). @dev->msi.domain points to
256
- * that platform-msi domain which is the parent for the new domain.
257
- */
258
- struct irq_domain *
259
- __platform_msi_create_device_domain (struct device * dev ,
260
- unsigned int nvec ,
261
- bool is_tree ,
262
- irq_write_msi_msg_t write_msi_msg ,
263
- const struct irq_domain_ops * ops ,
264
- void * host_data )
265
- {
266
- struct platform_msi_priv_data * data ;
267
- struct irq_domain * domain ;
268
- int err ;
269
-
270
- err = platform_msi_alloc_priv_data (dev , nvec , write_msi_msg );
271
- if (err )
272
- return NULL ;
273
-
274
- /*
275
- * Use a separate lock class for the MSI descriptor mutex on
276
- * platform MSI device domains because the descriptor mutex nests
277
- * into the domain mutex. See alloc/free below.
278
- */
279
- lockdep_set_class (& dev -> msi .data -> mutex , & platform_device_msi_lock_class );
280
-
281
- data = dev -> msi .data -> platform_data ;
282
- data -> host_data = host_data ;
283
- domain = irq_domain_create_hierarchy (dev -> msi .domain , 0 ,
284
- is_tree ? 0 : nvec ,
285
- dev -> fwnode , ops , data );
286
- if (!domain )
287
- goto free_priv ;
288
-
289
- platform_msi_set_proxy_dev (& data -> arg );
290
- err = msi_domain_prepare_irqs (domain -> parent , dev , nvec , & data -> arg );
291
- if (err )
292
- goto free_domain ;
293
-
294
- return domain ;
295
-
296
- free_domain :
297
- irq_domain_remove (domain );
298
- free_priv :
299
- platform_msi_free_priv_data (dev );
300
- return NULL ;
301
- }
302
-
303
- /**
304
- * platform_msi_device_domain_free - Free interrupts associated with a platform-msi
305
- * device domain
306
- *
307
- * @domain: The platform-msi device domain
308
- * @virq: The base irq from which to perform the free operation
309
- * @nr_irqs: How many interrupts to free from @virq
310
- */
311
- void platform_msi_device_domain_free (struct irq_domain * domain , unsigned int virq ,
312
- unsigned int nr_irqs )
313
- {
314
- struct platform_msi_priv_data * data = domain -> host_data ;
315
-
316
- msi_lock_descs (data -> dev );
317
- msi_domain_depopulate_descs (data -> dev , virq , nr_irqs );
318
- irq_domain_free_irqs_common (domain , virq , nr_irqs );
319
- msi_free_msi_descs_range (data -> dev , virq , virq + nr_irqs - 1 );
320
- msi_unlock_descs (data -> dev );
321
- }
322
-
323
- /**
324
- * platform_msi_device_domain_alloc - Allocate interrupts associated with
325
- * a platform-msi device domain
326
- *
327
- * @domain: The platform-msi device domain
328
- * @virq: The base irq from which to perform the allocate operation
329
- * @nr_irqs: How many interrupts to allocate from @virq
330
- *
331
- * Return 0 on success, or an error code on failure. Must be called
332
- * with irq_domain_mutex held (which can only be done as part of a
333
- * top-level interrupt allocation).
334
- */
335
- int platform_msi_device_domain_alloc (struct irq_domain * domain , unsigned int virq ,
336
- unsigned int nr_irqs )
337
- {
338
- struct platform_msi_priv_data * data = domain -> host_data ;
339
- struct device * dev = data -> dev ;
340
-
341
- return msi_domain_populate_irqs (domain -> parent , dev , virq , nr_irqs , & data -> arg );
342
- }
343
-
344
- /* End of removal area */
345
-
346
- /* Real per device domain interfaces */
347
13
348
14
/*
349
15
* This indirection can go when platform_device_msi_init_and_alloc_irqs()
@@ -357,7 +23,7 @@ static void platform_msi_write_msi_msg(struct irq_data *d, struct msi_msg *msg)
357
23
cb (irq_data_get_msi_desc (d ), msg );
358
24
}
359
25
360
- static void platform_msi_set_desc_byindex (msi_alloc_info_t * arg , struct msi_desc * desc )
26
+ static void platform_msi_set_desc (msi_alloc_info_t * arg , struct msi_desc * desc )
361
27
{
362
28
arg -> desc = desc ;
363
29
arg -> hwirq = desc -> msi_index ;
@@ -373,7 +39,7 @@ static const struct msi_domain_template platform_msi_template = {
373
39
},
374
40
375
41
.ops = {
376
- .set_desc = platform_msi_set_desc_byindex ,
42
+ .set_desc = platform_msi_set_desc ,
377
43
},
378
44
379
45
.info = {
@@ -408,10 +74,6 @@ int platform_device_msi_init_and_alloc_irqs(struct device *dev, unsigned int nve
408
74
if (!domain || !write_msi_msg )
409
75
return - EINVAL ;
410
76
411
- /* Migration support. Will go away once everything is converted */
412
- if (!irq_domain_is_msi_parent (domain ))
413
- return platform_msi_domain_alloc_irqs (dev , nvec , write_msi_msg );
414
-
415
77
/*
416
78
* @write_msi_msg is stored in the resulting msi_domain_info::data.
417
79
* The underlying domain creation mechanism will assign that
@@ -432,12 +94,6 @@ EXPORT_SYMBOL_GPL(platform_device_msi_init_and_alloc_irqs);
432
94
*/
433
95
void platform_device_msi_free_irqs_all (struct device * dev )
434
96
{
435
- struct irq_domain * domain = dev -> msi .domain ;
436
-
437
97
msi_domain_free_irqs_all (dev , MSI_DEFAULT_DOMAIN );
438
-
439
- /* Migration support. Will go away once everything is converted */
440
- if (!irq_domain_is_msi_parent (domain ))
441
- platform_msi_free_priv_data (dev );
442
98
}
443
99
EXPORT_SYMBOL_GPL (platform_device_msi_free_irqs_all );
0 commit comments