Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'irq/for-arm' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip into next/soc

* 'irq/for-arm' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
irqchip: vf610-mscm: Support NVIC parent chip
irqchip: nvic: Support hierarchy irq domain
genirq: generic chip: Support hierarchy domain
genirq: Add irq_chip_(enable/disable)_parent
irqdomain: Add non-hierarchy helper irq_domain_set_info

+102 -14
+1
drivers/irqchip/Kconfig
··· 30 30 config ARM_NVIC 31 31 bool 32 32 select IRQ_DOMAIN 33 + select IRQ_DOMAIN_HIERARCHY 33 34 select GENERIC_IRQ_CHIP 34 35 35 36 config ARM_VIC
+27 -1
drivers/irqchip/irq-nvic.c
··· 49 49 handle_IRQ(irq, regs); 50 50 } 51 51 52 + static int nvic_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, 53 + unsigned int nr_irqs, void *arg) 54 + { 55 + int i, ret; 56 + irq_hw_number_t hwirq; 57 + unsigned int type = IRQ_TYPE_NONE; 58 + struct of_phandle_args *irq_data = arg; 59 + 60 + ret = irq_domain_xlate_onecell(domain, irq_data->np, irq_data->args, 61 + irq_data->args_count, &hwirq, &type); 62 + if (ret) 63 + return ret; 64 + 65 + for (i = 0; i < nr_irqs; i++) 66 + irq_map_generic_chip(domain, virq + i, hwirq + i); 67 + 68 + return 0; 69 + } 70 + 71 + static const struct irq_domain_ops nvic_irq_domain_ops = { 72 + .xlate = irq_domain_xlate_onecell, 73 + .alloc = nvic_irq_domain_alloc, 74 + .free = irq_domain_free_irqs_top, 75 + }; 76 + 52 77 static int __init nvic_of_init(struct device_node *node, 53 78 struct device_node *parent) 54 79 { ··· 95 70 irqs = NVIC_MAX_IRQ; 96 71 97 72 nvic_irq_domain = 98 - irq_domain_add_linear(node, irqs, &irq_generic_chip_ops, NULL); 73 + irq_domain_add_linear(node, irqs, &nvic_irq_domain_ops, NULL); 74 + 99 75 if (!nvic_irq_domain) { 100 76 pr_warn("Failed to allocate irq domain\n"); 101 77 return -ENOMEM;
+17 -6
drivers/irqchip/irq-vf610-mscm-ir.c
··· 47 47 void __iomem *mscm_ir_base; 48 48 u16 cpu_mask; 49 49 u16 saved_irsprc[MSCM_IRSPRC_NUM]; 50 + bool is_nvic; 50 51 }; 51 52 52 53 static struct vf610_mscm_ir_chip_data *mscm_ir_data; ··· 102 101 writew_relaxed(chip_data->cpu_mask, 103 102 chip_data->mscm_ir_base + MSCM_IRSPRC(hwirq)); 104 103 105 - irq_chip_unmask_parent(data); 104 + irq_chip_enable_parent(data); 106 105 } 107 106 108 107 static void vf610_mscm_ir_disable(struct irq_data *data) ··· 112 111 113 112 writew_relaxed(0x0, chip_data->mscm_ir_base + MSCM_IRSPRC(hwirq)); 114 113 115 - irq_chip_mask_parent(data); 114 + irq_chip_disable_parent(data); 116 115 } 117 116 118 117 static struct irq_chip vf610_mscm_ir_irq_chip = { ··· 144 143 domain->host_data); 145 144 146 145 gic_data.np = domain->parent->of_node; 147 - gic_data.args_count = 3; 148 - gic_data.args[0] = GIC_SPI; 149 - gic_data.args[1] = irq_data->args[0]; 150 - gic_data.args[2] = irq_data->args[1]; 146 + 147 + if (mscm_ir_data->is_nvic) { 148 + gic_data.args_count = 1; 149 + gic_data.args[0] = irq_data->args[0]; 150 + } else { 151 + gic_data.args_count = 3; 152 + gic_data.args[0] = GIC_SPI; 153 + gic_data.args[1] = irq_data->args[0]; 154 + gic_data.args[2] = irq_data->args[1]; 155 + } 156 + 151 157 return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &gic_data); 152 158 } 153 159 ··· 206 198 ret = -ENOMEM; 207 199 goto out_unmap; 208 200 } 201 + 202 + if (of_device_is_compatible(domain->parent->of_node, "arm,armv7m-nvic")) 203 + mscm_ir_data->is_nvic = true; 209 204 210 205 cpu_pm_register_notifier(&mscm_ir_notifier_block); 211 206
+2
include/linux/irq.h
··· 458 458 459 459 extern int irq_chip_compose_msi_msg(struct irq_data *data, struct msi_msg *msg); 460 460 #ifdef CONFIG_IRQ_DOMAIN_HIERARCHY 461 + extern void irq_chip_enable_parent(struct irq_data *data); 462 + extern void irq_chip_disable_parent(struct irq_data *data); 461 463 extern void irq_chip_ack_parent(struct irq_data *data); 462 464 extern int irq_chip_retrigger_hierarchy(struct irq_data *data); 463 465 extern void irq_chip_mask_parent(struct irq_data *data);
+4 -4
include/linux/irqdomain.h
··· 258 258 /* V2 interfaces to support hierarchy IRQ domains. */ 259 259 extern struct irq_data *irq_domain_get_irq_data(struct irq_domain *domain, 260 260 unsigned int virq); 261 + extern void irq_domain_set_info(struct irq_domain *domain, unsigned int virq, 262 + irq_hw_number_t hwirq, struct irq_chip *chip, 263 + void *chip_data, irq_flow_handler_t handler, 264 + void *handler_data, const char *handler_name); 261 265 #ifdef CONFIG_IRQ_DOMAIN_HIERARCHY 262 266 extern struct irq_domain *irq_domain_add_hierarchy(struct irq_domain *parent, 263 267 unsigned int flags, unsigned int size, ··· 285 281 irq_hw_number_t hwirq, 286 282 struct irq_chip *chip, 287 283 void *chip_data); 288 - extern void irq_domain_set_info(struct irq_domain *domain, unsigned int virq, 289 - irq_hw_number_t hwirq, struct irq_chip *chip, 290 - void *chip_data, irq_flow_handler_t handler, 291 - void *handler_data, const char *handler_name); 292 284 extern void irq_domain_reset_irq_data(struct irq_data *irq_data); 293 285 extern void irq_domain_free_irqs_common(struct irq_domain *domain, 294 286 unsigned int virq,
+28
kernel/irq/chip.c
··· 876 876 877 877 #ifdef CONFIG_IRQ_DOMAIN_HIERARCHY 878 878 /** 879 + * irq_chip_enable_parent - Enable the parent interrupt (defaults to unmask if 880 + * NULL) 881 + * @data: Pointer to interrupt specific data 882 + */ 883 + void irq_chip_enable_parent(struct irq_data *data) 884 + { 885 + data = data->parent_data; 886 + if (data->chip->irq_enable) 887 + data->chip->irq_enable(data); 888 + else 889 + data->chip->irq_unmask(data); 890 + } 891 + 892 + /** 893 + * irq_chip_disable_parent - Disable the parent interrupt (defaults to mask if 894 + * NULL) 895 + * @data: Pointer to interrupt specific data 896 + */ 897 + void irq_chip_disable_parent(struct irq_data *data) 898 + { 899 + data = data->parent_data; 900 + if (data->chip->irq_disable) 901 + data->chip->irq_disable(data); 902 + else 903 + data->chip->irq_mask(data); 904 + } 905 + 906 + /** 879 907 * irq_chip_ack_parent - Acknowledge the parent interrupt 880 908 * @data: Pointer to interrupt specific data 881 909 */
+2 -3
kernel/irq/generic-chip.c
··· 360 360 int irq_map_generic_chip(struct irq_domain *d, unsigned int virq, 361 361 irq_hw_number_t hw_irq) 362 362 { 363 - struct irq_data *data = irq_get_irq_data(virq); 363 + struct irq_data *data = irq_domain_get_irq_data(d, virq); 364 364 struct irq_domain_chip_generic *dgc = d->gc; 365 365 struct irq_chip_generic *gc; 366 366 struct irq_chip_type *ct; ··· 405 405 else 406 406 data->mask = 1 << idx; 407 407 408 - irq_set_chip_and_handler(virq, chip, ct->handler); 409 - irq_set_chip_data(virq, gc); 408 + irq_domain_set_info(d, virq, hw_irq, chip, gc, ct->handler, NULL, NULL); 410 409 irq_modify_status(virq, dgc->irq_flags_to_clear, dgc->irq_flags_to_set); 411 410 return 0; 412 411 }
+21
kernel/irq/irqdomain.c
··· 1232 1232 return (irq_data && irq_data->domain == domain) ? irq_data : NULL; 1233 1233 } 1234 1234 1235 + /** 1236 + * irq_domain_set_info - Set the complete data for a @virq in @domain 1237 + * @domain: Interrupt domain to match 1238 + * @virq: IRQ number 1239 + * @hwirq: The hardware interrupt number 1240 + * @chip: The associated interrupt chip 1241 + * @chip_data: The associated interrupt chip data 1242 + * @handler: The interrupt flow handler 1243 + * @handler_data: The interrupt flow handler data 1244 + * @handler_name: The interrupt handler name 1245 + */ 1246 + void irq_domain_set_info(struct irq_domain *domain, unsigned int virq, 1247 + irq_hw_number_t hwirq, struct irq_chip *chip, 1248 + void *chip_data, irq_flow_handler_t handler, 1249 + void *handler_data, const char *handler_name) 1250 + { 1251 + irq_set_chip_and_handler_name(virq, chip, handler, handler_name); 1252 + irq_set_chip_data(virq, chip_data); 1253 + irq_set_handler_data(virq, handler_data); 1254 + } 1255 + 1235 1256 static void irq_domain_check_hierarchy(struct irq_domain *domain) 1236 1257 { 1237 1258 }