LCOV - code coverage report
Current view: top level - drivers/of - irq.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 138 0.0 %
Date: 2014-02-18 Functions: 0 8 0.0 %
Branches: 0 128 0.0 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  *  Derived from arch/i386/kernel/irq.c
       3                 :            :  *    Copyright (C) 1992 Linus Torvalds
       4                 :            :  *  Adapted from arch/i386 by Gary Thomas
       5                 :            :  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
       6                 :            :  *  Updated and modified by Cort Dougan <cort@fsmlabs.com>
       7                 :            :  *    Copyright (C) 1996-2001 Cort Dougan
       8                 :            :  *  Adapted for Power Macintosh by Paul Mackerras
       9                 :            :  *    Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au)
      10                 :            :  *
      11                 :            :  * This program is free software; you can redistribute it and/or
      12                 :            :  * modify it under the terms of the GNU General Public License
      13                 :            :  * as published by the Free Software Foundation; either version
      14                 :            :  * 2 of the License, or (at your option) any later version.
      15                 :            :  *
      16                 :            :  * This file contains the code used to make IRQ descriptions in the
      17                 :            :  * device tree to actual irq numbers on an interrupt controller
      18                 :            :  * driver.
      19                 :            :  */
      20                 :            : 
      21                 :            : #include <linux/errno.h>
      22                 :            : #include <linux/list.h>
      23                 :            : #include <linux/module.h>
      24                 :            : #include <linux/of.h>
      25                 :            : #include <linux/of_irq.h>
      26                 :            : #include <linux/string.h>
      27                 :            : #include <linux/slab.h>
      28                 :            : 
      29                 :            : /**
      30                 :            :  * irq_of_parse_and_map - Parse and map an interrupt into linux virq space
      31                 :            :  * @dev: Device node of the device whose interrupt is to be mapped
      32                 :            :  * @index: Index of the interrupt to map
      33                 :            :  *
      34                 :            :  * This function is a wrapper that chains of_irq_parse_one() and
      35                 :            :  * irq_create_of_mapping() to make things easier to callers
      36                 :            :  */
      37                 :          0 : unsigned int irq_of_parse_and_map(struct device_node *dev, int index)
      38                 :            : {
      39                 :            :         struct of_phandle_args oirq;
      40                 :            : 
      41         [ #  # ]:          0 :         if (of_irq_parse_one(dev, index, &oirq))
      42                 :            :                 return 0;
      43                 :            : 
      44                 :          0 :         return irq_create_of_mapping(&oirq);
      45                 :            : }
      46                 :            : EXPORT_SYMBOL_GPL(irq_of_parse_and_map);
      47                 :            : 
      48                 :            : /**
      49                 :            :  * of_irq_find_parent - Given a device node, find its interrupt parent node
      50                 :            :  * @child: pointer to device node
      51                 :            :  *
      52                 :            :  * Returns a pointer to the interrupt parent node, or NULL if the interrupt
      53                 :            :  * parent could not be determined.
      54                 :            :  */
      55                 :          0 : struct device_node *of_irq_find_parent(struct device_node *child)
      56                 :            : {
      57                 :            :         struct device_node *p;
      58                 :          0 :         const __be32 *parp;
      59                 :            : 
      60         [ #  # ]:          0 :         if (!of_node_get(child))
      61                 :            :                 return NULL;
      62                 :            : 
      63                 :            :         do {
      64                 :          0 :                 parp = of_get_property(child, "interrupt-parent", NULL);
      65         [ #  # ]:          0 :                 if (parp == NULL)
      66                 :          0 :                         p = of_get_parent(child);
      67                 :            :                 else {
      68                 :            :                         if (of_irq_workarounds & OF_IMAP_NO_PHANDLE)
      69                 :            :                                 p = of_node_get(of_irq_dflt_pic);
      70                 :            :                         else
      71                 :          0 :                                 p = of_find_node_by_phandle(be32_to_cpup(parp));
      72                 :            :                 }
      73                 :            :                 of_node_put(child);
      74                 :            :                 child = p;
      75 [ #  # ][ #  # ]:          0 :         } while (p && of_get_property(p, "#interrupt-cells", NULL) == NULL);
      76                 :            : 
      77                 :          0 :         return p;
      78                 :            : }
      79                 :            : 
      80                 :            : /**
      81                 :            :  * of_irq_parse_raw - Low level interrupt tree parsing
      82                 :            :  * @parent:     the device interrupt parent
      83                 :            :  * @addr:       address specifier (start of "reg" property of the device) in be32 format
      84                 :            :  * @out_irq:    structure of_irq updated by this function
      85                 :            :  *
      86                 :            :  * Returns 0 on success and a negative number on error
      87                 :            :  *
      88                 :            :  * This function is a low-level interrupt tree walking function. It
      89                 :            :  * can be used to do a partial walk with synthetized reg and interrupts
      90                 :            :  * properties, for example when resolving PCI interrupts when no device
      91                 :            :  * node exist for the parent. It takes an interrupt specifier structure as
      92                 :            :  * input, walks the tree looking for any interrupt-map properties, translates
      93                 :            :  * the specifier for each map, and then returns the translated map.
      94                 :            :  */
      95                 :          0 : int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
      96                 :            : {
      97                 :            :         struct device_node *ipar, *tnode, *old = NULL, *newpar = NULL;
      98                 :            :         __be32 initial_match_array[MAX_PHANDLE_ARGS];
      99                 :            :         const __be32 *match_array = initial_match_array;
     100                 :          0 :         const __be32 *tmp, *imap, *imask, dummy_imask[] = { [0 ... MAX_PHANDLE_ARGS] = ~0 };
     101                 :            :         u32 intsize = 1, addrsize, newintsize = 0, newaddrsize = 0;
     102                 :            :         int imaplen, match, i;
     103                 :            : 
     104                 :            : #ifdef DEBUG
     105                 :            :         of_print_phandle_args("of_irq_parse_raw: ", out_irq);
     106                 :            : #endif
     107                 :            : 
     108                 :          0 :         ipar = of_node_get(out_irq->np);
     109                 :            : 
     110                 :            :         /* First get the #interrupt-cells property of the current cursor
     111                 :            :          * that tells us how to interpret the passed-in intspec. If there
     112                 :            :          * is none, we are nice and just walk up the tree
     113                 :            :          */
     114                 :            :         do {
     115                 :          0 :                 tmp = of_get_property(ipar, "#interrupt-cells", NULL);
     116         [ #  # ]:          0 :                 if (tmp != NULL) {
     117         [ #  # ]:          0 :                         intsize = be32_to_cpu(*tmp);
     118                 :          0 :                         break;
     119                 :            :                 }
     120                 :            :                 tnode = ipar;
     121                 :          0 :                 ipar = of_irq_find_parent(ipar);
     122                 :            :                 of_node_put(tnode);
     123         [ #  # ]:          0 :         } while (ipar);
     124         [ #  # ]:          0 :         if (ipar == NULL) {
     125                 :            :                 pr_debug(" -> no parent found !\n");
     126                 :            :                 goto fail;
     127                 :            :         }
     128                 :            : 
     129                 :            :         pr_debug("of_irq_parse_raw: ipar=%s, size=%d\n", of_node_full_name(ipar), intsize);
     130                 :            : 
     131         [ #  # ]:          0 :         if (out_irq->args_count != intsize)
     132                 :            :                 return -EINVAL;
     133                 :            : 
     134                 :            :         /* Look for this #address-cells. We have to implement the old linux
     135                 :            :          * trick of looking for the parent here as some device-trees rely on it
     136                 :            :          */
     137                 :            :         old = of_node_get(ipar);
     138                 :            :         do {
     139                 :          0 :                 tmp = of_get_property(old, "#address-cells", NULL);
     140                 :          0 :                 tnode = of_get_parent(old);
     141                 :            :                 of_node_put(old);
     142                 :            :                 old = tnode;
     143         [ #  # ]:          0 :         } while (old && tmp == NULL);
     144                 :            :         of_node_put(old);
     145                 :            :         old = NULL;
     146 [ #  # ][ #  # ]:          0 :         addrsize = (tmp == NULL) ? 2 : be32_to_cpu(*tmp);
     147                 :            : 
     148                 :            :         pr_debug(" -> addrsize=%d\n", addrsize);
     149                 :            : 
     150                 :            :         /* Range check so that the temporary buffer doesn't overflow */
     151 [ #  # ][ #  # ]:          0 :         if (WARN_ON(addrsize + intsize > MAX_PHANDLE_ARGS))
     152                 :            :                 goto fail;
     153                 :            : 
     154                 :            :         /* Precalculate the match array - this simplifies match loop */
     155         [ #  # ]:          0 :         for (i = 0; i < addrsize; i++)
     156         [ #  # ]:          0 :                 initial_match_array[i] = addr ? addr[i] : 0;
     157         [ #  # ]:          0 :         for (i = 0; i < intsize; i++)
     158         [ #  # ]:          0 :                 initial_match_array[addrsize + i] = cpu_to_be32(out_irq->args[i]);
     159                 :            : 
     160                 :            :         /* Now start the actual "proper" walk of the interrupt tree */
     161         [ #  # ]:          0 :         while (ipar != NULL) {
     162                 :            :                 /* Now check if cursor is an interrupt-controller and if it is
     163                 :            :                  * then we are done
     164                 :            :                  */
     165         [ #  # ]:          0 :                 if (of_get_property(ipar, "interrupt-controller", NULL) !=
     166                 :            :                                 NULL) {
     167                 :            :                         pr_debug(" -> got it !\n");
     168                 :            :                         return 0;
     169                 :            :                 }
     170                 :            : 
     171                 :            :                 /*
     172                 :            :                  * interrupt-map parsing does not work without a reg
     173                 :            :                  * property when #address-cells != 0
     174                 :            :                  */
     175         [ #  # ]:          0 :                 if (addrsize && !addr) {
     176                 :            :                         pr_debug(" -> no reg passed in when needed !\n");
     177                 :            :                         goto fail;
     178                 :            :                 }
     179                 :            : 
     180                 :            :                 /* Now look for an interrupt-map */
     181                 :          0 :                 imap = of_get_property(ipar, "interrupt-map", &imaplen);
     182                 :            :                 /* No interrupt map, check for an interrupt parent */
     183         [ #  # ]:          0 :                 if (imap == NULL) {
     184                 :            :                         pr_debug(" -> no map, getting parent\n");
     185                 :          0 :                         newpar = of_irq_find_parent(ipar);
     186                 :          0 :                         goto skiplevel;
     187                 :            :                 }
     188                 :          0 :                 imaplen /= sizeof(u32);
     189                 :            : 
     190                 :            :                 /* Look for a mask */
     191                 :          0 :                 imask = of_get_property(ipar, "interrupt-map-mask", NULL);
     192         [ #  # ]:          0 :                 if (!imask)
     193                 :            :                         imask = dummy_imask;
     194                 :            : 
     195                 :            :                 /* Parse interrupt-map */
     196                 :            :                 match = 0;
     197 [ #  # ][ #  # ]:          0 :                 while (imaplen > (addrsize + intsize + 1) && !match) {
     198                 :            :                         /* Compare specifiers */
     199                 :            :                         match = 1;
     200         [ #  # ]:          0 :                         for (i = 0; i < (addrsize + intsize); i++, imaplen--)
     201                 :          0 :                                 match &= !((match_array[i] ^ *imap++) & imask[i]);
     202                 :            : 
     203                 :            :                         pr_debug(" -> match=%d (imaplen=%d)\n", match, imaplen);
     204                 :            : 
     205                 :            :                         /* Get the interrupt parent */
     206                 :            :                         if (of_irq_workarounds & OF_IMAP_NO_PHANDLE)
     207                 :            :                                 newpar = of_node_get(of_irq_dflt_pic);
     208                 :            :                         else
     209                 :          0 :                                 newpar = of_find_node_by_phandle(be32_to_cpup(imap));
     210                 :          0 :                         imap++;
     211                 :          0 :                         --imaplen;
     212                 :            : 
     213                 :            :                         /* Check if not found */
     214         [ #  # ]:          0 :                         if (newpar == NULL) {
     215                 :            :                                 pr_debug(" -> imap parent not found !\n");
     216                 :            :                                 goto fail;
     217                 :            :                         }
     218                 :            : 
     219                 :            :                         /* Get #interrupt-cells and #address-cells of new
     220                 :            :                          * parent
     221                 :            :                          */
     222                 :          0 :                         tmp = of_get_property(newpar, "#interrupt-cells", NULL);
     223         [ #  # ]:          0 :                         if (tmp == NULL) {
     224                 :            :                                 pr_debug(" -> parent lacks #interrupt-cells!\n");
     225                 :            :                                 goto fail;
     226                 :            :                         }
     227         [ #  # ]:          0 :                         newintsize = be32_to_cpu(*tmp);
     228                 :          0 :                         tmp = of_get_property(newpar, "#address-cells", NULL);
     229 [ #  # ][ #  # ]:          0 :                         newaddrsize = (tmp == NULL) ? 0 : be32_to_cpu(*tmp);
     230                 :            : 
     231                 :            :                         pr_debug(" -> newintsize=%d, newaddrsize=%d\n",
     232                 :            :                             newintsize, newaddrsize);
     233                 :            : 
     234                 :            :                         /* Check for malformed properties */
     235 [ #  # ][ #  # ]:          0 :                         if (WARN_ON(newaddrsize + newintsize > MAX_PHANDLE_ARGS))
     236                 :            :                                 goto fail;
     237         [ #  # ]:          0 :                         if (imaplen < (newaddrsize + newintsize))
     238                 :            :                                 goto fail;
     239                 :            : 
     240                 :          0 :                         imap += newaddrsize + newintsize;
     241                 :          0 :                         imaplen -= newaddrsize + newintsize;
     242                 :            : 
     243                 :            :                         pr_debug(" -> imaplen=%d\n", imaplen);
     244                 :            :                 }
     245         [ #  # ]:          0 :                 if (!match)
     246                 :            :                         goto fail;
     247                 :            : 
     248                 :            :                 /*
     249                 :            :                  * Successfully parsed an interrrupt-map translation; copy new
     250                 :            :                  * interrupt specifier into the out_irq structure
     251                 :            :                  */
     252                 :          0 :                 out_irq->np = newpar;
     253                 :            : 
     254                 :          0 :                 match_array = imap - newaddrsize - newintsize;
     255         [ #  # ]:          0 :                 for (i = 0; i < newintsize; i++)
     256                 :          0 :                         out_irq->args[i] = be32_to_cpup(imap - newintsize + i);
     257                 :          0 :                 out_irq->args_count = intsize = newintsize;
     258                 :            :                 addrsize = newaddrsize;
     259                 :            : 
     260                 :            :         skiplevel:
     261                 :            :                 /* Iterate again with new parent */
     262                 :            :                 pr_debug(" -> new parent: %s\n", of_node_full_name(newpar));
     263                 :            :                 of_node_put(ipar);
     264                 :            :                 ipar = newpar;
     265                 :            :                 newpar = NULL;
     266                 :            :         }
     267                 :            :  fail:
     268                 :            :         of_node_put(ipar);
     269                 :            :         of_node_put(newpar);
     270                 :            : 
     271                 :            :         return -EINVAL;
     272                 :            : }
     273                 :            : EXPORT_SYMBOL_GPL(of_irq_parse_raw);
     274                 :            : 
     275                 :            : /**
     276                 :            :  * of_irq_parse_one - Resolve an interrupt for a device
     277                 :            :  * @device: the device whose interrupt is to be resolved
     278                 :            :  * @index: index of the interrupt to resolve
     279                 :            :  * @out_irq: structure of_irq filled by this function
     280                 :            :  *
     281                 :            :  * This function resolves an interrupt for a node by walking the interrupt tree,
     282                 :            :  * finding which interrupt controller node it is attached to, and returning the
     283                 :            :  * interrupt specifier that can be used to retrieve a Linux IRQ number.
     284                 :            :  */
     285                 :          0 : int of_irq_parse_one(struct device_node *device, int index, struct of_phandle_args *out_irq)
     286                 :            : {
     287                 :            :         struct device_node *p;
     288                 :          0 :         const __be32 *intspec, *tmp, *addr;
     289                 :            :         u32 intsize, intlen;
     290                 :            :         int i, res = -EINVAL;
     291                 :            : 
     292                 :            :         pr_debug("of_irq_parse_one: dev=%s, index=%d\n", of_node_full_name(device), index);
     293                 :            : 
     294                 :            :         /* OldWorld mac stuff is "special", handle out of line */
     295                 :            :         if (of_irq_workarounds & OF_IMAP_OLDWORLD_MAC)
     296                 :            :                 return of_irq_parse_oldworld(device, index, out_irq);
     297                 :            : 
     298                 :            :         /* Get the reg property (if any) */
     299                 :          0 :         addr = of_get_property(device, "reg", NULL);
     300                 :            : 
     301                 :            :         /* Get the interrupts property */
     302                 :          0 :         intspec = of_get_property(device, "interrupts", &intlen);
     303         [ #  # ]:          0 :         if (intspec == NULL) {
     304                 :            :                 /* Try the new-style interrupts-extended */
     305                 :          0 :                 res = of_parse_phandle_with_args(device, "interrupts-extended",
     306                 :            :                                                 "#interrupt-cells", index, out_irq);
     307         [ #  # ]:          0 :                 if (res)
     308                 :            :                         return -EINVAL;
     309                 :          0 :                 return of_irq_parse_raw(addr, out_irq);
     310                 :            :         }
     311                 :          0 :         intlen /= sizeof(*intspec);
     312                 :            : 
     313                 :            :         pr_debug(" intspec=%d intlen=%d\n", be32_to_cpup(intspec), intlen);
     314                 :            : 
     315                 :            :         /* Look for the interrupt parent. */
     316                 :          0 :         p = of_irq_find_parent(device);
     317         [ #  # ]:          0 :         if (p == NULL)
     318                 :            :                 return -EINVAL;
     319                 :            : 
     320                 :            :         /* Get size of interrupt specifier */
     321                 :          0 :         tmp = of_get_property(p, "#interrupt-cells", NULL);
     322         [ #  # ]:          0 :         if (tmp == NULL)
     323                 :            :                 goto out;
     324         [ #  # ]:          0 :         intsize = be32_to_cpu(*tmp);
     325                 :            : 
     326                 :            :         pr_debug(" intsize=%d intlen=%d\n", intsize, intlen);
     327                 :            : 
     328                 :            :         /* Check index */
     329         [ #  # ]:          0 :         if ((index + 1) * intsize > intlen)
     330                 :            :                 goto out;
     331                 :            : 
     332                 :            :         /* Copy intspec into irq structure */
     333                 :          0 :         intspec += index * intsize;
     334                 :          0 :         out_irq->np = p;
     335                 :          0 :         out_irq->args_count = intsize;
     336         [ #  # ]:          0 :         for (i = 0; i < intsize; i++)
     337                 :          0 :                 out_irq->args[i] = be32_to_cpup(intspec++);
     338                 :            : 
     339                 :            :         /* Check if there are any interrupt-map translations to process */
     340                 :          0 :         res = of_irq_parse_raw(addr, out_irq);
     341                 :            :  out:
     342                 :            :         of_node_put(p);
     343                 :          0 :         return res;
     344                 :            : }
     345                 :            : EXPORT_SYMBOL_GPL(of_irq_parse_one);
     346                 :            : 
     347                 :            : /**
     348                 :            :  * of_irq_to_resource - Decode a node's IRQ and return it as a resource
     349                 :            :  * @dev: pointer to device tree node
     350                 :            :  * @index: zero-based index of the irq
     351                 :            :  * @r: pointer to resource structure to return result into.
     352                 :            :  */
     353                 :          0 : int of_irq_to_resource(struct device_node *dev, int index, struct resource *r)
     354                 :            : {
     355                 :          0 :         int irq = irq_of_parse_and_map(dev, index);
     356                 :            : 
     357                 :            :         /* Only dereference the resource if both the
     358                 :            :          * resource and the irq are valid. */
     359         [ #  # ]:          0 :         if (r && irq) {
     360                 :          0 :                 const char *name = NULL;
     361                 :            : 
     362                 :          0 :                 memset(r, 0, sizeof(*r));
     363                 :            :                 /*
     364                 :            :                  * Get optional "interrupts-names" property to add a name
     365                 :            :                  * to the resource.
     366                 :            :                  */
     367                 :          0 :                 of_property_read_string_index(dev, "interrupt-names", index,
     368                 :            :                                               &name);
     369                 :            : 
     370                 :          0 :                 r->start = r->end = irq;
     371                 :          0 :                 r->flags = IORESOURCE_IRQ | irqd_get_trigger_type(irq_get_irq_data(irq));
     372         [ #  # ]:          0 :                 r->name = name ? name : of_node_full_name(dev);
     373                 :            :         }
     374                 :            : 
     375                 :          0 :         return irq;
     376                 :            : }
     377                 :            : EXPORT_SYMBOL_GPL(of_irq_to_resource);
     378                 :            : 
     379                 :            : /**
     380                 :            :  * of_irq_count - Count the number of IRQs a node uses
     381                 :            :  * @dev: pointer to device tree node
     382                 :            :  */
     383                 :          0 : int of_irq_count(struct device_node *dev)
     384                 :            : {
     385                 :            :         struct of_phandle_args irq;
     386                 :            :         int nr = 0;
     387                 :            : 
     388         [ #  # ]:          0 :         while (of_irq_parse_one(dev, nr, &irq) == 0)
     389                 :          0 :                 nr++;
     390                 :            : 
     391                 :          0 :         return nr;
     392                 :            : }
     393                 :            : 
     394                 :            : /**
     395                 :            :  * of_irq_to_resource_table - Fill in resource table with node's IRQ info
     396                 :            :  * @dev: pointer to device tree node
     397                 :            :  * @res: array of resources to fill in
     398                 :            :  * @nr_irqs: the number of IRQs (and upper bound for num of @res elements)
     399                 :            :  *
     400                 :            :  * Returns the size of the filled in table (up to @nr_irqs).
     401                 :            :  */
     402                 :          0 : int of_irq_to_resource_table(struct device_node *dev, struct resource *res,
     403                 :            :                 int nr_irqs)
     404                 :            : {
     405                 :            :         int i;
     406                 :            : 
     407         [ #  # ]:          0 :         for (i = 0; i < nr_irqs; i++, res++)
     408         [ #  # ]:          0 :                 if (!of_irq_to_resource(dev, i, res))
     409                 :            :                         break;
     410                 :            : 
     411                 :          0 :         return i;
     412                 :            : }
     413                 :            : EXPORT_SYMBOL_GPL(of_irq_to_resource_table);
     414                 :            : 
     415                 :            : struct intc_desc {
     416                 :            :         struct list_head        list;
     417                 :            :         struct device_node      *dev;
     418                 :            :         struct device_node      *interrupt_parent;
     419                 :            : };
     420                 :            : 
     421                 :            : /**
     422                 :            :  * of_irq_init - Scan and init matching interrupt controllers in DT
     423                 :            :  * @matches: 0 terminated array of nodes to match and init function to call
     424                 :            :  *
     425                 :            :  * This function scans the device tree for matching interrupt controller nodes,
     426                 :            :  * and calls their initialization functions in order with parents first.
     427                 :            :  */
     428                 :          0 : void __init of_irq_init(const struct of_device_id *matches)
     429                 :            : {
     430                 :            :         struct device_node *np, *parent = NULL;
     431                 :            :         struct intc_desc *desc, *temp_desc;
     432                 :            :         struct list_head intc_desc_list, intc_parent_list;
     433                 :            : 
     434                 :            :         INIT_LIST_HEAD(&intc_desc_list);
     435                 :            :         INIT_LIST_HEAD(&intc_parent_list);
     436                 :            : 
     437         [ #  # ]:          0 :         for_each_matching_node(np, matches) {
     438         [ #  # ]:          0 :                 if (!of_find_property(np, "interrupt-controller", NULL))
     439                 :          0 :                         continue;
     440                 :            :                 /*
     441                 :            :                  * Here, we allocate and populate an intc_desc with the node
     442                 :            :                  * pointer, interrupt-parent device_node etc.
     443                 :            :                  */
     444                 :            :                 desc = kzalloc(sizeof(*desc), GFP_KERNEL);
     445 [ #  # ][ #  # ]:          0 :                 if (WARN_ON(!desc))
     446                 :            :                         goto err;
     447                 :            : 
     448                 :          0 :                 desc->dev = np;
     449                 :          0 :                 desc->interrupt_parent = of_irq_find_parent(np);
     450         [ #  # ]:          0 :                 if (desc->interrupt_parent == np)
     451                 :          0 :                         desc->interrupt_parent = NULL;
     452                 :          0 :                 list_add_tail(&desc->list, &intc_desc_list);
     453                 :            :         }
     454                 :            : 
     455                 :            :         /*
     456                 :            :          * The root irq controller is the one without an interrupt-parent.
     457                 :            :          * That one goes first, followed by the controllers that reference it,
     458                 :            :          * followed by the ones that reference the 2nd level controllers, etc.
     459                 :            :          */
     460         [ #  # ]:          0 :         while (!list_empty(&intc_desc_list)) {
     461                 :            :                 /*
     462                 :            :                  * Process all controllers with the current 'parent'.
     463                 :            :                  * First pass will be looking for NULL as the parent.
     464                 :            :                  * The assumption is that NULL parent means a root controller.
     465                 :            :                  */
     466         [ #  # ]:          0 :                 list_for_each_entry_safe(desc, temp_desc, &intc_desc_list, list) {
     467                 :            :                         const struct of_device_id *match;
     468                 :            :                         int ret;
     469                 :            :                         of_irq_init_cb_t irq_init_cb;
     470                 :            : 
     471         [ #  # ]:          0 :                         if (desc->interrupt_parent != parent)
     472                 :          0 :                                 continue;
     473                 :            : 
     474                 :            :                         list_del(&desc->list);
     475                 :          0 :                         match = of_match_node(matches, desc->dev);
     476 [ #  # ][ #  # ]:          0 :                         if (WARN(!match->data,
     477                 :            :                             "of_irq_init: no init function for %s\n",
     478                 :            :                             match->compatible)) {
     479                 :          0 :                                 kfree(desc);
     480                 :          0 :                                 continue;
     481                 :            :                         }
     482                 :            : 
     483                 :            :                         pr_debug("of_irq_init: init %s @ %p, parent %p\n",
     484                 :            :                                  match->compatible,
     485                 :            :                                  desc->dev, desc->interrupt_parent);
     486                 :          0 :                         irq_init_cb = (of_irq_init_cb_t)match->data;
     487                 :          0 :                         ret = irq_init_cb(desc->dev, desc->interrupt_parent);
     488         [ #  # ]:          0 :                         if (ret) {
     489                 :          0 :                                 kfree(desc);
     490                 :          0 :                                 continue;
     491                 :            :                         }
     492                 :            : 
     493                 :            :                         /*
     494                 :            :                          * This one is now set up; add it to the parent list so
     495                 :            :                          * its children can get processed in a subsequent pass.
     496                 :            :                          */
     497                 :            :                         list_add_tail(&desc->list, &intc_parent_list);
     498                 :            :                 }
     499                 :            : 
     500                 :            :                 /* Get the next pending parent that might have children */
     501         [ #  # ]:          0 :                 desc = list_first_entry_or_null(&intc_parent_list,
     502                 :            :                                                 typeof(*desc), list);
     503         [ #  # ]:          0 :                 if (!desc) {
     504                 :          0 :                         pr_err("of_irq_init: children remain, but no parents\n");
     505                 :          0 :                         break;
     506                 :            :                 }
     507                 :            :                 list_del(&desc->list);
     508                 :          0 :                 parent = desc->dev;
     509                 :          0 :                 kfree(desc);
     510                 :            :         }
     511                 :            : 
     512         [ #  # ]:          0 :         list_for_each_entry_safe(desc, temp_desc, &intc_parent_list, list) {
     513                 :            :                 list_del(&desc->list);
     514                 :          0 :                 kfree(desc);
     515                 :            :         }
     516                 :            : err:
     517         [ #  # ]:          0 :         list_for_each_entry_safe(desc, temp_desc, &intc_desc_list, list) {
     518                 :            :                 list_del(&desc->list);
     519                 :          0 :                 kfree(desc);
     520                 :            :         }
     521                 :          0 : }

Generated by: LCOV version 1.9