44 *
55 * Copyright (C) 2015 ARM Limited, All Rights Reserved.
66 * Author: Marc Zyngier <[email protected] > 7+ * Copyright (C) 2022 Linutronix GmbH
78 */
89
910#include <linux/device.h>
10- #include <linux/idr.h>
11- #include <linux/irq.h>
1211#include <linux/irqdomain.h>
1312#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 */
34713
34814/*
34915 * 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)
35723 cb (irq_data_get_msi_desc (d ), msg );
35824}
35925
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 )
36127{
36228 arg -> desc = desc ;
36329 arg -> hwirq = desc -> msi_index ;
@@ -373,7 +39,7 @@ static const struct msi_domain_template platform_msi_template = {
37339 },
37440
37541 .ops = {
376- .set_desc = platform_msi_set_desc_byindex ,
42+ .set_desc = platform_msi_set_desc ,
37743 },
37844
37945 .info = {
@@ -408,10 +74,6 @@ int platform_device_msi_init_and_alloc_irqs(struct device *dev, unsigned int nve
40874 if (!domain || !write_msi_msg )
40975 return - EINVAL ;
41076
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-
41577 /*
41678 * @write_msi_msg is stored in the resulting msi_domain_info::data.
41779 * The underlying domain creation mechanism will assign that
@@ -432,12 +94,6 @@ EXPORT_SYMBOL_GPL(platform_device_msi_init_and_alloc_irqs);
43294 */
43395void platform_device_msi_free_irqs_all (struct device * dev )
43496{
435- struct irq_domain * domain = dev -> msi .domain ;
436-
43797 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 );
44298}
44399EXPORT_SYMBOL_GPL (platform_device_msi_free_irqs_all );
0 commit comments