~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/virt/lib/irqbypass.c

Version: ~ [ linux-6.12-rc7 ] ~ [ linux-6.11.7 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.60 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.116 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.171 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.229 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.285 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.323 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.12 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

Diff markup

Differences between /virt/lib/irqbypass.c (Version linux-6.12-rc7) and /virt/lib/irqbypass.c (Version linux-6.10.14)


  1 // SPDX-License-Identifier: GPL-2.0-only            1 // SPDX-License-Identifier: GPL-2.0-only
  2 /*                                                  2 /*
  3  * IRQ offload/bypass manager                       3  * IRQ offload/bypass manager
  4  *                                                  4  *
  5  * Copyright (C) 2015 Red Hat, Inc.                 5  * Copyright (C) 2015 Red Hat, Inc.
  6  * Copyright (c) 2015 Linaro Ltd.                   6  * Copyright (c) 2015 Linaro Ltd.
  7  *                                                  7  *
  8  * Various virtualization hardware acceleratio      8  * Various virtualization hardware acceleration techniques allow bypassing or
  9  * offloading interrupts received from devices      9  * offloading interrupts received from devices around the host kernel.  Posted
 10  * Interrupts on Intel VT-d systems can allow      10  * Interrupts on Intel VT-d systems can allow interrupts to be received
 11  * directly by a virtual machine.  ARM IRQ For     11  * directly by a virtual machine.  ARM IRQ Forwarding allows forwarded physical
 12  * interrupts to be directly deactivated by th     12  * interrupts to be directly deactivated by the guest.  This manager allows
 13  * interrupt producers and consumers to find e     13  * interrupt producers and consumers to find each other to enable this sort of
 14  * bypass.                                         14  * bypass.
 15  */                                                15  */
 16                                                    16 
 17 #include <linux/irqbypass.h>                       17 #include <linux/irqbypass.h>
 18 #include <linux/list.h>                            18 #include <linux/list.h>
 19 #include <linux/module.h>                          19 #include <linux/module.h>
 20 #include <linux/mutex.h>                           20 #include <linux/mutex.h>
 21                                                    21 
 22 MODULE_LICENSE("GPL v2");                          22 MODULE_LICENSE("GPL v2");
 23 MODULE_DESCRIPTION("IRQ bypass manager utility     23 MODULE_DESCRIPTION("IRQ bypass manager utility module");
 24                                                    24 
 25 static LIST_HEAD(producers);                       25 static LIST_HEAD(producers);
 26 static LIST_HEAD(consumers);                       26 static LIST_HEAD(consumers);
 27 static DEFINE_MUTEX(lock);                         27 static DEFINE_MUTEX(lock);
 28                                                    28 
 29 /* @lock must be held when calling connect */      29 /* @lock must be held when calling connect */
 30 static int __connect(struct irq_bypass_produce     30 static int __connect(struct irq_bypass_producer *prod,
 31                      struct irq_bypass_consume     31                      struct irq_bypass_consumer *cons)
 32 {                                                  32 {
 33         int ret = 0;                               33         int ret = 0;
 34                                                    34 
 35         if (prod->stop)                            35         if (prod->stop)
 36                 prod->stop(prod);                  36                 prod->stop(prod);
 37         if (cons->stop)                            37         if (cons->stop)
 38                 cons->stop(cons);                  38                 cons->stop(cons);
 39                                                    39 
 40         if (prod->add_consumer)                    40         if (prod->add_consumer)
 41                 ret = prod->add_consumer(prod,     41                 ret = prod->add_consumer(prod, cons);
 42                                                    42 
 43         if (!ret) {                                43         if (!ret) {
 44                 ret = cons->add_producer(cons,     44                 ret = cons->add_producer(cons, prod);
 45                 if (ret && prod->del_consumer)     45                 if (ret && prod->del_consumer)
 46                         prod->del_consumer(pro     46                         prod->del_consumer(prod, cons);
 47         }                                          47         }
 48                                                    48 
 49         if (cons->start)                           49         if (cons->start)
 50                 cons->start(cons);                 50                 cons->start(cons);
 51         if (prod->start)                           51         if (prod->start)
 52                 prod->start(prod);                 52                 prod->start(prod);
 53                                                    53 
 54         return ret;                                54         return ret;
 55 }                                                  55 }
 56                                                    56 
 57 /* @lock must be held when calling disconnect      57 /* @lock must be held when calling disconnect */
 58 static void __disconnect(struct irq_bypass_pro     58 static void __disconnect(struct irq_bypass_producer *prod,
 59                          struct irq_bypass_con     59                          struct irq_bypass_consumer *cons)
 60 {                                                  60 {
 61         if (prod->stop)                            61         if (prod->stop)
 62                 prod->stop(prod);                  62                 prod->stop(prod);
 63         if (cons->stop)                            63         if (cons->stop)
 64                 cons->stop(cons);                  64                 cons->stop(cons);
 65                                                    65 
 66         cons->del_producer(cons, prod);            66         cons->del_producer(cons, prod);
 67                                                    67 
 68         if (prod->del_consumer)                    68         if (prod->del_consumer)
 69                 prod->del_consumer(prod, cons)     69                 prod->del_consumer(prod, cons);
 70                                                    70 
 71         if (cons->start)                           71         if (cons->start)
 72                 cons->start(cons);                 72                 cons->start(cons);
 73         if (prod->start)                           73         if (prod->start)
 74                 prod->start(prod);                 74                 prod->start(prod);
 75 }                                                  75 }
 76                                                    76 
 77 /**                                                77 /**
 78  * irq_bypass_register_producer - register IRQ     78  * irq_bypass_register_producer - register IRQ bypass producer
 79  * @producer: pointer to producer structure        79  * @producer: pointer to producer structure
 80  *                                                 80  *
 81  * Add the provided IRQ producer to the list o     81  * Add the provided IRQ producer to the list of producers and connect
 82  * with any matching token found on the IRQ co     82  * with any matching token found on the IRQ consumers list.
 83  */                                                83  */
 84 int irq_bypass_register_producer(struct irq_by     84 int irq_bypass_register_producer(struct irq_bypass_producer *producer)
 85 {                                                  85 {
 86         struct irq_bypass_producer *tmp;           86         struct irq_bypass_producer *tmp;
 87         struct irq_bypass_consumer *consumer;      87         struct irq_bypass_consumer *consumer;
 88         int ret;                                   88         int ret;
 89                                                    89 
 90         if (!producer->token)                      90         if (!producer->token)
 91                 return -EINVAL;                    91                 return -EINVAL;
 92                                                    92 
 93         might_sleep();                             93         might_sleep();
 94                                                    94 
 95         if (!try_module_get(THIS_MODULE))          95         if (!try_module_get(THIS_MODULE))
 96                 return -ENODEV;                    96                 return -ENODEV;
 97                                                    97 
 98         mutex_lock(&lock);                         98         mutex_lock(&lock);
 99                                                    99 
100         list_for_each_entry(tmp, &producers, n    100         list_for_each_entry(tmp, &producers, node) {
101                 if (tmp->token == producer->to    101                 if (tmp->token == producer->token) {
102                         ret = -EBUSY;             102                         ret = -EBUSY;
103                         goto out_err;             103                         goto out_err;
104                 }                                 104                 }
105         }                                         105         }
106                                                   106 
107         list_for_each_entry(consumer, &consume    107         list_for_each_entry(consumer, &consumers, node) {
108                 if (consumer->token == produce    108                 if (consumer->token == producer->token) {
109                         ret = __connect(produc    109                         ret = __connect(producer, consumer);
110                         if (ret)                  110                         if (ret)
111                                 goto out_err;     111                                 goto out_err;
112                         break;                    112                         break;
113                 }                                 113                 }
114         }                                         114         }
115                                                   115 
116         list_add(&producer->node, &producers);    116         list_add(&producer->node, &producers);
117                                                   117 
118         mutex_unlock(&lock);                      118         mutex_unlock(&lock);
119                                                   119 
120         return 0;                                 120         return 0;
121 out_err:                                          121 out_err:
122         mutex_unlock(&lock);                      122         mutex_unlock(&lock);
123         module_put(THIS_MODULE);                  123         module_put(THIS_MODULE);
124         return ret;                               124         return ret;
125 }                                                 125 }
126 EXPORT_SYMBOL_GPL(irq_bypass_register_producer    126 EXPORT_SYMBOL_GPL(irq_bypass_register_producer);
127                                                   127 
128 /**                                               128 /**
129  * irq_bypass_unregister_producer - unregister    129  * irq_bypass_unregister_producer - unregister IRQ bypass producer
130  * @producer: pointer to producer structure       130  * @producer: pointer to producer structure
131  *                                                131  *
132  * Remove a previously registered IRQ producer    132  * Remove a previously registered IRQ producer from the list of producers
133  * and disconnect it from any connected IRQ co    133  * and disconnect it from any connected IRQ consumer.
134  */                                               134  */
135 void irq_bypass_unregister_producer(struct irq    135 void irq_bypass_unregister_producer(struct irq_bypass_producer *producer)
136 {                                                 136 {
137         struct irq_bypass_producer *tmp;          137         struct irq_bypass_producer *tmp;
138         struct irq_bypass_consumer *consumer;     138         struct irq_bypass_consumer *consumer;
139                                                   139 
140         if (!producer->token)                     140         if (!producer->token)
141                 return;                           141                 return;
142                                                   142 
143         might_sleep();                            143         might_sleep();
144                                                   144 
145         if (!try_module_get(THIS_MODULE))         145         if (!try_module_get(THIS_MODULE))
146                 return; /* nothing in the list    146                 return; /* nothing in the list anyway */
147                                                   147 
148         mutex_lock(&lock);                        148         mutex_lock(&lock);
149                                                   149 
150         list_for_each_entry(tmp, &producers, n    150         list_for_each_entry(tmp, &producers, node) {
151                 if (tmp->token != producer->to    151                 if (tmp->token != producer->token)
152                         continue;                 152                         continue;
153                                                   153 
154                 list_for_each_entry(consumer,     154                 list_for_each_entry(consumer, &consumers, node) {
155                         if (consumer->token ==    155                         if (consumer->token == producer->token) {
156                                 __disconnect(p    156                                 __disconnect(producer, consumer);
157                                 break;            157                                 break;
158                         }                         158                         }
159                 }                                 159                 }
160                                                   160 
161                 list_del(&producer->node);        161                 list_del(&producer->node);
162                 module_put(THIS_MODULE);          162                 module_put(THIS_MODULE);
163                 break;                            163                 break;
164         }                                         164         }
165                                                   165 
166         mutex_unlock(&lock);                      166         mutex_unlock(&lock);
167                                                   167 
168         module_put(THIS_MODULE);                  168         module_put(THIS_MODULE);
169 }                                                 169 }
170 EXPORT_SYMBOL_GPL(irq_bypass_unregister_produc    170 EXPORT_SYMBOL_GPL(irq_bypass_unregister_producer);
171                                                   171 
172 /**                                               172 /**
173  * irq_bypass_register_consumer - register IRQ    173  * irq_bypass_register_consumer - register IRQ bypass consumer
174  * @consumer: pointer to consumer structure       174  * @consumer: pointer to consumer structure
175  *                                                175  *
176  * Add the provided IRQ consumer to the list o    176  * Add the provided IRQ consumer to the list of consumers and connect
177  * with any matching token found on the IRQ pr    177  * with any matching token found on the IRQ producer list.
178  */                                               178  */
179 int irq_bypass_register_consumer(struct irq_by    179 int irq_bypass_register_consumer(struct irq_bypass_consumer *consumer)
180 {                                                 180 {
181         struct irq_bypass_consumer *tmp;          181         struct irq_bypass_consumer *tmp;
182         struct irq_bypass_producer *producer;     182         struct irq_bypass_producer *producer;
183         int ret;                                  183         int ret;
184                                                   184 
185         if (!consumer->token ||                   185         if (!consumer->token ||
186             !consumer->add_producer || !consum    186             !consumer->add_producer || !consumer->del_producer)
187                 return -EINVAL;                   187                 return -EINVAL;
188                                                   188 
189         might_sleep();                            189         might_sleep();
190                                                   190 
191         if (!try_module_get(THIS_MODULE))         191         if (!try_module_get(THIS_MODULE))
192                 return -ENODEV;                   192                 return -ENODEV;
193                                                   193 
194         mutex_lock(&lock);                        194         mutex_lock(&lock);
195                                                   195 
196         list_for_each_entry(tmp, &consumers, n    196         list_for_each_entry(tmp, &consumers, node) {
197                 if (tmp->token == consumer->to    197                 if (tmp->token == consumer->token || tmp == consumer) {
198                         ret = -EBUSY;             198                         ret = -EBUSY;
199                         goto out_err;             199                         goto out_err;
200                 }                                 200                 }
201         }                                         201         }
202                                                   202 
203         list_for_each_entry(producer, &produce    203         list_for_each_entry(producer, &producers, node) {
204                 if (producer->token == consume    204                 if (producer->token == consumer->token) {
205                         ret = __connect(produc    205                         ret = __connect(producer, consumer);
206                         if (ret)                  206                         if (ret)
207                                 goto out_err;     207                                 goto out_err;
208                         break;                    208                         break;
209                 }                                 209                 }
210         }                                         210         }
211                                                   211 
212         list_add(&consumer->node, &consumers);    212         list_add(&consumer->node, &consumers);
213                                                   213 
214         mutex_unlock(&lock);                      214         mutex_unlock(&lock);
215                                                   215 
216         return 0;                                 216         return 0;
217 out_err:                                          217 out_err:
218         mutex_unlock(&lock);                      218         mutex_unlock(&lock);
219         module_put(THIS_MODULE);                  219         module_put(THIS_MODULE);
220         return ret;                               220         return ret;
221 }                                                 221 }
222 EXPORT_SYMBOL_GPL(irq_bypass_register_consumer    222 EXPORT_SYMBOL_GPL(irq_bypass_register_consumer);
223                                                   223 
224 /**                                               224 /**
225  * irq_bypass_unregister_consumer - unregister    225  * irq_bypass_unregister_consumer - unregister IRQ bypass consumer
226  * @consumer: pointer to consumer structure       226  * @consumer: pointer to consumer structure
227  *                                                227  *
228  * Remove a previously registered IRQ consumer    228  * Remove a previously registered IRQ consumer from the list of consumers
229  * and disconnect it from any connected IRQ pr    229  * and disconnect it from any connected IRQ producer.
230  */                                               230  */
231 void irq_bypass_unregister_consumer(struct irq    231 void irq_bypass_unregister_consumer(struct irq_bypass_consumer *consumer)
232 {                                                 232 {
233         struct irq_bypass_consumer *tmp;          233         struct irq_bypass_consumer *tmp;
234         struct irq_bypass_producer *producer;     234         struct irq_bypass_producer *producer;
235                                                   235 
236         if (!consumer->token)                     236         if (!consumer->token)
237                 return;                           237                 return;
238                                                   238 
239         might_sleep();                            239         might_sleep();
240                                                   240 
241         if (!try_module_get(THIS_MODULE))         241         if (!try_module_get(THIS_MODULE))
242                 return; /* nothing in the list    242                 return; /* nothing in the list anyway */
243                                                   243 
244         mutex_lock(&lock);                        244         mutex_lock(&lock);
245                                                   245 
246         list_for_each_entry(tmp, &consumers, n    246         list_for_each_entry(tmp, &consumers, node) {
247                 if (tmp != consumer)              247                 if (tmp != consumer)
248                         continue;                 248                         continue;
249                                                   249 
250                 list_for_each_entry(producer,     250                 list_for_each_entry(producer, &producers, node) {
251                         if (producer->token ==    251                         if (producer->token == consumer->token) {
252                                 __disconnect(p    252                                 __disconnect(producer, consumer);
253                                 break;            253                                 break;
254                         }                         254                         }
255                 }                                 255                 }
256                                                   256 
257                 list_del(&consumer->node);        257                 list_del(&consumer->node);
258                 module_put(THIS_MODULE);          258                 module_put(THIS_MODULE);
259                 break;                            259                 break;
260         }                                         260         }
261                                                   261 
262         mutex_unlock(&lock);                      262         mutex_unlock(&lock);
263                                                   263 
264         module_put(THIS_MODULE);                  264         module_put(THIS_MODULE);
265 }                                                 265 }
266 EXPORT_SYMBOL_GPL(irq_bypass_unregister_consum    266 EXPORT_SYMBOL_GPL(irq_bypass_unregister_consumer);
267                                                   267 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php