All of lore.kernel.org
 help / color / mirror / Atom feed
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>,
	"Paolo Bonzini" <pbonzini@redhat.com>,
	"Radim Krčmář" <rkrcmar@redhat.com>,
	"Joerg Roedel" <joro@8bytes.org>,
	kvm@vger.kernel.org
Subject: Re: [PATCH 1/1] irqdomain: Export __irq_domain_alloc_irqs() and irq_domain_free_irqs()
Date: Mon, 25 Jul 2016 22:35:07 +0300	[thread overview]
Message-ID: <579669EB.6030604@linux.com> (raw)
In-Reply-To: <578CCCDB.4050800@linux.com>

On 18.07.2016 15:34, Alexander Popov wrote:
> 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.


I hope that the code below is a valid use-case of irq_domain hierarchy API.
Such simple registration of IRQ handlers for interrupts injected by a hypervisor
is great for lightweight hypervisors, which avoid as much emulation as possible.

It only needs __irq_domain_alloc_irqs() and irq_domain_free_irqs() to be
exported to modules. Will you apply my patch which exports them?

[Add CC to KVM people to share the idea and, hopefully, find anybody interested]


> /*
>  * The module 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, &paravirq_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,
> 						&paravirq_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");
> 

  reply	other threads:[~2016-07-25 19:35 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
2016-07-25 19:35           ` Alexander Popov [this message]
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=579669EB.6030604@linux.com \
    --to=alex.popov@linux.com \
    --cc=joro@8bytes.org \
    --cc=kvm@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=marc.zyngier@arm.com \
    --cc=pbonzini@redhat.com \
    --cc=rkrcmar@redhat.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.