LCOV - code coverage report
Current view: top level - drivers/of - irq.c (source / functions) Hit Total Coverage
Test: Real Lines: 112 180 62.2 %
Date: 2020-10-17 15:46:16 Functions: 0 15 0.0 %
Legend: Neither, QEMU, Real, Both Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0+
       2                 :            : /*
       3                 :            :  *  Derived from arch/i386/kernel/irq.c
       4                 :            :  *    Copyright (C) 1992 Linus Torvalds
       5                 :            :  *  Adapted from arch/i386 by Gary Thomas
       6                 :            :  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
       7                 :            :  *  Updated and modified by Cort Dougan <cort@fsmlabs.com>
       8                 :            :  *    Copyright (C) 1996-2001 Cort Dougan
       9                 :            :  *  Adapted for Power Macintosh by Paul Mackerras
      10                 :            :  *    Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au)
      11                 :            :  *
      12                 :            :  * This file contains the code used to make IRQ descriptions in the
      13                 :            :  * device tree to actual irq numbers on an interrupt controller
      14                 :            :  * driver.
      15                 :            :  */
      16                 :            : 
      17                 :            : #define pr_fmt(fmt)     "OF: " fmt
      18                 :            : 
      19                 :            : #include <linux/device.h>
      20                 :            : #include <linux/errno.h>
      21                 :            : #include <linux/list.h>
      22                 :            : #include <linux/module.h>
      23                 :            : #include <linux/of.h>
      24                 :            : #include <linux/of_irq.h>
      25                 :            : #include <linux/string.h>
      26                 :            : #include <linux/slab.h>
      27                 :            : 
      28                 :            : /**
      29                 :            :  * irq_of_parse_and_map - Parse and map an interrupt into linux virq space
      30                 :            :  * @dev: Device node of the device whose interrupt is to be mapped
      31                 :            :  * @index: Index of the interrupt to map
      32                 :            :  *
      33                 :            :  * This function is a wrapper that chains of_irq_parse_one() and
      34                 :            :  * irq_create_of_mapping() to make things easier to callers
      35                 :            :  */
      36                 :          3 : unsigned int irq_of_parse_and_map(struct device_node *dev, int index)
      37                 :            : {
      38                 :            :         struct of_phandle_args oirq;
      39                 :            : 
      40                 :          3 :         if (of_irq_parse_one(dev, index, &oirq))
      41                 :            :                 return 0;
      42                 :            : 
      43                 :          3 :         return irq_create_of_mapping(&oirq);
      44                 :            : }
      45                 :            : EXPORT_SYMBOL_GPL(irq_of_parse_and_map);
      46                 :            : 
      47                 :            : /**
      48                 :            :  * of_irq_find_parent - Given a device node, find its interrupt parent node
      49                 :            :  * @child: pointer to device node
      50                 :            :  *
      51                 :            :  * Returns a pointer to the interrupt parent node, or NULL if the interrupt
      52                 :            :  * parent could not be determined.
      53                 :            :  */
      54                 :          3 : struct device_node *of_irq_find_parent(struct device_node *child)
      55                 :            : {
      56                 :            :         struct device_node *p;
      57                 :            :         phandle parent;
      58                 :            : 
      59                 :          3 :         if (!of_node_get(child))
      60                 :            :                 return NULL;
      61                 :            : 
      62                 :            :         do {
      63                 :          3 :                 if (of_property_read_u32(child, "interrupt-parent", &parent)) {
      64                 :          3 :                         p = of_get_parent(child);
      65                 :            :                 } else  {
      66                 :            :                         if (of_irq_workarounds & OF_IMAP_NO_PHANDLE)
      67                 :            :                                 p = of_node_get(of_irq_dflt_pic);
      68                 :            :                         else
      69                 :          3 :                                 p = of_find_node_by_phandle(parent);
      70                 :            :                 }
      71                 :          3 :                 of_node_put(child);
      72                 :            :                 child = p;
      73                 :          3 :         } while (p && of_get_property(p, "#interrupt-cells", NULL) == NULL);
      74                 :            : 
      75                 :          3 :         return p;
      76                 :            : }
      77                 :            : EXPORT_SYMBOL_GPL(of_irq_find_parent);
      78                 :            : 
      79                 :            : /**
      80                 :            :  * of_irq_parse_raw - Low level interrupt tree parsing
      81                 :            :  * @addr:       address specifier (start of "reg" property of the device) in be32 format
      82                 :            :  * @out_irq:    structure of_phandle_args updated by this function
      83                 :            :  *
      84                 :            :  * Returns 0 on success and a negative number on error
      85                 :            :  *
      86                 :            :  * This function is a low-level interrupt tree walking function. It
      87                 :            :  * can be used to do a partial walk with synthetized reg and interrupts
      88                 :            :  * properties, for example when resolving PCI interrupts when no device
      89                 :            :  * node exist for the parent. It takes an interrupt specifier structure as
      90                 :            :  * input, walks the tree looking for any interrupt-map properties, translates
      91                 :            :  * the specifier for each map, and then returns the translated map.
      92                 :            :  */
      93                 :          3 : int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
      94                 :            : {
      95                 :            :         struct device_node *ipar, *tnode, *old = NULL, *newpar = NULL;
      96                 :            :         __be32 initial_match_array[MAX_PHANDLE_ARGS];
      97                 :            :         const __be32 *match_array = initial_match_array;
      98                 :          3 :         const __be32 *tmp, *imap, *imask, dummy_imask[] = { [0 ... MAX_PHANDLE_ARGS] = cpu_to_be32(~0) };
      99                 :          3 :         u32 intsize = 1, addrsize, newintsize = 0, newaddrsize = 0;
     100                 :            :         int imaplen, match, i, rc = -EINVAL;
     101                 :            : 
     102                 :            : #ifdef DEBUG
     103                 :            :         of_print_phandle_args("of_irq_parse_raw: ", out_irq);
     104                 :            : #endif
     105                 :            : 
     106                 :          3 :         ipar = of_node_get(out_irq->np);
     107                 :            : 
     108                 :            :         /* First get the #interrupt-cells property of the current cursor
     109                 :            :          * that tells us how to interpret the passed-in intspec. If there
     110                 :            :          * is none, we are nice and just walk up the tree
     111                 :            :          */
     112                 :            :         do {
     113                 :          3 :                 if (!of_property_read_u32(ipar, "#interrupt-cells", &intsize))
     114                 :            :                         break;
     115                 :            :                 tnode = ipar;
     116                 :          0 :                 ipar = of_irq_find_parent(ipar);
     117                 :          0 :                 of_node_put(tnode);
     118                 :          0 :         } while (ipar);
     119                 :          3 :         if (ipar == NULL) {
     120                 :            :                 pr_debug(" -> no parent found !\n");
     121                 :            :                 goto fail;
     122                 :            :         }
     123                 :            : 
     124                 :            :         pr_debug("of_irq_parse_raw: ipar=%pOF, size=%d\n", ipar, intsize);
     125                 :            : 
     126                 :          3 :         if (out_irq->args_count != intsize)
     127                 :            :                 goto fail;
     128                 :            : 
     129                 :            :         /* Look for this #address-cells. We have to implement the old linux
     130                 :            :          * trick of looking for the parent here as some device-trees rely on it
     131                 :            :          */
     132                 :          3 :         old = of_node_get(ipar);
     133                 :            :         do {
     134                 :          3 :                 tmp = of_get_property(old, "#address-cells", NULL);
     135                 :          3 :                 tnode = of_get_parent(old);
     136                 :          3 :                 of_node_put(old);
     137                 :            :                 old = tnode;
     138                 :          3 :         } while (old && tmp == NULL);
     139                 :          3 :         of_node_put(old);
     140                 :            :         old = NULL;
     141                 :          3 :         addrsize = (tmp == NULL) ? 2 : be32_to_cpu(*tmp);
     142                 :            : 
     143                 :            :         pr_debug(" -> addrsize=%d\n", addrsize);
     144                 :            : 
     145                 :            :         /* Range check so that the temporary buffer doesn't overflow */
     146                 :          3 :         if (WARN_ON(addrsize + intsize > MAX_PHANDLE_ARGS)) {
     147                 :            :                 rc = -EFAULT;
     148                 :            :                 goto fail;
     149                 :            :         }
     150                 :            : 
     151                 :            :         /* Precalculate the match array - this simplifies match loop */
     152                 :          3 :         for (i = 0; i < addrsize; i++)
     153                 :          3 :                 initial_match_array[i] = addr ? addr[i] : 0;
     154                 :          3 :         for (i = 0; i < intsize; i++)
     155                 :          3 :                 initial_match_array[addrsize + i] = cpu_to_be32(out_irq->args[i]);
     156                 :            : 
     157                 :            :         /* Now start the actual "proper" walk of the interrupt tree */
     158                 :          3 :         while (ipar != NULL) {
     159                 :            :                 /* Now check if cursor is an interrupt-controller and if it is
     160                 :            :                  * then we are done
     161                 :            :                  */
     162                 :          3 :                 if (of_property_read_bool(ipar, "interrupt-controller")) {
     163                 :            :                         pr_debug(" -> got it !\n");
     164                 :            :                         return 0;
     165                 :            :                 }
     166                 :            : 
     167                 :            :                 /*
     168                 :            :                  * interrupt-map parsing does not work without a reg
     169                 :            :                  * property when #address-cells != 0
     170                 :            :                  */
     171                 :          0 :                 if (addrsize && !addr) {
     172                 :            :                         pr_debug(" -> no reg passed in when needed !\n");
     173                 :            :                         goto fail;
     174                 :            :                 }
     175                 :            : 
     176                 :            :                 /* Now look for an interrupt-map */
     177                 :          0 :                 imap = of_get_property(ipar, "interrupt-map", &imaplen);
     178                 :            :                 /* No interrupt map, check for an interrupt parent */
     179                 :          0 :                 if (imap == NULL) {
     180                 :            :                         pr_debug(" -> no map, getting parent\n");
     181                 :          0 :                         newpar = of_irq_find_parent(ipar);
     182                 :          0 :                         goto skiplevel;
     183                 :            :                 }
     184                 :          0 :                 imaplen /= sizeof(u32);
     185                 :            : 
     186                 :            :                 /* Look for a mask */
     187                 :          0 :                 imask = of_get_property(ipar, "interrupt-map-mask", NULL);
     188                 :          0 :                 if (!imask)
     189                 :            :                         imask = dummy_imask;
     190                 :            : 
     191                 :            :                 /* Parse interrupt-map */
     192                 :            :                 match = 0;
     193                 :          0 :                 while (imaplen > (addrsize + intsize + 1) && !match) {
     194                 :            :                         /* Compare specifiers */
     195                 :            :                         match = 1;
     196                 :          0 :                         for (i = 0; i < (addrsize + intsize); i++, imaplen--)
     197                 :          0 :                                 match &= !((match_array[i] ^ *imap++) & imask[i]);
     198                 :            : 
     199                 :            :                         pr_debug(" -> match=%d (imaplen=%d)\n", match, imaplen);
     200                 :            : 
     201                 :            :                         /* Get the interrupt parent */
     202                 :            :                         if (of_irq_workarounds & OF_IMAP_NO_PHANDLE)
     203                 :            :                                 newpar = of_node_get(of_irq_dflt_pic);
     204                 :            :                         else
     205                 :          0 :                                 newpar = of_find_node_by_phandle(be32_to_cpup(imap));
     206                 :            :                         imap++;
     207                 :          0 :                         --imaplen;
     208                 :            : 
     209                 :            :                         /* Check if not found */
     210                 :          0 :                         if (newpar == NULL) {
     211                 :            :                                 pr_debug(" -> imap parent not found !\n");
     212                 :            :                                 goto fail;
     213                 :            :                         }
     214                 :            : 
     215                 :          0 :                         if (!of_device_is_available(newpar))
     216                 :            :                                 match = 0;
     217                 :            : 
     218                 :            :                         /* Get #interrupt-cells and #address-cells of new
     219                 :            :                          * parent
     220                 :            :                          */
     221                 :          0 :                         if (of_property_read_u32(newpar, "#interrupt-cells",
     222                 :            :                                                  &newintsize)) {
     223                 :            :                                 pr_debug(" -> parent lacks #interrupt-cells!\n");
     224                 :            :                                 goto fail;
     225                 :            :                         }
     226                 :          0 :                         if (of_property_read_u32(newpar, "#address-cells",
     227                 :            :                                                  &newaddrsize))
     228                 :          0 :                                 newaddrsize = 0;
     229                 :            : 
     230                 :            :                         pr_debug(" -> newintsize=%d, newaddrsize=%d\n",
     231                 :            :                             newintsize, newaddrsize);
     232                 :            : 
     233                 :            :                         /* Check for malformed properties */
     234                 :          0 :                         if (WARN_ON(newaddrsize + newintsize > MAX_PHANDLE_ARGS)
     235                 :          0 :                             || (imaplen < (newaddrsize + newintsize))) {
     236                 :            :                                 rc = -EFAULT;
     237                 :            :                                 goto fail;
     238                 :            :                         }
     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 :                 match_array = imap - newaddrsize - newintsize;
     253                 :          0 :                 for (i = 0; i < newintsize; i++)
     254                 :          0 :                         out_irq->args[i] = be32_to_cpup(imap - newintsize + i);
     255                 :          0 :                 out_irq->args_count = intsize = newintsize;
     256                 :            :                 addrsize = newaddrsize;
     257                 :            : 
     258                 :            :         skiplevel:
     259                 :            :                 /* Iterate again with new parent */
     260                 :          0 :                 out_irq->np = newpar;
     261                 :            :                 pr_debug(" -> new parent: %pOF\n", newpar);
     262                 :          0 :                 of_node_put(ipar);
     263                 :            :                 ipar = newpar;
     264                 :            :                 newpar = NULL;
     265                 :            :         }
     266                 :            :         rc = -ENOENT; /* No interrupt-map found */
     267                 :            : 
     268                 :            :  fail:
     269                 :          0 :         of_node_put(ipar);
     270                 :          0 :         of_node_put(newpar);
     271                 :            : 
     272                 :          0 :         return rc;
     273                 :            : }
     274                 :            : EXPORT_SYMBOL_GPL(of_irq_parse_raw);
     275                 :            : 
     276                 :            : /**
     277                 :            :  * of_irq_parse_one - Resolve an interrupt for a device
     278                 :            :  * @device: the device whose interrupt is to be resolved
     279                 :            :  * @index: index of the interrupt to resolve
     280                 :            :  * @out_irq: structure of_phandle_args filled by this function
     281                 :            :  *
     282                 :            :  * This function resolves an interrupt for a node by walking the interrupt tree,
     283                 :            :  * finding which interrupt controller node it is attached to, and returning the
     284                 :            :  * interrupt specifier that can be used to retrieve a Linux IRQ number.
     285                 :            :  */
     286                 :          3 : int of_irq_parse_one(struct device_node *device, int index, struct of_phandle_args *out_irq)
     287                 :            : {
     288                 :            :         struct device_node *p;
     289                 :            :         const __be32 *addr;
     290                 :            :         u32 intsize;
     291                 :            :         int i, res;
     292                 :            : 
     293                 :            :         pr_debug("of_irq_parse_one: dev=%pOF, index=%d\n", device, index);
     294                 :            : 
     295                 :            :         /* OldWorld mac stuff is "special", handle out of line */
     296                 :            :         if (of_irq_workarounds & OF_IMAP_OLDWORLD_MAC)
     297                 :            :                 return of_irq_parse_oldworld(device, index, out_irq);
     298                 :            : 
     299                 :            :         /* Get the reg property (if any) */
     300                 :          3 :         addr = of_get_property(device, "reg", NULL);
     301                 :            : 
     302                 :            :         /* Try the new-style interrupts-extended first */
     303                 :          3 :         res = of_parse_phandle_with_args(device, "interrupts-extended",
     304                 :            :                                         "#interrupt-cells", index, out_irq);
     305                 :          3 :         if (!res)
     306                 :          0 :                 return of_irq_parse_raw(addr, out_irq);
     307                 :            : 
     308                 :            :         /* Look for the interrupt parent. */
     309                 :          3 :         p = of_irq_find_parent(device);
     310                 :          3 :         if (p == NULL)
     311                 :            :                 return -EINVAL;
     312                 :            : 
     313                 :            :         /* Get size of interrupt specifier */
     314                 :          3 :         if (of_property_read_u32(p, "#interrupt-cells", &intsize)) {
     315                 :            :                 res = -EINVAL;
     316                 :            :                 goto out;
     317                 :            :         }
     318                 :            : 
     319                 :            :         pr_debug(" parent=%pOF, intsize=%d\n", p, intsize);
     320                 :            : 
     321                 :            :         /* Copy intspec into irq structure */
     322                 :          3 :         out_irq->np = p;
     323                 :          3 :         out_irq->args_count = intsize;
     324                 :          3 :         for (i = 0; i < intsize; i++) {
     325                 :          3 :                 res = of_property_read_u32_index(device, "interrupts",
     326                 :          3 :                                                  (index * intsize) + i,
     327                 :          3 :                                                  out_irq->args + i);
     328                 :          3 :                 if (res)
     329                 :            :                         goto out;
     330                 :            :         }
     331                 :            : 
     332                 :            :         pr_debug(" intspec=%d\n", *out_irq->args);
     333                 :            : 
     334                 :            : 
     335                 :            :         /* Check if there are any interrupt-map translations to process */
     336                 :          3 :         res = of_irq_parse_raw(addr, out_irq);
     337                 :            :  out:
     338                 :          3 :         of_node_put(p);
     339                 :          3 :         return res;
     340                 :            : }
     341                 :            : EXPORT_SYMBOL_GPL(of_irq_parse_one);
     342                 :            : 
     343                 :            : /**
     344                 :            :  * of_irq_to_resource - Decode a node's IRQ and return it as a resource
     345                 :            :  * @dev: pointer to device tree node
     346                 :            :  * @index: zero-based index of the irq
     347                 :            :  * @r: pointer to resource structure to return result into.
     348                 :            :  */
     349                 :          3 : int of_irq_to_resource(struct device_node *dev, int index, struct resource *r)
     350                 :            : {
     351                 :          3 :         int irq = of_irq_get(dev, index);
     352                 :            : 
     353                 :          3 :         if (irq < 0)
     354                 :            :                 return irq;
     355                 :            : 
     356                 :            :         /* Only dereference the resource if both the
     357                 :            :          * resource and the irq are valid. */
     358                 :          3 :         if (r && irq) {
     359                 :          3 :                 const char *name = NULL;
     360                 :            : 
     361                 :          3 :                 memset(r, 0, sizeof(*r));
     362                 :            :                 /*
     363                 :            :                  * Get optional "interrupt-names" property to add a name
     364                 :            :                  * to the resource.
     365                 :            :                  */
     366                 :            :                 of_property_read_string_index(dev, "interrupt-names", index,
     367                 :            :                                               &name);
     368                 :            : 
     369                 :          3 :                 r->start = r->end = irq;
     370                 :          3 :                 r->flags = IORESOURCE_IRQ | irqd_get_trigger_type(irq_get_irq_data(irq));
     371                 :          3 :                 r->name = name ? name : of_node_full_name(dev);
     372                 :            :         }
     373                 :            : 
     374                 :            :         return irq;
     375                 :            : }
     376                 :            : EXPORT_SYMBOL_GPL(of_irq_to_resource);
     377                 :            : 
     378                 :            : /**
     379                 :            :  * of_irq_get - Decode a node's IRQ and return it as a Linux IRQ number
     380                 :            :  * @dev: pointer to device tree node
     381                 :            :  * @index: zero-based index of the IRQ
     382                 :            :  *
     383                 :            :  * Returns Linux IRQ number on success, or 0 on the IRQ mapping failure, or
     384                 :            :  * -EPROBE_DEFER if the IRQ domain is not yet created, or error code in case
     385                 :            :  * of any other failure.
     386                 :            :  */
     387                 :          3 : int of_irq_get(struct device_node *dev, int index)
     388                 :            : {
     389                 :            :         int rc;
     390                 :            :         struct of_phandle_args oirq;
     391                 :            :         struct irq_domain *domain;
     392                 :            : 
     393                 :          3 :         rc = of_irq_parse_one(dev, index, &oirq);
     394                 :          3 :         if (rc)
     395                 :            :                 return rc;
     396                 :            : 
     397                 :          3 :         domain = irq_find_host(oirq.np);
     398                 :          3 :         if (!domain)
     399                 :            :                 return -EPROBE_DEFER;
     400                 :            : 
     401                 :          3 :         return irq_create_of_mapping(&oirq);
     402                 :            : }
     403                 :            : EXPORT_SYMBOL_GPL(of_irq_get);
     404                 :            : 
     405                 :            : /**
     406                 :            :  * of_irq_get_byname - Decode a node's IRQ and return it as a Linux IRQ number
     407                 :            :  * @dev: pointer to device tree node
     408                 :            :  * @name: IRQ name
     409                 :            :  *
     410                 :            :  * Returns Linux IRQ number on success, or 0 on the IRQ mapping failure, or
     411                 :            :  * -EPROBE_DEFER if the IRQ domain is not yet created, or error code in case
     412                 :            :  * of any other failure.
     413                 :            :  */
     414                 :          3 : int of_irq_get_byname(struct device_node *dev, const char *name)
     415                 :            : {
     416                 :            :         int index;
     417                 :            : 
     418                 :          3 :         if (unlikely(!name))
     419                 :            :                 return -EINVAL;
     420                 :            : 
     421                 :          3 :         index = of_property_match_string(dev, "interrupt-names", name);
     422                 :          3 :         if (index < 0)
     423                 :            :                 return index;
     424                 :            : 
     425                 :          3 :         return of_irq_get(dev, index);
     426                 :            : }
     427                 :            : EXPORT_SYMBOL_GPL(of_irq_get_byname);
     428                 :            : 
     429                 :            : /**
     430                 :            :  * of_irq_count - Count the number of IRQs a node uses
     431                 :            :  * @dev: pointer to device tree node
     432                 :            :  */
     433                 :          3 : int of_irq_count(struct device_node *dev)
     434                 :            : {
     435                 :            :         struct of_phandle_args irq;
     436                 :            :         int nr = 0;
     437                 :            : 
     438                 :          3 :         while (of_irq_parse_one(dev, nr, &irq) == 0)
     439                 :          3 :                 nr++;
     440                 :            : 
     441                 :          3 :         return nr;
     442                 :            : }
     443                 :            : 
     444                 :            : /**
     445                 :            :  * of_irq_to_resource_table - Fill in resource table with node's IRQ info
     446                 :            :  * @dev: pointer to device tree node
     447                 :            :  * @res: array of resources to fill in
     448                 :            :  * @nr_irqs: the number of IRQs (and upper bound for num of @res elements)
     449                 :            :  *
     450                 :            :  * Returns the size of the filled in table (up to @nr_irqs).
     451                 :            :  */
     452                 :          3 : int of_irq_to_resource_table(struct device_node *dev, struct resource *res,
     453                 :            :                 int nr_irqs)
     454                 :            : {
     455                 :            :         int i;
     456                 :            : 
     457                 :          3 :         for (i = 0; i < nr_irqs; i++, res++)
     458                 :          3 :                 if (of_irq_to_resource(dev, i, res) <= 0)
     459                 :            :                         break;
     460                 :            : 
     461                 :          3 :         return i;
     462                 :            : }
     463                 :            : EXPORT_SYMBOL_GPL(of_irq_to_resource_table);
     464                 :            : 
     465                 :            : struct of_intc_desc {
     466                 :            :         struct list_head        list;
     467                 :            :         of_irq_init_cb_t        irq_init_cb;
     468                 :            :         struct device_node      *dev;
     469                 :            :         struct device_node      *interrupt_parent;
     470                 :            : };
     471                 :            : 
     472                 :            : /**
     473                 :            :  * of_irq_init - Scan and init matching interrupt controllers in DT
     474                 :            :  * @matches: 0 terminated array of nodes to match and init function to call
     475                 :            :  *
     476                 :            :  * This function scans the device tree for matching interrupt controller nodes,
     477                 :            :  * and calls their initialization functions in order with parents first.
     478                 :            :  */
     479                 :          3 : void __init of_irq_init(const struct of_device_id *matches)
     480                 :            : {
     481                 :            :         const struct of_device_id *match;
     482                 :            :         struct device_node *np, *parent = NULL;
     483                 :            :         struct of_intc_desc *desc, *temp_desc;
     484                 :            :         struct list_head intc_desc_list, intc_parent_list;
     485                 :            : 
     486                 :            :         INIT_LIST_HEAD(&intc_desc_list);
     487                 :            :         INIT_LIST_HEAD(&intc_parent_list);
     488                 :            : 
     489                 :          3 :         for_each_matching_node_and_match(np, matches, &match) {
     490                 :          3 :                 if (!of_property_read_bool(np, "interrupt-controller") ||
     491                 :          3 :                                 !of_device_is_available(np))
     492                 :          0 :                         continue;
     493                 :            : 
     494                 :          3 :                 if (WARN(!match->data, "of_irq_init: no init function for %s\n",
     495                 :            :                          match->compatible))
     496                 :          0 :                         continue;
     497                 :            : 
     498                 :            :                 /*
     499                 :            :                  * Here, we allocate and populate an of_intc_desc with the node
     500                 :            :                  * pointer, interrupt-parent device_node etc.
     501                 :            :                  */
     502                 :          3 :                 desc = kzalloc(sizeof(*desc), GFP_KERNEL);
     503                 :          3 :                 if (!desc) {
     504                 :          0 :                         of_node_put(np);
     505                 :          0 :                         goto err;
     506                 :            :                 }
     507                 :            : 
     508                 :          3 :                 desc->irq_init_cb = match->data;
     509                 :          3 :                 desc->dev = of_node_get(np);
     510                 :          3 :                 desc->interrupt_parent = of_irq_find_parent(np);
     511                 :          3 :                 if (desc->interrupt_parent == np)
     512                 :          3 :                         desc->interrupt_parent = NULL;
     513                 :          3 :                 list_add_tail(&desc->list, &intc_desc_list);
     514                 :            :         }
     515                 :            : 
     516                 :            :         /*
     517                 :            :          * The root irq controller is the one without an interrupt-parent.
     518                 :            :          * That one goes first, followed by the controllers that reference it,
     519                 :            :          * followed by the ones that reference the 2nd level controllers, etc.
     520                 :            :          */
     521                 :          3 :         while (!list_empty(&intc_desc_list)) {
     522                 :            :                 /*
     523                 :            :                  * Process all controllers with the current 'parent'.
     524                 :            :                  * First pass will be looking for NULL as the parent.
     525                 :            :                  * The assumption is that NULL parent means a root controller.
     526                 :            :                  */
     527                 :          3 :                 list_for_each_entry_safe(desc, temp_desc, &intc_desc_list, list) {
     528                 :            :                         int ret;
     529                 :            : 
     530                 :          3 :                         if (desc->interrupt_parent != parent)
     531                 :          3 :                                 continue;
     532                 :            : 
     533                 :            :                         list_del(&desc->list);
     534                 :            : 
     535                 :          3 :                         of_node_set_flag(desc->dev, OF_POPULATED);
     536                 :            : 
     537                 :            :                         pr_debug("of_irq_init: init %pOF (%p), parent %p\n",
     538                 :            :                                  desc->dev,
     539                 :            :                                  desc->dev, desc->interrupt_parent);
     540                 :          3 :                         ret = desc->irq_init_cb(desc->dev,
     541                 :            :                                                 desc->interrupt_parent);
     542                 :          3 :                         if (ret) {
     543                 :          0 :                                 of_node_clear_flag(desc->dev, OF_POPULATED);
     544                 :          0 :                                 kfree(desc);
     545                 :          0 :                                 continue;
     546                 :            :                         }
     547                 :            : 
     548                 :            :                         /*
     549                 :            :                          * This one is now set up; add it to the parent list so
     550                 :            :                          * its children can get processed in a subsequent pass.
     551                 :            :                          */
     552                 :            :                         list_add_tail(&desc->list, &intc_parent_list);
     553                 :            :                 }
     554                 :            : 
     555                 :            :                 /* Get the next pending parent that might have children */
     556                 :          3 :                 desc = list_first_entry_or_null(&intc_parent_list,
     557                 :            :                                                 typeof(*desc), list);
     558                 :          3 :                 if (!desc) {
     559                 :          0 :                         pr_err("of_irq_init: children remain, but no parents\n");
     560                 :          0 :                         break;
     561                 :            :                 }
     562                 :            :                 list_del(&desc->list);
     563                 :          3 :                 parent = desc->dev;
     564                 :          3 :                 kfree(desc);
     565                 :            :         }
     566                 :            : 
     567                 :          3 :         list_for_each_entry_safe(desc, temp_desc, &intc_parent_list, list) {
     568                 :            :                 list_del(&desc->list);
     569                 :          0 :                 kfree(desc);
     570                 :            :         }
     571                 :            : err:
     572                 :          3 :         list_for_each_entry_safe(desc, temp_desc, &intc_desc_list, list) {
     573                 :            :                 list_del(&desc->list);
     574                 :          0 :                 of_node_put(desc->dev);
     575                 :          0 :                 kfree(desc);
     576                 :            :         }
     577                 :          3 : }
     578                 :            : 
     579                 :          0 : static u32 __of_msi_map_rid(struct device *dev, struct device_node **np,
     580                 :            :                             u32 rid_in)
     581                 :            : {
     582                 :            :         struct device *parent_dev;
     583                 :          0 :         u32 rid_out = rid_in;
     584                 :            : 
     585                 :            :         /*
     586                 :            :          * Walk up the device parent links looking for one with a
     587                 :            :          * "msi-map" property.
     588                 :            :          */
     589                 :          0 :         for (parent_dev = dev; parent_dev; parent_dev = parent_dev->parent)
     590                 :          0 :                 if (!of_map_rid(parent_dev->of_node, rid_in, "msi-map",
     591                 :            :                                 "msi-map-mask", np, &rid_out))
     592                 :            :                         break;
     593                 :          0 :         return rid_out;
     594                 :            : }
     595                 :            : 
     596                 :            : /**
     597                 :            :  * of_msi_map_rid - Map a MSI requester ID for a device.
     598                 :            :  * @dev: device for which the mapping is to be done.
     599                 :            :  * @msi_np: device node of the expected msi controller.
     600                 :            :  * @rid_in: unmapped MSI requester ID for the device.
     601                 :            :  *
     602                 :            :  * Walk up the device hierarchy looking for devices with a "msi-map"
     603                 :            :  * property.  If found, apply the mapping to @rid_in.
     604                 :            :  *
     605                 :            :  * Returns the mapped MSI requester ID.
     606                 :            :  */
     607                 :          0 : u32 of_msi_map_rid(struct device *dev, struct device_node *msi_np, u32 rid_in)
     608                 :            : {
     609                 :          0 :         return __of_msi_map_rid(dev, &msi_np, rid_in);
     610                 :            : }
     611                 :            : 
     612                 :            : /**
     613                 :            :  * of_msi_map_get_device_domain - Use msi-map to find the relevant MSI domain
     614                 :            :  * @dev: device for which the mapping is to be done.
     615                 :            :  * @rid: Requester ID for the device.
     616                 :            :  *
     617                 :            :  * Walk up the device hierarchy looking for devices with a "msi-map"
     618                 :            :  * property.
     619                 :            :  *
     620                 :            :  * Returns: the MSI domain for this device (or NULL on failure)
     621                 :            :  */
     622                 :          0 : struct irq_domain *of_msi_map_get_device_domain(struct device *dev, u32 rid)
     623                 :            : {
     624                 :          0 :         struct device_node *np = NULL;
     625                 :            : 
     626                 :          0 :         __of_msi_map_rid(dev, &np, rid);
     627                 :          0 :         return irq_find_matching_host(np, DOMAIN_BUS_PCI_MSI);
     628                 :            : }
     629                 :            : 
     630                 :            : /**
     631                 :            :  * of_msi_get_domain - Use msi-parent to find the relevant MSI domain
     632                 :            :  * @dev: device for which the domain is requested
     633                 :            :  * @np: device node for @dev
     634                 :            :  * @token: bus type for this domain
     635                 :            :  *
     636                 :            :  * Parse the msi-parent property (both the simple and the complex
     637                 :            :  * versions), and returns the corresponding MSI domain.
     638                 :            :  *
     639                 :            :  * Returns: the MSI domain for this device (or NULL on failure).
     640                 :            :  */
     641                 :          3 : struct irq_domain *of_msi_get_domain(struct device *dev,
     642                 :            :                                      struct device_node *np,
     643                 :            :                                      enum irq_domain_bus_token token)
     644                 :            : {
     645                 :            :         struct device_node *msi_np;
     646                 :            :         struct irq_domain *d;
     647                 :            : 
     648                 :            :         /* Check for a single msi-parent property */
     649                 :          3 :         msi_np = of_parse_phandle(np, "msi-parent", 0);
     650                 :          3 :         if (msi_np && !of_property_read_bool(msi_np, "#msi-cells")) {
     651                 :          0 :                 d = irq_find_matching_host(msi_np, token);
     652                 :          0 :                 if (!d)
     653                 :          0 :                         of_node_put(msi_np);
     654                 :          0 :                 return d;
     655                 :            :         }
     656                 :            : 
     657                 :          3 :         if (token == DOMAIN_BUS_PLATFORM_MSI) {
     658                 :            :                 /* Check for the complex msi-parent version */
     659                 :            :                 struct of_phandle_args args;
     660                 :            :                 int index = 0;
     661                 :            : 
     662                 :          3 :                 while (!of_parse_phandle_with_args(np, "msi-parent",
     663                 :            :                                                    "#msi-cells",
     664                 :            :                                                    index, &args)) {
     665                 :          0 :                         d = irq_find_matching_host(args.np, token);
     666                 :          0 :                         if (d)
     667                 :          0 :                                 return d;
     668                 :            : 
     669                 :          0 :                         of_node_put(args.np);
     670                 :          0 :                         index++;
     671                 :            :                 }
     672                 :            :         }
     673                 :            : 
     674                 :            :         return NULL;
     675                 :            : }
     676                 :            : 
     677                 :            : /**
     678                 :            :  * of_msi_configure - Set the msi_domain field of a device
     679                 :            :  * @dev: device structure to associate with an MSI irq domain
     680                 :            :  * @np: device node for that device
     681                 :            :  */
     682                 :          3 : void of_msi_configure(struct device *dev, struct device_node *np)
     683                 :            : {
     684                 :          3 :         dev_set_msi_domain(dev,
     685                 :            :                            of_msi_get_domain(dev, np, DOMAIN_BUS_PLATFORM_MSI));
     686                 :          3 : }
     687                 :            : EXPORT_SYMBOL_GPL(of_msi_configure);
    

Generated by: LCOV version 1.14