From: Alexander Popov <alex.popov@linux.com>
To: Marc Zyngier <marc.zyngier@arm.com>
Cc: Thomas Gleixner <tglx@linutronix.de>,
LKML <linux-kernel@vger.kernel.org>,
Alexander Popov <alex.popov@linux.com>
Subject: Re: [PATCH 1/1] irqdomain: Export __irq_domain_alloc_irqs() and irq_domain_free_irqs()
Date: Mon, 18 Jul 2016 15:34:35 +0300 [thread overview]
Message-ID: <578CCCDB.4050800@linux.com> (raw)
In-Reply-To: <20160716092218.3a2de5c7@arm.com>
On 16.07.2016 11:22, Marc Zyngier wrote:
> On Sat, 16 Jul 2016 04:33:59 +0300
> Alexander Popov <alex.popov@linux.com> wrote:
>
>> On 08.07.2016 11:34, Alexander Popov wrote:
>>> On 06.07.2016 14:17, Thomas Gleixner wrote:
>>>> On Fri, 1 Jul 2016, Alexander Popov wrote:
>>>>
>>>>> Export __irq_domain_alloc_irqs() and irq_domain_free_irqs() for being
>>>>> able to work with irq_domain hierarchy in modules.
>>>>
>>>> We usually export only when we have a proper use case which is supposed to go
>>>> into the kernel tree proper. What's yours?
...
>> Did I properly answer your question? Will you accept my patch exporting these
>> two functions?
>
> I think that without any in-tree modular users of these symbols, the
> incentive for exporting those is pretty low. I can't really say
> anything about your particular use-case, but I'd really to see some
> code before taking that kind of patch.
Thanks for your answer, Mark.
Here is the module which uses __irq_domain_alloc_irqs() and
irq_domain_free_irqs() and allows registering IRQ handlers for interrupts
injected by the hypervisor on x86_64. Large hypervisors usually emulate
an MSI-capable PCI device to do this job, but that way is inappropriate
for lightweight hypervisors.
/*
* The module is for registering IRQ handlers for interrupts injected
* by the hypervisor using Intel VT-x technology. This module targets
* x86_64 platform.
*
* It works fine if __irq_domain_alloc_irqs() and irq_domain_free_irqs()
* are exported.
*/
#include <linux/module.h>
#include <linux/irq.h>
#include <linux/irqdesc.h>
#include <linux/irqnr.h>
#include <linux/irqdomain.h>
#include <linux/interrupt.h>
#include <asm/hw_irq.h>
#include <asm/irqdomain.h>
#define PARAVIRT_IRQS_N 10
struct irq_domain *paravirq_domain = NULL;
static int paravirq_irqbase = -EINVAL;
static int paravirq_irqs[PARAVIRT_IRQS_N] =
{[0 ... PARAVIRT_IRQS_N - 1] = -EINVAL};
static irqreturn_t paravirq_irq_handler(int irq, void *cookie)
{
printk("\tparavirq_irq_handler: virq %d\n", irq);
/* ... some job ... */
return IRQ_HANDLED;
}
static void paravirq_chip_irq_mask(struct irq_data *data)
{
printk("\tparavirq_chip_irq_mask\n");
/* ... tell the hypervisor not to inject the interrupt ... */
}
static void paravirq_chip_irq_unmask(struct irq_data *data)
{
printk("\tparavirq_chip_irq_UNmask\n");
/* ... allow the hypervisor to inject the interrupt ... */
}
static void paravirq_chip_ack(struct irq_data *data)
{
data = data->parent_data;
data->chip->irq_ack(data);
}
static struct irq_chip paravirq_chip __read_mostly = {
.name = "PARAVIRQ",
.irq_mask = paravirq_chip_irq_mask,
.irq_unmask = paravirq_chip_irq_unmask,
.irq_ack = paravirq_chip_ack,
};
static int paravirq_domain_alloc(struct irq_domain *domain,
unsigned int virq, unsigned int nr_irqs, void *arg)
{
int ret = 0;
unsigned int i = 0;
unsigned int irq = 0;
printk("\tparavirq_domain_alloc: virq %u, nr_irqs %u, arg 0x%p\n",
virq, nr_irqs, arg);
for (i = 0; i < nr_irqs; i++) {
irq = virq + i;
ret = irq_domain_set_hwirq_and_chip(domain,
irq, i, ¶virq_chip, NULL);
if (ret) {
printk("\t\tsetting chip, hwirq for %d failed\n", irq);
return ret;
}
__irq_set_handler(irq, handle_edge_irq, 0, "edge");
}
return 0;
}
static void paravirq_domain_free(struct irq_domain *domain, unsigned int virq,
unsigned int nr_irqs)
{
int ret = 0;
unsigned int i = 0;
unsigned int irq = 0;
printk("\tparavirq_domain_free: virq %u, nr_irqs %u\n", virq, nr_irqs);
for (i = 0; i < nr_irqs; i++) {
irq = virq + i;
ret = irq_set_chip(irq, NULL);
if (ret)
printk("\t\tunsetting chip for %d failed\n", irq);
}
}
const struct irq_domain_ops paravirq_irqdomain_ops = {
.alloc = paravirq_domain_alloc,
.free = paravirq_domain_free,
};
static int __init paravirq_init(void)
{
int ret = 0;
int i = 0;
struct irq_alloc_info info = { 0 };
struct irq_cfg *cfg = NULL;
printk("paravirq_init\n");
paravirq_domain = irq_domain_add_linear(NULL, PARAVIRT_IRQS_N,
¶virq_irqdomain_ops, NULL);
if (!paravirq_domain) {
ret = -ENOMEM;
goto err0;
}
paravirq_domain->name = paravirq_chip.name;
paravirq_domain->parent = x86_vector_domain;
paravirq_domain->flags |= IRQ_DOMAIN_FLAG_AUTO_RECURSIVE;
printk("\tparavirq_domain %s (0x%p) is created\n",
paravirq_domain->name, paravirq_domain);
printk("\tcall irq_domain_alloc_irqs with info 0x%p\n", &info);
paravirq_irqbase = irq_domain_alloc_irqs(paravirq_domain,
PARAVIRT_IRQS_N, NUMA_NO_NODE, &info);
if (paravirq_irqbase < 0) {
printk("\tallocating irqs failed: %d\n", paravirq_irqbase);
ret = paravirq_irqbase;
goto err1;
}
printk("\tsuccessfully allocated %d irqs beginning from %d\n",
PARAVIRT_IRQS_N, paravirq_irqbase);
for (i = 0; i < PARAVIRT_IRQS_N; i++) {
int irq = paravirq_irqbase + i;
ret = request_irq(irq, paravirq_irq_handler,
0, "paravirq_mod", NULL);
if (ret) {
printk("\trequest_irq %d failed: %d\n", irq, ret);
goto err2;
} else {
printk("\tvirq %d is requested!\n", irq);
paravirq_irqs[i] = irq;
}
}
printk("\tSo, paravirq_mod grabbed %d irqs:\n", PARAVIRT_IRQS_N);
for (i = 0; i < PARAVIRT_IRQS_N; i++) {
cfg = irqd_cfg(irq_get_irq_data(paravirq_irqs[i]));
if (!cfg) {
printk("\t\tirq #%d: NULL irq_cfg\n", paravirq_irqs[i]);
goto err2;
}
printk("\t\tirq #%d: virq %d, vector %d\n",
i, paravirq_irqs[i], cfg->vector);
}
return 0;
err2:
for (i = 0; i < PARAVIRT_IRQS_N; i++) {
if (paravirq_irqs[i] >= 0) {
printk("\tfreeing virq %d\n", paravirq_irqs[i]);
free_irq(paravirq_irqs[i], NULL);
}
}
irq_domain_free_irqs(paravirq_irqbase, PARAVIRT_IRQS_N);
err1:
irq_domain_remove(paravirq_domain);
err0:
return ret;
}
static void __exit paravirq_exit(void)
{
int i;
printk("paravirq_exit\n");
for (i = 0; i < PARAVIRT_IRQS_N; i++) {
if (paravirq_irqs[i] > 0) {
printk("\tfreeing virq %d\n", paravirq_irqs[i]);
free_irq(paravirq_irqs[i], NULL);
}
}
if (paravirq_irqbase >= 0)
irq_domain_free_irqs(paravirq_irqbase, PARAVIRT_IRQS_N);
if (paravirq_domain)
irq_domain_remove(paravirq_domain);
}
module_init(paravirq_init)
module_exit(paravirq_exit)
MODULE_AUTHOR("Alexander Popov <alex.popov@linux.com>");
MODULE_DESCRIPTION("The module for handling interrupts from the hypervisor");
MODULE_LICENSE("GPL v2");
next prev parent reply other threads:[~2016-07-18 12:32 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-07-01 19:29 [PATCH 1/1] irqdomain: Export __irq_domain_alloc_irqs() and irq_domain_free_irqs() Alexander Popov
2016-07-06 11:17 ` Thomas Gleixner
2016-07-08 8:34 ` Alexander Popov
2016-07-16 1:33 ` Alexander Popov
2016-07-16 8:22 ` Marc Zyngier
2016-07-18 12:34 ` Alexander Popov [this message]
2016-07-25 19:35 ` Alexander Popov
2016-07-27 11:22 ` Christoph Hellwig
2016-07-29 23:21 ` Alexander Popov
2016-08-01 11:28 ` Jason Cooper
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=578CCCDB.4050800@linux.com \
--to=alex.popov@linux.com \
--cc=linux-kernel@vger.kernel.org \
--cc=marc.zyngier@arm.com \
--cc=tglx@linutronix.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.