static int uv_domain_alloc(struct irq_domain *domain, unsigned int virq, unsigned int nr_irqs, void *arg) { struct uv_irq_2_mmr_pnode *chip_data; struct irq_alloc_info *info = arg; struct irq_data *irq_data = irq_domain_get_irq_data(domain, virq); int ret; if (nr_irqs > 1 || !info || info->type != X86_IRQ_ALLOC_TYPE_UV) return -EINVAL; chip_data = kmalloc_node(sizeof(*chip_data), GFP_KERNEL, irq_data_get_node(irq_data)); if (!chip_data) return -ENOMEM; ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, arg); if (ret >= 0) { if (info->uv_limit == UV_AFFINITY_CPU) irq_set_status_flags(virq, IRQ_NO_BALANCING); else irq_set_status_flags(virq, IRQ_MOVE_PCNTXT); chip_data->pnode = uv_blade_to_pnode(info->uv_blade); chip_data->offset = info->uv_offset; irq_domain_set_info(domain, virq, virq, &uv_irq_chip, chip_data, handle_percpu_irq, NULL, info->uv_name); } else { kfree(chip_data); } return ret; }
static int imx_gpcv2_domain_alloc(struct irq_domain *domain, unsigned int irq, unsigned int nr_irqs, void *data) { struct of_phandle_args *args = data; struct of_phandle_args parent_args; irq_hw_number_t hwirq; int i; /* Not GIC compliant */ if (args->args_count != 3) return -EINVAL; /* No PPI should point to this domain */ if (args->args[0] != 0) return -EINVAL; /* Can't deal with this */ hwirq = args->args[1]; if (hwirq >= GPC_MAX_IRQS) return -EINVAL; for (i = 0; i < nr_irqs; i++) { irq_domain_set_hwirq_and_chip(domain, irq + i, hwirq + i, &gpcv2_irqchip_data_chip, domain->host_data); } parent_args = *args; parent_args.np = domain->parent->of_node; return irq_domain_alloc_irqs_parent(domain, irq, nr_irqs, &parent_args); }
static int imx_gpc_domain_alloc(struct irq_domain *domain, unsigned int irq, unsigned int nr_irqs, void *data) { struct irq_fwspec *fwspec = data; struct irq_fwspec parent_fwspec; irq_hw_number_t hwirq; int i; if (fwspec->param_count != 3) return -EINVAL; /* Not GIC compliant */ if (fwspec->param[0] != 0) return -EINVAL; /* No PPI should point to this domain */ hwirq = fwspec->param[1]; if (hwirq >= GPC_MAX_IRQS) return -EINVAL; /* Can't deal with this */ for (i = 0; i < nr_irqs; i++) irq_domain_set_hwirq_and_chip(domain, irq + i, hwirq + i, &imx_gpc_chip, NULL); parent_fwspec = *fwspec; parent_fwspec.fwnode = domain->parent->fwnode; return irq_domain_alloc_irqs_parent(domain, irq, nr_irqs, &parent_fwspec); }
static int xgene_gpio_sb_domain_alloc(struct irq_domain *domain, unsigned int virq, unsigned int nr_irqs, void *data) { struct irq_fwspec *fwspec = data; struct irq_fwspec parent_fwspec; struct xgene_gpio_sb *priv = domain->host_data; irq_hw_number_t hwirq; unsigned int i; hwirq = fwspec->param[0]; for (i = 0; i < nr_irqs; i++) irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i, &xgene_gpio_sb_irq_chip, priv); parent_fwspec.fwnode = domain->parent->fwnode; if (is_of_node(parent_fwspec.fwnode)) { parent_fwspec.param_count = 3; parent_fwspec.param[0] = 0;/* SPI */ /* Skip SGIs and PPIs*/ parent_fwspec.param[1] = hwirq + priv->parent_irq_base - 32; parent_fwspec.param[2] = fwspec->param[1]; } else if (is_fwnode_irqchip(parent_fwspec.fwnode)) { parent_fwspec.param_count = 2; parent_fwspec.param[0] = hwirq + priv->parent_irq_base; parent_fwspec.param[1] = fwspec->param[1]; } else return -EINVAL; return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &parent_fwspec); }
static int msi_domain_alloc(struct irq_domain *domain, unsigned int virq, unsigned int nr_irqs, void *arg) { struct msi_domain_info *info = domain->host_data; struct msi_domain_ops *ops = info->ops; irq_hw_number_t hwirq = ops->get_hwirq(info, arg); int i, ret; if (irq_find_mapping(domain, hwirq) > 0) return -EEXIST; ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, arg); if (ret < 0) return ret; for (i = 0; i < nr_irqs; i++) { ret = ops->msi_init(domain, info, virq + i, hwirq + i, arg); if (ret < 0) { if (ops->msi_free) { for (i--; i > 0; i--) ops->msi_free(domain, info, virq + i); } irq_domain_free_irqs_top(domain, virq, nr_irqs); return ret; } } return 0; }
static int gicp_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, unsigned int nr_irqs, void *args) { struct mvebu_gicp *gicp = domain->host_data; struct irq_fwspec fwspec; unsigned int hwirq; int ret; spin_lock(&gicp->spi_lock); hwirq = find_first_zero_bit(gicp->spi_bitmap, gicp->spi_cnt); if (hwirq == gicp->spi_cnt) { spin_unlock(&gicp->spi_lock); return -ENOSPC; } __set_bit(hwirq, gicp->spi_bitmap); spin_unlock(&gicp->spi_lock); fwspec.fwnode = domain->parent->fwnode; fwspec.param_count = 3; fwspec.param[0] = GIC_SPI; fwspec.param[1] = gicp_idx_to_spi(gicp, hwirq) - 32; /* * Assume edge rising for now, it will be properly set when * ->set_type() is called */ fwspec.param[2] = IRQ_TYPE_EDGE_RISING; ret = irq_domain_alloc_irqs_parent(domain, virq, 1, &fwspec); if (ret) { dev_err(gicp->dev, "Cannot allocate parent IRQ\n"); goto free_hwirq; } ret = irq_domain_set_hwirq_and_chip(domain, virq, hwirq, &gicp_irq_chip, gicp); if (ret) goto free_irqs_parent; return 0; free_irqs_parent: irq_domain_free_irqs_parent(domain, virq, nr_irqs); free_hwirq: spin_lock(&gicp->spi_lock); __clear_bit(hwirq, gicp->spi_bitmap); spin_unlock(&gicp->spi_lock); return ret; }
static int hyperv_irq_remapping_alloc(struct irq_domain *domain, unsigned int virq, unsigned int nr_irqs, void *arg) { struct irq_alloc_info *info = arg; struct irq_data *irq_data; struct irq_desc *desc; int ret = 0; if (!info || info->type != X86_IRQ_ALLOC_TYPE_IOAPIC || nr_irqs > 1) return -EINVAL; ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, arg); if (ret < 0) return ret; irq_data = irq_domain_get_irq_data(domain, virq); if (!irq_data) { irq_domain_free_irqs_common(domain, virq, nr_irqs); return -EINVAL; } irq_data->chip = &hyperv_ir_chip; /* * If there is interrupt remapping function of IOMMU, setting irq * affinity only needs to change IRTE of IOMMU. But Hyper-V doesn't * support interrupt remapping function, setting irq affinity of IO-APIC * interrupts still needs to change IO-APIC registers. But ioapic_ * configure_entry() will ignore value of cfg->vector and cfg-> * dest_apicid when IO-APIC's parent irq domain is not the vector * domain.(See ioapic_configure_entry()) In order to setting vector * and dest_apicid to IO-APIC register, IO-APIC entry pointer is saved * in the chip_data and hyperv_irq_remapping_activate()/hyperv_ir_set_ * affinity() set vector and dest_apicid directly into IO-APIC entry. */ irq_data->chip_data = info->ioapic_entry; /* * Hypver-V IO APIC irq affinity should be in the scope of * ioapic_max_cpumask because no irq remapping support. */ desc = irq_data_to_desc(irq_data); cpumask_copy(desc->irq_common_data.affinity, &ioapic_max_cpumask); return 0; }
static int htirq_domain_alloc(struct irq_domain *domain, unsigned int virq, unsigned int nr_irqs, void *arg) { struct ht_irq_cfg *ht_cfg; struct irq_alloc_info *info = arg; struct pci_dev *dev; irq_hw_number_t hwirq; int ret; if (nr_irqs > 1 || !info) return -EINVAL; dev = info->ht_dev; hwirq = (info->ht_idx & 0xFF) | PCI_DEVID(dev->bus->number, dev->devfn) << 8 | (pci_domain_nr(dev->bus) & 0xFFFFFFFF) << 24; if (irq_find_mapping(domain, hwirq) > 0) return -EEXIST; ht_cfg = kmalloc(sizeof(*ht_cfg), GFP_KERNEL); if (!ht_cfg) return -ENOMEM; ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, info); if (ret < 0) { kfree(ht_cfg); return ret; } /* Initialize msg to a value that will never match the first write. */ ht_cfg->msg.address_lo = 0xffffffff; ht_cfg->msg.address_hi = 0xffffffff; ht_cfg->dev = info->ht_dev; ht_cfg->update = info->ht_update; ht_cfg->pos = info->ht_pos; ht_cfg->idx = 0x10 + (info->ht_idx * 2); irq_domain_set_info(domain, virq, hwirq, &ht_irq_chip, ht_cfg, handle_edge_irq, ht_cfg, "edge"); return 0; }
static int gicv2m_irq_gic_domain_alloc(struct irq_domain *domain, unsigned int virq, irq_hw_number_t hwirq) { struct of_phandle_args args; struct irq_data *d; int err; args.np = domain->parent->of_node; args.args_count = 3; args.args[0] = 0; args.args[1] = hwirq - 32; args.args[2] = IRQ_TYPE_EDGE_RISING; err = irq_domain_alloc_irqs_parent(domain, virq, 1, &args); if (err) return err; /* Configure the interrupt line to be edge */ d = irq_domain_get_irq_data(domain->parent, virq); d->chip->irq_set_type(d, IRQ_TYPE_EDGE_RISING); return 0; }
static int exynos_pmu_domain_alloc(struct irq_domain *domain, unsigned int virq, unsigned int nr_irqs, void *data) { struct of_phandle_args *args = data; struct of_phandle_args parent_args; irq_hw_number_t hwirq; int i; if (args->args_count != 3) return -EINVAL; /* Not GIC compliant */ if (args->args[0] != 0) return -EINVAL; /* No PPI should point to this domain */ hwirq = args->args[1]; for (i = 0; i < nr_irqs; i++) irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i, &exynos_pmu_chip, NULL); parent_args = *args; parent_args.np = domain->parent->of_node; return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &parent_args); }
static int vf610_mscm_ir_domain_alloc(struct irq_domain *domain, unsigned int virq, unsigned int nr_irqs, void *arg) { int i; irq_hw_number_t hwirq; struct of_phandle_args *irq_data = arg; struct of_phandle_args gic_data; if (irq_data->args_count != 2) return -EINVAL; hwirq = irq_data->args[0]; for (i = 0; i < nr_irqs; i++) irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i, &vf610_mscm_ir_irq_chip, domain->host_data); gic_data.np = domain->parent->of_node; gic_data.args_count = 3; gic_data.args[0] = GIC_SPI; gic_data.args[1] = irq_data->args[0]; gic_data.args[2] = irq_data->args[1]; return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &gic_data); }
static int allocate_gic_irq(struct irq_domain *domain, unsigned virq, irq_hw_number_t hwirq) { struct irq_fwspec fwspec; int i; int err; if (!irq_domain_get_of_node(domain->parent)) return -EINVAL; raw_spin_lock(&cb->lock); for (i = cb->int_max - 1; i >= 0; i--) { if (cb->irq_map[i] == IRQ_FREE) { cb->irq_map[i] = hwirq; break; } } raw_spin_unlock(&cb->lock); if (i < 0) return -ENODEV; fwspec.fwnode = domain->parent->fwnode; fwspec.param_count = 3; fwspec.param[0] = 0; /* SPI */ fwspec.param[1] = i; fwspec.param[2] = IRQ_TYPE_LEVEL_HIGH; err = irq_domain_alloc_irqs_parent(domain, virq, 1, &fwspec); if (err) cb->irq_map[i] = IRQ_FREE; else cb->write(i, hwirq); return err; }