Each revmap type has different arguments for setting up the revmap.
This patch splits up the generator functions so that each revmap type
can do its own setup and the user doesn't need to keep track of how
each revmap type handles the arguments.
This patch also adds a host_data argument to the generators. There are
cases where the host_data pointer will be needed before the function returns.
ie. the legacy map calls the .map callback for each irq before returning.
v2: - Add void *host_data argument to irq_domain_add_*() functions
- fixed failure to compile
- Moved IRQ_DOMAIN_MAP_* defines into irqdomain.c
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
Cc: Rob Herring <rob.herring@calxeda.com>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Milton Miller <miltonm@bga.com>
Tested-by: Olof Johansson <olof@lixom.net>
cpld_pic_node = of_node_get(np);
- cpld_pic_host =
- irq_alloc_host(np, IRQ_DOMAIN_MAP_LINEAR, 16, &cpld_pic_host_ops, 16);
+ cpld_pic_host = irq_domain_add_linear(np, 16, &cpld_pic_host_ops, NULL);
if (!cpld_pic_host) {
printk(KERN_ERR "CPLD PIC: failed to allocate irq host!\n");
goto end;
spin_lock_init(&media5200_irq.lock);
- media5200_irq.irqhost = irq_alloc_host(fpga_np, IRQ_DOMAIN_MAP_LINEAR,
- MEDIA5200_NUM_IRQS,
- &media5200_irq_ops, -1);
+ media5200_irq.irqhost = irq_domain_add_linear(fpga_np,
+ MEDIA5200_NUM_IRQS, &media5200_irq_ops, &media5200_irq);
if (!media5200_irq.irqhost)
goto out;
pr_debug("%s: allocated irqhost\n", __func__);
- media5200_irq.irqhost->host_data = &media5200_irq;
-
irq_set_handler_data(cascade_virq, &media5200_irq);
irq_set_chained_handler(cascade_virq, media5200_irq_cascade);
if (!cascade_virq)
return;
- gpt->irqhost = irq_alloc_host(node, IRQ_DOMAIN_MAP_LINEAR, 1,
- &mpc52xx_gpt_irq_ops, -1);
+ gpt->irqhost = irq_domain_add_linear(node, 1, &mpc52xx_gpt_irq_ops, gpt);
if (!gpt->irqhost) {
- dev_err(gpt->dev, "irq_alloc_host() failed\n");
+ dev_err(gpt->dev, "irq_domain_add_linear() failed\n");
return;
}
- gpt->irqhost->host_data = gpt;
irq_set_handler_data(cascade_virq, gpt);
irq_set_chained_handler(cascade_virq, mpc52xx_gpt_irq_cascade);
* As last step, add an irq host to translate the real
* hw irq information provided by the ofw to linux virq
*/
- mpc52xx_irqhost = irq_alloc_host(picnode, IRQ_DOMAIN_MAP_LINEAR,
+ mpc52xx_irqhost = irq_domain_add_linear(picnode,
MPC52xx_IRQ_HIGHTESTHWIRQ,
- &mpc52xx_irqhost_ops, -1);
+ &mpc52xx_irqhost_ops, NULL);
if (!mpc52xx_irqhost)
panic(__FILE__ ": Cannot allocate the IRQ host\n");
out_be32(&priv->regs->mask, ~0);
mb();
- host = irq_alloc_host(np, IRQ_DOMAIN_MAP_LINEAR, NUM_IRQS,
- &pci_pic_host_ops, NUM_IRQS);
+ host = irq_domain_add_linear(np, NUM_IRQS, &pci_pic_host_ops, priv);
if (!host) {
ret = -ENOMEM;
goto out_unmap_regs;
}
- host->host_data = priv;
-
priv->host = host;
- host->host_data = priv;
irq_set_handler_data(irq, priv);
irq_set_chained_handler(irq, pq2ads_pci_irq_demux);
int i;
/* Setup an irq_domain structure */
- socrates_fpga_pic_irq_host = irq_alloc_host(pic, IRQ_DOMAIN_MAP_LINEAR,
- SOCRATES_FPGA_NUM_IRQS, &socrates_fpga_pic_host_ops,
- SOCRATES_FPGA_NUM_IRQS);
+ socrates_fpga_pic_irq_host = irq_domain_add_linear(pic,
+ SOCRATES_FPGA_NUM_IRQS, &socrates_fpga_pic_host_ops, NULL);
if (socrates_fpga_pic_irq_host == NULL) {
pr_err("FPGA PIC: Unable to allocate host\n");
return;
}
/* Setup an irq_domain structure */
- gef_pic_irq_host = irq_alloc_host(np, IRQ_DOMAIN_MAP_LINEAR,
- GEF_PIC_NUM_IRQS,
- &gef_pic_host_ops, NO_IRQ);
+ gef_pic_irq_host = irq_domain_add_linear(np, GEF_PIC_NUM_IRQS,
+ &gef_pic_host_ops, NULL);
if (gef_pic_irq_host == NULL)
return;
}
memset(msic->fifo_virt, 0xff, MSIC_FIFO_SIZE_BYTES);
- msic->irq_domain = irq_alloc_host(dn, IRQ_DOMAIN_MAP_NOMAP,
- NR_IRQS, &msic_host_ops, 0);
+ msic->irq_domain = irq_domain_add_nomap(dn, &msic_host_ops, msic);
if (!msic->irq_domain) {
printk(KERN_ERR "axon_msi: couldn't allocate irq_domain for %s\n",
dn->full_name);
goto out_free_fifo;
}
- msic->irq_domain->host_data = msic;
-
irq_set_handler_data(virq, msic);
irq_set_chained_handler(virq, axon_msi_cascade);
pr_devel("axon_msi: irq 0x%x setup for axon_msi\n", virq);
ppc_md.get_irq = beatic_get_irq;
/* Allocate an irq host */
- beatic_host = irq_alloc_host(NULL, IRQ_DOMAIN_MAP_NOMAP, 0,
- &beatic_pic_host_ops,
- 0);
+ beatic_host = irq_domain_add_nomap(NULL, &beatic_pic_host_ops, NULL);
BUG_ON(beatic_host == NULL);
irq_set_default_host(beatic_host);
}
void __init iic_init_IRQ(void)
{
/* Setup an irq host data structure */
- iic_host = irq_alloc_host(NULL, IRQ_DOMAIN_MAP_LINEAR, IIC_SOURCE_COUNT,
- &iic_host_ops, IIC_IRQ_INVALID);
+ iic_host = irq_domain_add_linear(NULL, IIC_SOURCE_COUNT, &iic_host_ops,
+ NULL);
BUG_ON(iic_host == NULL);
irq_set_default_host(iic_host);
panic("spider_pic: can't map registers !");
/* Allocate a host */
- pic->host = irq_alloc_host(of_node, IRQ_DOMAIN_MAP_LINEAR,
- SPIDER_SRC_COUNT, &spider_host_ops,
- SPIDER_IRQ_INVALID);
+ pic->host = irq_domain_add_linear(of_node, SPIDER_SRC_COUNT,
+ &spider_host_ops, pic);
if (pic->host == NULL)
panic("spider_pic: can't allocate irq host !");
- pic->host->host_data = pic;
/* Go through all sources and disable them */
for (i = 0; i < SPIDER_SRC_COUNT; i++) {
__flipper_quiesce(io_base);
- irq_domain = irq_alloc_host(np, IRQ_DOMAIN_MAP_LINEAR, FLIPPER_NR_IRQS,
- &flipper_irq_domain_ops, -1);
+ irq_domain = irq_domain_add_linear(np, FLIPPER_NR_IRQS,
+ &flipper_irq_domain_ops, io_base);
if (!irq_domain) {
pr_err("failed to allocate irq_domain\n");
return NULL;
}
- irq_domain->host_data = io_base;
-
out:
return irq_domain;
}
__hlwd_quiesce(io_base);
- irq_domain = irq_alloc_host(np, IRQ_DOMAIN_MAP_LINEAR, HLWD_NR_IRQS,
- &hlwd_irq_domain_ops, -1);
+ irq_domain = irq_domain_add_linear(np, HLWD_NR_IRQS,
+ &hlwd_irq_domain_ops, io_base);
if (!irq_domain) {
pr_err("failed to allocate irq_domain\n");
return NULL;
}
- irq_domain->host_data = io_base;
return irq_domain;
}
/* Create irq host. No need for a revmap since HV will give us
* back our virtual irq number
*/
- host = irq_alloc_host(NULL, IRQ_DOMAIN_MAP_NOMAP, 0,
- &iseries_irq_domain_ops, 0);
+ host = irq_domain_add_nomap(NULL, &iseries_irq_domain_ops, NULL);
BUG_ON(host == NULL);
irq_set_default_host(host);
/*
* Allocate an irq host
*/
- pmac_pic_host = irq_alloc_host(master, IRQ_DOMAIN_MAP_LINEAR, max_irqs,
- &pmac_pic_host_ops,
- max_irqs);
+ pmac_pic_host = irq_domain_add_linear(master, max_irqs,
+ &pmac_pic_host_ops, NULL);
BUG_ON(pmac_pic_host == NULL);
irq_set_default_host(pmac_pic_host);
{
int rc = -ENOMEM;
- psurge_host = irq_alloc_host(NULL, IRQ_DOMAIN_MAP_NOMAP, 0,
- &psurge_host_ops, 0);
+ psurge_host = irq_domain_add_nomap(NULL, &psurge_host_ops, NULL);
if (psurge_host)
psurge_secondary_virq = irq_create_direct_mapping(psurge_host);
unsigned cpu;
struct irq_domain *host;
- host = irq_alloc_host(NULL, IRQ_DOMAIN_MAP_NOMAP, 0, &ps3_host_ops,
- PS3_INVALID_OUTLET);
+ host = irq_domain_add_nomap(NULL, &ps3_host_ops, NULL);
irq_set_default_host(host);
irq_set_virq_count(PS3_PLUG_MAX + 1);
goto free_opb;
}
- /* Allocate an irq host so that Linux knows that despite only
+ /* Allocate an irq domain so that Linux knows that despite only
* having one interrupt to issue, we're the controller for multiple
* hardware IRQs, so later we can lookup their virtual IRQs. */
- opb->host = irq_alloc_host(dn, IRQ_DOMAIN_MAP_LINEAR,
- OPB_NR_IRQS, &opb_host_ops, -1);
-
+ opb->host = irq_domain_add_linear(dn, OPB_NR_IRQS, &opb_host_ops, opb);
if (!opb->host) {
printk(KERN_ERR "opb: Failed to allocate IRQ host!\n");
goto free_regs;
opb->index = opb_index++;
spin_lock_init(&opb->lock);
- opb->host->host_data = opb;
/* Disable all interrupts by default */
opb_out(opb, OPB_MLSASIER, 0);
out_be32(&cpic_reg->cpic_cimr, 0);
- cpm_pic_host = irq_alloc_host(np, IRQ_DOMAIN_MAP_LINEAR,
- 64, &cpm_pic_host_ops, 64);
+ cpm_pic_host = irq_domain_add_linear(np, 64, &cpm_pic_host_ops, NULL);
if (cpm_pic_host == NULL) {
printk(KERN_ERR "CPM2 PIC: failed to allocate irq host!\n");
sirq = NO_IRQ;
out_be32(&cpm2_intctl->ic_scprrl, 0x05309770);
/* create a legacy host */
- cpm2_pic_host = irq_alloc_host(node, IRQ_DOMAIN_MAP_LINEAR,
- 64, &cpm2_pic_host_ops, 64);
+ cpm2_pic_host = irq_domain_add_linear(node, 64, &cpm2_pic_host_ops, NULL);
if (cpm2_pic_host == NULL) {
printk(KERN_ERR "CPM2 PIC: failed to allocate irq host!\n");
return;
return;
}
- ehv_pic->irqhost = irq_alloc_host(np, IRQ_DOMAIN_MAP_LINEAR,
- NR_EHV_PIC_INTS, &ehv_pic_host_ops, 0);
-
+ ehv_pic->irqhost = irq_domain_add_linear(np, NR_EHV_PIC_INTS,
+ &ehv_pic_host_ops, ehv_pic);
if (!ehv_pic->irqhost) {
of_node_put(np);
kfree(ehv_pic);
of_node_put(np2);
}
- ehv_pic->irqhost->host_data = ehv_pic;
ehv_pic->hc_irq = ehv_pic_irq_chip;
ehv_pic->hc_irq.irq_set_affinity = ehv_pic_set_affinity;
ehv_pic->coreint_flag = coreint_flag;
}
platform_set_drvdata(dev, msi);
- msi->irqhost = irq_alloc_host(dev->dev.of_node, IRQ_DOMAIN_MAP_LINEAR,
- NR_MSI_IRQS, &fsl_msi_host_ops, 0);
+ msi->irqhost = irq_domain_add_linear(dev->dev.of_node,
+ NR_MSI_IRQS, &fsl_msi_host_ops, msi);
if (msi->irqhost == NULL) {
dev_err(&dev->dev, "No memory for MSI irqhost\n");
msi->feature = features->fsl_pic_ip;
- msi->irqhost->host_data = msi;
-
/*
* Remember the phandle, so that we can match with any PCI nodes
* that have an "fsl,msi" property.
raw_spin_unlock_irqrestore(&i8259_lock, flags);
/* create a legacy host */
- i8259_host = irq_alloc_host(node, IRQ_DOMAIN_MAP_LEGACY,
- 0, &i8259_host_ops, 0);
+ i8259_host = irq_domain_add_legacy(node, &i8259_host_ops, NULL);
if (i8259_host == NULL) {
printk(KERN_ERR "i8259: failed to allocate irq host !\n");
return;
if (ipic == NULL)
return NULL;
- ipic->irqhost = irq_alloc_host(node, IRQ_DOMAIN_MAP_LINEAR,
- NR_IPIC_INTS,
- &ipic_host_ops, 0);
+ ipic->irqhost = irq_domain_add_linear(node, NR_IPIC_INTS,
+ &ipic_host_ops, ipic);
if (ipic->irqhost == NULL) {
kfree(ipic);
return NULL;
ipic->regs = ioremap(res.start, resource_size(&res));
- ipic->irqhost->host_data = ipic;
-
/* init hw */
ipic_write(ipic->regs, IPIC_SICNR, 0x0);
goto out;
}
- mpc8xx_pic_host = irq_alloc_host(np, IRQ_DOMAIN_MAP_LINEAR,
- 64, &mpc8xx_pic_host_ops, 64);
+ mpc8xx_pic_host = irq_domain_add_linear(np, 64, &mpc8xx_pic_host_ops, NULL);
if (mpc8xx_pic_host == NULL) {
printk(KERN_ERR "MPC8xx PIC: failed to allocate irq host!\n");
ret = -ENOMEM;
mpic->isu_shift = 1 + __ilog2(mpic->isu_size - 1);
mpic->isu_mask = (1 << mpic->isu_shift) - 1;
- mpic->irqhost = irq_alloc_host(mpic->node, IRQ_DOMAIN_MAP_LINEAR,
+ mpic->irqhost = irq_domain_add_linear(mpic->node,
isu_size ? isu_size : mpic->num_sources,
- &mpic_host_ops,
- flags & MPIC_LARGE_VECTORS ? 2048 : 256);
+ &mpic_host_ops, mpic);
/*
* FIXME: The code leaks the MPIC object and mappings here; this
if (mpic->irqhost == NULL)
return NULL;
- mpic->irqhost->host_data = mpic;
-
/* Display version */
switch (greg_feature & MPIC_GREG_FEATURE_VERSION_MASK) {
case 1:
paddr = of_translate_address(np, reg);
mv64x60_irq_reg_base = ioremap(paddr, reg[1]);
- mv64x60_irq_host = irq_alloc_host(np, IRQ_DOMAIN_MAP_LINEAR,
- MV64x60_NUM_IRQS,
- &mv64x60_host_ops, MV64x60_NUM_IRQS);
+ mv64x60_irq_host = irq_domain_add_linear(np, MV64x60_NUM_IRQS,
+ &mv64x60_host_ops, NULL);
spin_lock_irqsave(&mv64x60_lock, flags);
out_le32(mv64x60_gpp_reg_base + MV64x60_GPP_INTR_MASK,
if (qe_ic == NULL)
return;
- qe_ic->irqhost = irq_alloc_host(node, IRQ_DOMAIN_MAP_LINEAR,
- NR_QE_IC_INTS, &qe_ic_host_ops, 0);
+ qe_ic->irqhost = irq_domain_add_linear(node, NR_QE_IC_INTS,
+ &qe_ic_host_ops, qe_ic);
if (qe_ic->irqhost == NULL) {
kfree(qe_ic);
return;
qe_ic->regs = ioremap(res.start, resource_size(&res));
- qe_ic->irqhost->host_data = qe_ic;
qe_ic->hc_irq = qe_ic_irq_chip;
qe_ic->virq_high = irq_of_parse_and_map(node, 0);
{
DBG("Tsi108_pci_int_init: initializing PCI interrupts\n");
- pci_irq_host = irq_alloc_host(node, IRQ_DOMAIN_MAP_LEGACY,
- 0, &pci_irq_domain_ops, 0);
+ pci_irq_host = irq_domain_add_legacy(node, &pci_irq_domain_ops, NULL);
if (pci_irq_host == NULL) {
printk(KERN_ERR "pci_irq_host: failed to allocate irq domain!\n");
return;
}
uic->dcrbase = *dcrreg;
- uic->irqhost = irq_alloc_host(node, IRQ_DOMAIN_MAP_LINEAR,
- NR_UIC_INTS, &uic_host_ops, -1);
+ uic->irqhost = irq_domain_add_linear(node, NR_UIC_INTS, &uic_host_ops,
+ uic);
if (! uic->irqhost)
return NULL; /* FIXME: panic? */
- uic->irqhost->host_data = uic;
-
/* Start with all interrupts disabled, level and non-critical */
mtdcr(uic->dcrbase + UIC_ER, 0);
mtdcr(uic->dcrbase + UIC_CR, 0);
static void __init xics_init_host(void)
{
- xics_host = irq_alloc_host(NULL, IRQ_DOMAIN_MAP_TREE, 0, &xics_host_ops,
- XICS_IRQ_SPURIOUS);
+ xics_host = irq_domain_add_tree(NULL, &xics_host_ops, NULL);
BUG_ON(xics_host == NULL);
irq_set_default_host(xics_host);
}
out_be32(regs + XINTC_MER, 0x3UL); /* Turn on the Master Enable. */
/* Allocate and initialize an irq_domain structure. */
- irq = irq_alloc_host(np, IRQ_DOMAIN_MAP_LINEAR, XILINX_INTC_MAXIRQS,
- &xilinx_intc_ops, -1);
+ irq = irq_domain_add_linear(np, XILINX_INTC_MAXIRQS, &xilinx_intc_ops,
+ regs);
if (!irq)
panic(__FILE__ ": Cannot allocate IRQ host\n");
- irq->host_data = regs;
return irq;
}
if (hwirq == NO_IRQ)
goto skip_irq;
- mpc8xxx_gc->irq =
- irq_alloc_host(np, IRQ_DOMAIN_MAP_LINEAR, MPC8XXX_GPIO_PINS,
- &mpc8xxx_gpio_irq_ops, MPC8XXX_GPIO_PINS);
+ mpc8xxx_gc->irq = irq_domain_add_linear(np, MPC8XXX_GPIO_PINS,
+ &mpc8xxx_gpio_irq_ops, mpc8xxx_gc);
if (!mpc8xxx_gc->irq)
goto skip_irq;
if (id)
mpc8xxx_gc->of_dev_id_data = id->data;
- mpc8xxx_gc->irq->host_data = mpc8xxx_gc;
-
/* ack and mask all irqs */
out_be32(mm_gc->regs + GPIO_IER, 0xffffffff);
out_be32(mm_gc->regs + GPIO_IMR, 0);
/* type of reverse mapping_technique */
unsigned int revmap_type;
-#define IRQ_DOMAIN_MAP_LEGACY 0 /* legacy 8259, gets irqs 1..15 */
-#define IRQ_DOMAIN_MAP_NOMAP 1 /* no fast reverse mapping */
-#define IRQ_DOMAIN_MAP_LINEAR 2 /* linear map of interrupts */
-#define IRQ_DOMAIN_MAP_TREE 3 /* radix tree */
union {
struct {
unsigned int size;
#ifdef CONFIG_IRQ_DOMAIN
#ifdef CONFIG_PPC
-extern struct irq_domain *irq_alloc_host(struct device_node *of_node,
- unsigned int revmap_type,
- unsigned int revmap_arg,
- struct irq_domain_ops *ops,
- irq_hw_number_t inval_irq);
+struct irq_domain *irq_domain_add_legacy(struct device_node *of_node,
+ struct irq_domain_ops *ops,
+ void *host_data);
+struct irq_domain *irq_domain_add_linear(struct device_node *of_node,
+ unsigned int size,
+ struct irq_domain_ops *ops,
+ void *host_data);
+struct irq_domain *irq_domain_add_nomap(struct device_node *of_node,
+ struct irq_domain_ops *ops,
+ void *host_data);
+struct irq_domain *irq_domain_add_tree(struct device_node *of_node,
+ struct irq_domain_ops *ops,
+ void *host_data);
+
+
extern struct irq_domain *irq_find_host(struct device_node *node);
extern void irq_set_default_host(struct irq_domain *host);
extern void irq_set_virq_count(unsigned int count);
#include <linux/smp.h>
#include <linux/fs.h>
+#define IRQ_DOMAIN_MAP_LEGACY 0 /* legacy 8259, gets irqs 1..15 */
+#define IRQ_DOMAIN_MAP_NOMAP 1 /* no fast reverse mapping */
+#define IRQ_DOMAIN_MAP_LINEAR 2 /* linear map of interrupts */
+#define IRQ_DOMAIN_MAP_TREE 3 /* radix tree */
+
static LIST_HEAD(irq_domain_list);
static DEFINE_MUTEX(irq_domain_mutex);
}
/**
- * irq_alloc_host() - Allocate a new irq_domain data structure
+ * irq_domain_alloc() - Allocate a new irq_domain data structure
* @of_node: optional device-tree node of the interrupt controller
* @revmap_type: type of reverse mapping to use
- * @revmap_arg: for IRQ_DOMAIN_MAP_LINEAR linear only: size of the map
* @ops: map/unmap domain callbacks
- * @inval_irq: provide a hw number in that domain space that is always invalid
+ * @host_data: Controller private data pointer
*
- * Allocates and initialize and irq_domain structure. Note that in the case of
- * IRQ_DOMAIN_MAP_LEGACY, the map() callback will be called before this returns
- * for all legacy interrupts except 0 (which is always the invalid irq for
- * a legacy controller). For a IRQ_DOMAIN_MAP_LINEAR, the map is allocated by
- * this call as well. For a IRQ_DOMAIN_MAP_TREE, the radix tree will be
- * allocated later during boot automatically (the reverse mapping will use the
- * slow path until that happens).
+ * Allocates and initialize and irq_domain structure. Caller is expected to
+ * register allocated irq_domain with irq_domain_register(). Returns pointer
+ * to IRQ domain, or NULL on failure.
*/
-struct irq_domain *irq_alloc_host(struct device_node *of_node,
- unsigned int revmap_type,
- unsigned int revmap_arg,
- struct irq_domain_ops *ops,
- irq_hw_number_t inval_irq)
+static struct irq_domain *irq_domain_alloc(struct device_node *of_node,
+ unsigned int revmap_type,
+ struct irq_domain_ops *ops,
+ void *host_data)
{
- struct irq_domain *domain, *h;
- unsigned int size = sizeof(struct irq_domain);
- unsigned int i;
- unsigned int *rmap;
+ struct irq_domain *domain;
- /* Allocate structure and revmap table if using linear mapping */
- if (revmap_type == IRQ_DOMAIN_MAP_LINEAR)
- size += revmap_arg * sizeof(unsigned int);
- domain = kzalloc(size, GFP_KERNEL);
- if (domain == NULL)
+ domain = kzalloc(sizeof(*domain), GFP_KERNEL);
+ if (WARN_ON(!domain))
return NULL;
/* Fill structure */
domain->revmap_type = revmap_type;
- domain->inval_irq = inval_irq;
domain->ops = ops;
+ domain->host_data = host_data;
domain->of_node = of_node_get(of_node);
if (domain->ops->match == NULL)
domain->ops->match = default_irq_domain_match;
+ return domain;
+}
+
+static void irq_domain_add(struct irq_domain *domain)
+{
+ mutex_lock(&irq_domain_mutex);
+ list_add(&domain->link, &irq_domain_list);
+ mutex_unlock(&irq_domain_mutex);
+ pr_debug("irq: Allocated domain of type %d @0x%p\n",
+ domain->revmap_type, domain);
+}
+
+/**
+ * irq_domain_add_legacy() - Allocate and register a legacy revmap irq_domain.
+ * @of_node: pointer to interrupt controller's device tree node.
+ * @ops: map/unmap domain callbacks
+ * @host_data: Controller private data pointer
+ *
+ * Note: the map() callback will be called before this function returns
+ * for all legacy interrupts except 0 (which is always the invalid irq for
+ * a legacy controller).
+ */
+struct irq_domain *irq_domain_add_legacy(struct device_node *of_node,
+ struct irq_domain_ops *ops,
+ void *host_data)
+{
+ struct irq_domain *domain, *h;
+ unsigned int i;
+
+ domain = irq_domain_alloc(of_node, IRQ_DOMAIN_MAP_LEGACY, ops, host_data);
+ if (!domain)
+ return NULL;
+
mutex_lock(&irq_domain_mutex);
/* Make sure only one legacy controller can be created */
- if (revmap_type == IRQ_DOMAIN_MAP_LEGACY) {
- list_for_each_entry(h, &irq_domain_list, link) {
- if (WARN_ON(h->revmap_type == IRQ_DOMAIN_MAP_LEGACY)) {
- mutex_unlock(&irq_domain_mutex);
- of_node_put(domain->of_node);
- kfree(domain);
- return NULL;
- }
+ list_for_each_entry(h, &irq_domain_list, link) {
+ if (WARN_ON(h->revmap_type == IRQ_DOMAIN_MAP_LEGACY)) {
+ mutex_unlock(&irq_domain_mutex);
+ of_node_put(domain->of_node);
+ kfree(domain);
+ return NULL;
}
}
list_add(&domain->link, &irq_domain_list);
mutex_unlock(&irq_domain_mutex);
- /* Additional setups per revmap type */
- switch(revmap_type) {
- case IRQ_DOMAIN_MAP_LEGACY:
- /* 0 is always the invalid number for legacy */
- domain->inval_irq = 0;
- /* setup us as the domain for all legacy interrupts */
- for (i = 1; i < NUM_ISA_INTERRUPTS; i++) {
- struct irq_data *irq_data = irq_get_irq_data(i);
- irq_data->hwirq = i;
- irq_data->domain = domain;
-
- /* Legacy flags are left to default at this point,
- * one can then use irq_create_mapping() to
- * explicitly change them
- */
- ops->map(domain, i, i);
-
- /* Clear norequest flags */
- irq_clear_status_flags(i, IRQ_NOREQUEST);
- }
- break;
- case IRQ_DOMAIN_MAP_LINEAR:
- rmap = (unsigned int *)(domain + 1);
- for (i = 0; i < revmap_arg; i++)
- rmap[i] = 0;
- domain->revmap_data.linear.size = revmap_arg;
- domain->revmap_data.linear.revmap = rmap;
- break;
- case IRQ_DOMAIN_MAP_TREE:
- INIT_RADIX_TREE(&domain->revmap_data.tree, GFP_KERNEL);
- break;
- default:
- break;
+ /* setup us as the domain for all legacy interrupts */
+ for (i = 1; i < NUM_ISA_INTERRUPTS; i++) {
+ struct irq_data *irq_data = irq_get_irq_data(i);
+ irq_data->hwirq = i;
+ irq_data->domain = domain;
+
+ /* Legacy flags are left to default at this point,
+ * one can then use irq_create_mapping() to
+ * explicitly change them
+ */
+ ops->map(domain, i, i);
+
+ /* Clear norequest flags */
+ irq_clear_status_flags(i, IRQ_NOREQUEST);
}
+ return domain;
+}
- pr_debug("irq: Allocated domain of type %d @0x%p\n", revmap_type, domain);
+/**
+ * irq_domain_add_linear() - Allocate and register a legacy revmap irq_domain.
+ * @of_node: pointer to interrupt controller's device tree node.
+ * @ops: map/unmap domain callbacks
+ * @host_data: Controller private data pointer
+ */
+struct irq_domain *irq_domain_add_linear(struct device_node *of_node,
+ unsigned int size,
+ struct irq_domain_ops *ops,
+ void *host_data)
+{
+ struct irq_domain *domain;
+ unsigned int *revmap;
+
+ revmap = kzalloc(sizeof(*revmap) * size, GFP_KERNEL);
+ if (WARN_ON(!revmap))
+ return NULL;
+ domain = irq_domain_alloc(of_node, IRQ_DOMAIN_MAP_LINEAR, ops, host_data);
+ if (!domain) {
+ kfree(revmap);
+ return NULL;
+ }
+ domain->revmap_data.linear.size = size;
+ domain->revmap_data.linear.revmap = revmap;
+ irq_domain_add(domain);
+ return domain;
+}
+
+struct irq_domain *irq_domain_add_nomap(struct device_node *of_node,
+ struct irq_domain_ops *ops,
+ void *host_data)
+{
+ struct irq_domain *domain = irq_domain_alloc(of_node,
+ IRQ_DOMAIN_MAP_NOMAP, ops, host_data);
+ if (domain)
+ irq_domain_add(domain);
+ return domain;
+}
+
+/**
+ * irq_domain_add_tree()
+ * @of_node: pointer to interrupt controller's device tree node.
+ * @ops: map/unmap domain callbacks
+ *
+ * Note: The radix tree will be allocated later during boot automatically
+ * (the reverse mapping will use the slow path until that happens).
+ */
+struct irq_domain *irq_domain_add_tree(struct device_node *of_node,
+ struct irq_domain_ops *ops,
+ void *host_data)
+{
+ struct irq_domain *domain = irq_domain_alloc(of_node,
+ IRQ_DOMAIN_MAP_TREE, ops, host_data);
+ if (domain) {
+ INIT_RADIX_TREE(&domain->revmap_data.tree, GFP_KERNEL);
+ irq_domain_add(domain);
+ }
return domain;
}
break;
}
- /* Destroy map */
- irq_data->hwirq = domain->inval_irq;
-
irq_free_desc(virq);
}
EXPORT_SYMBOL_GPL(irq_dispose_mapping);