LCOV - code coverage report
Current view: top level - drivers/irqchip - irq-bcm2835.c (source / functions) Hit Total Coverage
Test: gcov_data_raspi2_real_modules_combined.info Lines: 78 97 80.4 %
Date: 2020-09-30 20:25:40 Functions: 7 9 77.8 %
Branches: 47 74 63.5 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0+
       2                 :            : /*
       3                 :            :  * Copyright 2010 Broadcom
       4                 :            :  * Copyright 2012 Simon Arlott, Chris Boot, Stephen Warren
       5                 :            :  *
       6                 :            :  * Quirk 1: Shortcut interrupts don't set the bank 1/2 register pending bits
       7                 :            :  *
       8                 :            :  * If an interrupt fires on bank 1 that isn't in the shortcuts list, bit 8
       9                 :            :  * on bank 0 is set to signify that an interrupt in bank 1 has fired, and
      10                 :            :  * to look in the bank 1 status register for more information.
      11                 :            :  *
      12                 :            :  * If an interrupt fires on bank 1 that _is_ in the shortcuts list, its
      13                 :            :  * shortcut bit in bank 0 is set as well as its interrupt bit in the bank 1
      14                 :            :  * status register, but bank 0 bit 8 is _not_ set.
      15                 :            :  *
      16                 :            :  * Quirk 2: You can't mask the register 1/2 pending interrupts
      17                 :            :  *
      18                 :            :  * In a proper cascaded interrupt controller, the interrupt lines with
      19                 :            :  * cascaded interrupt controllers on them are just normal interrupt lines.
      20                 :            :  * You can mask the interrupts and get on with things. With this controller
      21                 :            :  * you can't do that.
      22                 :            :  *
      23                 :            :  * Quirk 3: The shortcut interrupts can't be (un)masked in bank 0
      24                 :            :  *
      25                 :            :  * Those interrupts that have shortcuts can only be masked/unmasked in
      26                 :            :  * their respective banks' enable/disable registers. Doing so in the bank 0
      27                 :            :  * enable/disable registers has no effect.
      28                 :            :  *
      29                 :            :  * The FIQ control register:
      30                 :            :  *  Bits 0-6: IRQ (index in order of interrupts from banks 1, 2, then 0)
      31                 :            :  *  Bit    7: Enable FIQ generation
      32                 :            :  *  Bits  8+: Unused
      33                 :            :  *
      34                 :            :  * An interrupt must be disabled before configuring it for FIQ generation
      35                 :            :  * otherwise both handlers will fire at the same time!
      36                 :            :  */
      37                 :            : 
      38                 :            : #include <linux/io.h>
      39                 :            : #include <linux/slab.h>
      40                 :            : #include <linux/of_address.h>
      41                 :            : #include <linux/of_irq.h>
      42                 :            : #include <linux/irqchip.h>
      43                 :            : #include <linux/irqdomain.h>
      44                 :            : 
      45                 :            : #include <asm/exception.h>
      46                 :            : #ifndef CONFIG_ARM64
      47                 :            : #include <asm/mach/irq.h>
      48                 :            : #endif
      49                 :            : 
      50                 :            : /* Put the bank and irq (32 bits) into the hwirq */
      51                 :            : #define MAKE_HWIRQ(b, n)        (((b) << 5) | (n))
      52                 :            : #define HWIRQ_BANK(i)           (i >> 5)
      53                 :            : #define HWIRQ_BIT(i)            BIT(i & 0x1f)
      54                 :            : 
      55                 :            : #define NR_IRQS_BANK0           8
      56                 :            : #define BANK0_HWIRQ_MASK        0xff
      57                 :            : /* Shortcuts can't be disabled so any unknown new ones need to be masked */
      58                 :            : #define SHORTCUT1_MASK          0x00007c00
      59                 :            : #define SHORTCUT2_MASK          0x001f8000
      60                 :            : #define SHORTCUT_SHIFT          10
      61                 :            : #define BANK1_HWIRQ             BIT(8)
      62                 :            : #define BANK2_HWIRQ             BIT(9)
      63                 :            : #define BANK0_VALID_MASK        (BANK0_HWIRQ_MASK | BANK1_HWIRQ | BANK2_HWIRQ \
      64                 :            :                                         | SHORTCUT1_MASK | SHORTCUT2_MASK)
      65                 :            : 
      66                 :            : #undef ARM_LOCAL_GPU_INT_ROUTING
      67                 :            : #define ARM_LOCAL_GPU_INT_ROUTING 0x0c
      68                 :            : 
      69                 :            : #define REG_FIQ_CONTROL         0x0c
      70                 :            : #define FIQ_CONTROL_ENABLE      BIT(7)
      71                 :            : 
      72                 :            : #define NR_BANKS                3
      73                 :            : #define IRQS_PER_BANK           32
      74                 :            : #define NUMBER_IRQS             MAKE_HWIRQ(NR_BANKS, 0)
      75                 :            : 
      76                 :            : static const int reg_pending[] __initconst = { 0x00, 0x04, 0x08 };
      77                 :            : static const int reg_enable[] __initconst = { 0x18, 0x10, 0x14 };
      78                 :            : static const int reg_disable[] __initconst = { 0x24, 0x1c, 0x20 };
      79                 :            : static const int bank_irqs[] __initconst = { 8, 32, 32 };
      80                 :            : 
      81                 :            : static const int shortcuts[] = {
      82                 :            :         7, 9, 10, 18, 19,               /* Bank 1 */
      83                 :            :         21, 22, 23, 24, 25, 30          /* Bank 2 */
      84                 :            : };
      85                 :            : 
      86                 :            : struct armctrl_ic {
      87                 :            :         void __iomem *base;
      88                 :            :         void __iomem *pending[NR_BANKS];
      89                 :            :         void __iomem *enable[NR_BANKS];
      90                 :            :         void __iomem *disable[NR_BANKS];
      91                 :            :         struct irq_domain *domain;
      92                 :            :         void __iomem *local_base;
      93                 :            : };
      94                 :            : 
      95                 :            : static struct armctrl_ic intc __read_mostly;
      96                 :            : static void __exception_irq_entry bcm2835_handle_irq(
      97                 :            :         struct pt_regs *regs);
      98                 :            : static void bcm2836_chained_handle_irq(struct irq_desc *desc);
      99                 :            : 
     100                 :            : static inline unsigned int hwirq_to_fiq(unsigned long hwirq)
     101                 :            : {
     102                 :        207 :         hwirq -= NUMBER_IRQS;
     103                 :            :         /*
     104                 :            :          * The hwirq numbering used in this driver is:
     105                 :            :          *   BASE (0-7) GPU1 (32-63) GPU2 (64-95).
     106                 :            :          * This differ from the one used in the FIQ register:
     107                 :            :          *   GPU1 (0-31) GPU2 (32-63) BASE (64-71)
     108                 :            :          */
     109         [ +  - ]:        207 :         if (hwirq >= 32)
     110                 :        207 :                 return hwirq - 32;
     111                 :            : 
     112                 :          0 :         return hwirq + 64;
     113                 :            : }
     114                 :            : 
     115                 :   14139930 : static void armctrl_mask_irq(struct irq_data *d)
     116                 :            : {
     117         [ -  + ]:   14139930 :         if (d->hwirq >= NUMBER_IRQS)
     118                 :          0 :                 writel_relaxed(0, intc.base + REG_FIQ_CONTROL);
     119                 :            :         else
     120                 :   14139930 :                 writel_relaxed(HWIRQ_BIT(d->hwirq),
     121                 :            :                                intc.disable[HWIRQ_BANK(d->hwirq)]);
     122                 :   14139930 : }
     123                 :            : 
     124                 :   14141991 : static void armctrl_unmask_irq(struct irq_data *d)
     125                 :            : {
     126         [ +  + ]:   14141991 :         if (d->hwirq >= NUMBER_IRQS) {
     127         [ +  - ]:        207 :                 if (num_online_cpus() > 1) {
     128                 :            :                         unsigned int data;
     129                 :            : 
     130         [ -  + ]:        207 :                         if (!intc.local_base) {
     131                 :          0 :                                 pr_err("FIQ is disabled due to missing arm_local_intc\n");
     132                 :   14141991 :                                 return;
     133                 :            :                         }
     134                 :            : 
     135                 :        207 :                         data = readl_relaxed(intc.local_base +
     136                 :            :                                              ARM_LOCAL_GPU_INT_ROUTING);
     137                 :            : 
     138                 :        207 :                         data &= ~0xc;
     139                 :        207 :                         data |= (1 << 2);
     140                 :            :                         writel_relaxed(data,
     141                 :            :                                        intc.local_base +
     142                 :            :                                        ARM_LOCAL_GPU_INT_ROUTING);
     143                 :            :                 }
     144                 :            : 
     145                 :        207 :                 writel_relaxed(FIQ_CONTROL_ENABLE | hwirq_to_fiq(d->hwirq),
     146                 :            :                                intc.base + REG_FIQ_CONTROL);
     147                 :            :         } else {
     148                 :   14141784 :                 writel_relaxed(HWIRQ_BIT(d->hwirq),
     149                 :            :                                intc.enable[HWIRQ_BANK(d->hwirq)]);
     150                 :            :         }
     151                 :            : }
     152                 :            : 
     153                 :            : #ifdef CONFIG_ARM64
     154                 :            : void bcm2836_arm_irqchip_spin_gpu_irq(void);
     155                 :            : 
     156                 :            : static void armctrl_ack_irq(struct irq_data *d)
     157                 :            : {
     158                 :            :         bcm2836_arm_irqchip_spin_gpu_irq();
     159                 :            : }
     160                 :            : 
     161                 :            : #endif
     162                 :            : 
     163                 :            : static struct irq_chip armctrl_chip = {
     164                 :            :         .name = "ARMCTRL-level",
     165                 :            :         .irq_mask = armctrl_mask_irq,
     166                 :            :         .irq_unmask = armctrl_unmask_irq,
     167                 :            : #ifdef CONFIG_ARM64
     168                 :            :         .irq_ack    = armctrl_ack_irq
     169                 :            : #endif
     170                 :            : };
     171                 :            : 
     172                 :       8694 : static int armctrl_xlate(struct irq_domain *d, struct device_node *ctrlr,
     173                 :            :         const u32 *intspec, unsigned int intsize,
     174                 :            :         unsigned long *out_hwirq, unsigned int *out_type)
     175                 :            : {
     176   [ -  +  +  - ]:       8694 :         if (WARN_ON(intsize != 2))
     177                 :            :                 return -EINVAL;
     178                 :            : 
     179   [ -  +  +  - ]:       8694 :         if (WARN_ON(intspec[0] >= NR_BANKS))
     180                 :            :                 return -EINVAL;
     181                 :            : 
     182   [ -  +  +  - ]:       8694 :         if (WARN_ON(intspec[1] >= IRQS_PER_BANK))
     183                 :            :                 return -EINVAL;
     184                 :            : 
     185   [ +  +  +  -  :       8694 :         if (WARN_ON(intspec[0] == 0 && intspec[1] >= NR_IRQS_BANK0))
             -  +  +  - ]
     186                 :            :                 return -EINVAL;
     187                 :            : 
     188                 :       8694 :         *out_hwirq = MAKE_HWIRQ(intspec[0], intspec[1]);
     189                 :       8694 :         *out_type = IRQ_TYPE_NONE;
     190                 :       8694 :         return 0;
     191                 :            : }
     192                 :            : 
     193                 :            : static const struct irq_domain_ops armctrl_ops = {
     194                 :            :         .xlate = armctrl_xlate
     195                 :            : };
     196                 :            : 
     197                 :        207 : static int __init armctrl_of_init(struct device_node *node,
     198                 :            :                                   struct device_node *parent,
     199                 :            :                                   bool is_2836)
     200                 :            : {
     201                 :            :         void __iomem *base;
     202                 :            :         int irq = 0, last_irq, b, i;
     203                 :            :         u32 reg;
     204                 :            : 
     205                 :        207 :         base = of_iomap(node, 0);
     206         [ -  + ]:        207 :         if (!base)
     207                 :          0 :                 panic("%pOF: unable to map IC registers\n", node);
     208                 :            : 
     209                 :        207 :         intc.base = base;
     210                 :        207 :         intc.domain = irq_domain_add_linear(node, NUMBER_IRQS * 2,
     211                 :            :                                             &armctrl_ops, NULL);
     212         [ +  - ]:        207 :         if (!intc.domain)
     213                 :          0 :                 panic("%pOF: unable to create IRQ domain\n", node);
     214                 :            : 
     215         [ +  + ]:        621 :         for (b = 0; b < NR_BANKS; b++) {
     216                 :        621 :                 intc.pending[b] = base + reg_pending[b];
     217                 :        621 :                 intc.enable[b] = base + reg_enable[b];
     218                 :        621 :                 intc.disable[b] = base + reg_disable[b];
     219                 :            : 
     220         [ +  + ]:      15525 :                 for (i = 0; i < bank_irqs[b]; i++) {
     221                 :      14904 :                         irq = irq_create_mapping(intc.domain, MAKE_HWIRQ(b, i));
     222         [ -  + ]:      14904 :                         BUG_ON(irq <= 0);
     223                 :            :                         irq_set_chip_and_handler(irq, &armctrl_chip,
     224                 :            :                                 handle_level_irq);
     225                 :            :                         irq_set_probe(irq);
     226                 :            :                 }
     227                 :            : 
     228                 :       1242 :                 reg = readl_relaxed(intc.enable[b]);
     229         [ -  + ]:        621 :                 if (reg) {
     230                 :          0 :                         writel_relaxed(reg, intc.disable[b]);
     231                 :          0 :                         pr_err(FW_BUG "Bootloader left irq enabled: "
     232                 :            :                                "bank %d irq %*pbl\n", b, IRQS_PER_BANK, &reg);
     233                 :            :                 }
     234                 :            :         }
     235                 :            : 
     236                 :        414 :         reg = readl_relaxed(base + REG_FIQ_CONTROL);
     237         [ -  + ]:        207 :         if (reg & FIQ_CONTROL_ENABLE) {
     238                 :            :                 writel_relaxed(0, base + REG_FIQ_CONTROL);
     239                 :          0 :                 pr_err(FW_BUG "Bootloader left fiq enabled\n");
     240                 :            :         }
     241                 :            : 
     242                 :        207 :         last_irq = irq;
     243                 :            : 
     244         [ +  - ]:        207 :         if (is_2836) {
     245                 :        207 :                 int parent_irq = irq_of_parse_and_map(node, 0);
     246                 :            : 
     247         [ -  + ]:        207 :                 if (!parent_irq) {
     248                 :          0 :                         panic("%pOF: unable to get parent interrupt.\n",
     249                 :            :                               node);
     250                 :            :                 }
     251                 :            :                 irq_set_chained_handler(parent_irq, bcm2836_chained_handle_irq);
     252                 :            :         } else {
     253                 :          0 :                 set_handle_irq(bcm2835_handle_irq);
     254                 :            :         }
     255                 :            : 
     256         [ +  - ]:        207 :         if (is_2836) {
     257                 :            :                 extern void __iomem * __attribute__((weak)) arm_local_intc;
     258                 :        207 :                 intc.local_base = arm_local_intc;
     259         [ -  + ]:        207 :                 if (!intc.local_base)
     260                 :          0 :                         pr_err("Failed to get local intc base. FIQ is disabled for cpus > 1\n");
     261                 :            :         }
     262                 :            : 
     263                 :            :         /* Make a duplicate irq range which is used to enable FIQ */
     264         [ +  + ]:        621 :         for (b = 0; b < NR_BANKS; b++) {
     265         [ +  + ]:      14904 :                 for (i = 0; i < bank_irqs[b]; i++) {
     266                 :      29808 :                         irq = irq_create_mapping(intc.domain,
     267                 :      14904 :                                         MAKE_HWIRQ(b, i) + NUMBER_IRQS);
     268         [ -  + ]:      14904 :                         BUG_ON(irq <= 0);
     269                 :      14904 :                         irq_set_chip(irq, &armctrl_chip);
     270                 :            :                         irq_set_probe(irq);
     271                 :            :                 }
     272                 :            :         }
     273                 :            : #ifndef CONFIG_ARM64
     274                 :        207 :         init_FIQ(irq - last_irq);
     275                 :            : #endif
     276                 :            : 
     277                 :        207 :         return 0;
     278                 :            : }
     279                 :            : 
     280                 :          0 : static int __init bcm2835_armctrl_of_init(struct device_node *node,
     281                 :            :                                           struct device_node *parent)
     282                 :            : {
     283                 :          0 :         return armctrl_of_init(node, parent, false);
     284                 :            : }
     285                 :            : 
     286                 :        207 : static int __init bcm2836_armctrl_of_init(struct device_node *node,
     287                 :            :                                           struct device_node *parent)
     288                 :            : {
     289                 :        207 :         return armctrl_of_init(node, parent, true);
     290                 :            : }
     291                 :            : 
     292                 :            : 
     293                 :            : /*
     294                 :            :  * Handle each interrupt across the entire interrupt controller.  This reads the
     295                 :            :  * status register before handling each interrupt, which is necessary given that
     296                 :            :  * handle_IRQ may briefly re-enable interrupts for soft IRQ handling.
     297                 :            :  */
     298                 :            : 
     299                 :            : static u32 armctrl_translate_bank(int bank)
     300                 :            : {
     301                 :   12881571 :         u32 stat = readl_relaxed(intc.pending[bank]);
     302                 :            : 
     303                 :   25763142 :         return MAKE_HWIRQ(bank, ffs(stat) - 1);
     304                 :            : }
     305                 :            : 
     306                 :            : static u32 armctrl_translate_shortcut(int bank, u32 stat)
     307                 :            : {
     308                 :    2374218 :         return MAKE_HWIRQ(bank, shortcuts[ffs(stat >> SHORTCUT_SHIFT) - 1]);
     309                 :            : }
     310                 :            : 
     311                 :   28073178 : static u32 get_next_armctrl_hwirq(void)
     312                 :            : {
     313                 :   56146356 :         u32 stat = readl_relaxed(intc.pending[0]) & BANK0_VALID_MASK;
     314                 :            : 
     315         [ +  + ]:   28073178 :         if (stat == 0)
     316                 :            :                 return ~0;
     317         [ +  + ]:   14139500 :         else if (stat & BANK0_HWIRQ_MASK)
     318                 :     141640 :                 return MAKE_HWIRQ(0, ffs(stat & BANK0_HWIRQ_MASK) - 1);
     319         [ +  + ]:   14068680 :         else if (stat & SHORTCUT1_MASK)
     320                 :    1038053 :                 return armctrl_translate_shortcut(1, stat & SHORTCUT1_MASK);
     321         [ +  + ]:   13030627 :         else if (stat & SHORTCUT2_MASK)
     322                 :     149056 :                 return armctrl_translate_shortcut(2, stat & SHORTCUT2_MASK);
     323         [ -  + ]:   12881571 :         else if (stat & BANK1_HWIRQ)
     324                 :          0 :                 return armctrl_translate_bank(1);
     325         [ +  - ]:   12881571 :         else if (stat & BANK2_HWIRQ)
     326                 :   12881571 :                 return armctrl_translate_bank(2);
     327                 :            :         else
     328                 :          0 :                 BUG();
     329                 :            : }
     330                 :            : 
     331                 :          0 : static void __exception_irq_entry bcm2835_handle_irq(
     332                 :            :         struct pt_regs *regs)
     333                 :            : {
     334                 :            :         u32 hwirq;
     335                 :            : 
     336         [ #  # ]:          0 :         while ((hwirq = get_next_armctrl_hwirq()) != ~0)
     337                 :          0 :                 handle_domain_irq(intc.domain, hwirq, regs);
     338                 :          0 : }
     339                 :            : 
     340                 :   13933675 : static void bcm2836_chained_handle_irq(struct irq_desc *desc)
     341                 :            : {
     342                 :            :         u32 hwirq;
     343                 :            : 
     344         [ +  + ]:   42006839 :         while ((hwirq = get_next_armctrl_hwirq()) != ~0)
     345                 :   28278984 :                 generic_handle_irq(irq_linear_revmap(intc.domain, hwirq));
     346                 :   13933672 : }
     347                 :            : 
     348                 :            : IRQCHIP_DECLARE(bcm2835_armctrl_ic, "brcm,bcm2835-armctrl-ic",
     349                 :            :                 bcm2835_armctrl_of_init);
     350                 :            : IRQCHIP_DECLARE(bcm2836_armctrl_ic, "brcm,bcm2836-armctrl-ic",
     351                 :            :                 bcm2836_armctrl_of_init);

Generated by: LCOV version 1.14