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

irqchip/irq-bcm7038-l1: Support brcm,int-fwd-mask

On some specific chips like 7211 we need to leave some interrupts
untouched/forwarded to the VPU which is another agent in the system
making use of that interrupt controller hardware (goes to both ARM GIC
and VPU L1 interrupt controller). Make that possible by using the
existing brcm,int-fwd-mask property and take necessary actions to avoid
masking that interrupt as well as not allowing Linux to map them.

Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: Marc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20191024201415.23454-6-f.fainelli@gmail.com

authored by

Florian Fainelli and committed by
Marc Zyngier
96de80c1 e14b5e5f

+26 -4
+26 -4
drivers/irqchip/irq-bcm7038-l1.c
··· 44 44 struct list_head list; 45 45 u32 wake_mask[MAX_WORDS]; 46 46 #endif 47 + u32 irq_fwd_mask[MAX_WORDS]; 47 48 u8 affinity[MAX_WORDS * IRQS_PER_WORD]; 48 49 }; 49 50 ··· 255 254 resource_size_t sz; 256 255 struct bcm7038_l1_cpu *cpu; 257 256 unsigned int i, n_words, parent_irq; 257 + int ret; 258 258 259 259 if (of_address_to_resource(dn, idx, &res)) 260 260 return -EINVAL; ··· 269 267 else if (intc->n_words != n_words) 270 268 return -EINVAL; 271 269 270 + ret = of_property_read_u32_array(dn , "brcm,int-fwd-mask", 271 + intc->irq_fwd_mask, n_words); 272 + if (ret != 0 && ret != -EINVAL) { 273 + /* property exists but has the wrong number of words */ 274 + pr_err("invalid brcm,int-fwd-mask property\n"); 275 + return -EINVAL; 276 + } 277 + 272 278 cpu = intc->cpus[idx] = kzalloc(sizeof(*cpu) + n_words * sizeof(u32), 273 279 GFP_KERNEL); 274 280 if (!cpu) ··· 287 277 return -ENOMEM; 288 278 289 279 for (i = 0; i < n_words; i++) { 290 - l1_writel(0xffffffff, cpu->map_base + reg_mask_set(intc, i)); 291 - cpu->mask_cache[i] = 0xffffffff; 280 + l1_writel(~intc->irq_fwd_mask[i], 281 + cpu->map_base + reg_mask_set(intc, i)); 282 + l1_writel(intc->irq_fwd_mask[i], 283 + cpu->map_base + reg_mask_clr(intc, i)); 284 + cpu->mask_cache[i] = ~intc->irq_fwd_mask[i]; 292 285 } 293 286 294 287 parent_irq = irq_of_parse_and_map(dn, idx); ··· 324 311 { 325 312 struct bcm7038_l1_chip *intc; 326 313 int boot_cpu, word; 314 + u32 val; 327 315 328 316 /* Wakeup interrupt should only come from the boot cpu */ 329 317 boot_cpu = cpu_logical_map(0); 330 318 331 319 list_for_each_entry(intc, &bcm7038_l1_intcs_list, list) { 332 320 for (word = 0; word < intc->n_words; word++) { 333 - l1_writel(~intc->wake_mask[word], 321 + val = intc->wake_mask[word] | intc->irq_fwd_mask[word]; 322 + l1_writel(~val, 334 323 intc->cpus[boot_cpu]->map_base + reg_mask_set(intc, word)); 335 - l1_writel(intc->wake_mask[word], 324 + l1_writel(val, 336 325 intc->cpus[boot_cpu]->map_base + reg_mask_clr(intc, word)); 337 326 } 338 327 } ··· 398 383 static int bcm7038_l1_map(struct irq_domain *d, unsigned int virq, 399 384 irq_hw_number_t hw_irq) 400 385 { 386 + struct bcm7038_l1_chip *intc = d->host_data; 387 + u32 mask = BIT(hw_irq % IRQS_PER_WORD); 388 + u32 word = hw_irq / IRQS_PER_WORD; 389 + 390 + if (intc->irq_fwd_mask[word] & mask) 391 + return -EPERM; 392 + 401 393 irq_set_chip_and_handler(virq, &bcm7038_l1_irq_chip, handle_level_irq); 402 394 irq_set_chip_data(virq, d->host_data); 403 395 irqd_set_single_target(irq_desc_get_irq_data(irq_to_desc(virq)));