LCOV - code coverage report
Current view: top level - kernel/irq - irqdomain.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 5 169 3.0 %
Date: 2014-04-16 Functions: 1 18 5.6 %
Branches: 4 143 2.8 %

           Branch data     Line data    Source code
       1                 :            : #define pr_fmt(fmt)  "irq: " fmt
       2                 :            : 
       3                 :            : #include <linux/debugfs.h>
       4                 :            : #include <linux/hardirq.h>
       5                 :            : #include <linux/interrupt.h>
       6                 :            : #include <linux/irq.h>
       7                 :            : #include <linux/irqdesc.h>
       8                 :            : #include <linux/irqdomain.h>
       9                 :            : #include <linux/module.h>
      10                 :            : #include <linux/mutex.h>
      11                 :            : #include <linux/of.h>
      12                 :            : #include <linux/of_address.h>
      13                 :            : #include <linux/of_irq.h>
      14                 :            : #include <linux/topology.h>
      15                 :            : #include <linux/seq_file.h>
      16                 :            : #include <linux/slab.h>
      17                 :            : #include <linux/smp.h>
      18                 :            : #include <linux/fs.h>
      19                 :            : 
      20                 :            : static LIST_HEAD(irq_domain_list);
      21                 :            : static DEFINE_MUTEX(irq_domain_mutex);
      22                 :            : 
      23                 :            : static DEFINE_MUTEX(revmap_trees_mutex);
      24                 :            : static struct irq_domain *irq_default_domain;
      25                 :            : 
      26                 :            : /**
      27                 :            :  * __irq_domain_add() - Allocate a new irq_domain data structure
      28                 :            :  * @of_node: optional device-tree node of the interrupt controller
      29                 :            :  * @size: Size of linear map; 0 for radix mapping only
      30                 :            :  * @direct_max: Maximum value of direct maps; Use ~0 for no limit; 0 for no
      31                 :            :  *              direct mapping
      32                 :            :  * @ops: map/unmap domain callbacks
      33                 :            :  * @host_data: Controller private data pointer
      34                 :            :  *
      35                 :            :  * Allocates and initialize and irq_domain structure.  Caller is expected to
      36                 :            :  * register allocated irq_domain with irq_domain_register().  Returns pointer
      37                 :            :  * to IRQ domain, or NULL on failure.
      38                 :            :  */
      39                 :          0 : struct irq_domain *__irq_domain_add(struct device_node *of_node, int size,
      40                 :            :                                     irq_hw_number_t hwirq_max, int direct_max,
      41                 :            :                                     const struct irq_domain_ops *ops,
      42                 :            :                                     void *host_data)
      43                 :            : {
      44                 :            :         struct irq_domain *domain;
      45                 :            : 
      46                 :          0 :         domain = kzalloc_node(sizeof(*domain) + (sizeof(unsigned int) * size),
      47                 :            :                               GFP_KERNEL, of_node_to_nid(of_node));
      48 [ #  # ][ #  # ]:          0 :         if (WARN_ON(!domain))
      49                 :            :                 return NULL;
      50                 :            : 
      51                 :            :         /* Fill structure */
      52                 :          0 :         INIT_RADIX_TREE(&domain->revmap_tree, GFP_KERNEL);
      53                 :          0 :         domain->ops = ops;
      54                 :          0 :         domain->host_data = host_data;
      55                 :          0 :         domain->of_node = of_node_get(of_node);
      56                 :          0 :         domain->hwirq_max = hwirq_max;
      57                 :          0 :         domain->revmap_size = size;
      58                 :          0 :         domain->revmap_direct_max_irq = direct_max;
      59                 :            : 
      60                 :          0 :         mutex_lock(&irq_domain_mutex);
      61                 :          0 :         list_add(&domain->link, &irq_domain_list);
      62                 :          0 :         mutex_unlock(&irq_domain_mutex);
      63                 :            : 
      64                 :            :         pr_debug("Added domain %s\n", domain->name);
      65                 :          0 :         return domain;
      66                 :            : }
      67                 :            : EXPORT_SYMBOL_GPL(__irq_domain_add);
      68                 :            : 
      69                 :            : /**
      70                 :            :  * irq_domain_remove() - Remove an irq domain.
      71                 :            :  * @domain: domain to remove
      72                 :            :  *
      73                 :            :  * This routine is used to remove an irq domain. The caller must ensure
      74                 :            :  * that all mappings within the domain have been disposed of prior to
      75                 :            :  * use, depending on the revmap type.
      76                 :            :  */
      77                 :          0 : void irq_domain_remove(struct irq_domain *domain)
      78                 :            : {
      79                 :          0 :         mutex_lock(&irq_domain_mutex);
      80                 :            : 
      81                 :            :         /*
      82                 :            :          * radix_tree_delete() takes care of destroying the root
      83                 :            :          * node when all entries are removed. Shout if there are
      84                 :            :          * any mappings left.
      85                 :            :          */
      86         [ #  # ]:          0 :         WARN_ON(domain->revmap_tree.height);
      87                 :            : 
      88                 :            :         list_del(&domain->link);
      89                 :            : 
      90                 :            :         /*
      91                 :            :          * If the going away domain is the default one, reset it.
      92                 :            :          */
      93         [ #  # ]:          0 :         if (unlikely(irq_default_domain == domain))
      94                 :            :                 irq_set_default_host(NULL);
      95                 :            : 
      96                 :          0 :         mutex_unlock(&irq_domain_mutex);
      97                 :            : 
      98                 :            :         pr_debug("Removed domain %s\n", domain->name);
      99                 :            : 
     100                 :            :         of_node_put(domain->of_node);
     101                 :          0 :         kfree(domain);
     102                 :          0 : }
     103                 :            : EXPORT_SYMBOL_GPL(irq_domain_remove);
     104                 :            : 
     105                 :            : /**
     106                 :            :  * irq_domain_add_simple() - Register an irq_domain and optionally map a range of irqs
     107                 :            :  * @of_node: pointer to interrupt controller's device tree node.
     108                 :            :  * @size: total number of irqs in mapping
     109                 :            :  * @first_irq: first number of irq block assigned to the domain,
     110                 :            :  *      pass zero to assign irqs on-the-fly. If first_irq is non-zero, then
     111                 :            :  *      pre-map all of the irqs in the domain to virqs starting at first_irq.
     112                 :            :  * @ops: map/unmap domain callbacks
     113                 :            :  * @host_data: Controller private data pointer
     114                 :            :  *
     115                 :            :  * Allocates an irq_domain, and optionally if first_irq is positive then also
     116                 :            :  * allocate irq_descs and map all of the hwirqs to virqs starting at first_irq.
     117                 :            :  *
     118                 :            :  * This is intended to implement the expected behaviour for most
     119                 :            :  * interrupt controllers. If device tree is used, then first_irq will be 0 and
     120                 :            :  * irqs get mapped dynamically on the fly. However, if the controller requires
     121                 :            :  * static virq assignments (non-DT boot) then it will set that up correctly.
     122                 :            :  */
     123                 :          0 : struct irq_domain *irq_domain_add_simple(struct device_node *of_node,
     124                 :            :                                          unsigned int size,
     125                 :            :                                          unsigned int first_irq,
     126                 :            :                                          const struct irq_domain_ops *ops,
     127                 :            :                                          void *host_data)
     128                 :            : {
     129                 :            :         struct irq_domain *domain;
     130                 :            : 
     131                 :          0 :         domain = __irq_domain_add(of_node, size, size, 0, ops, host_data);
     132         [ #  # ]:          0 :         if (!domain)
     133                 :            :                 return NULL;
     134                 :            : 
     135         [ #  # ]:          0 :         if (first_irq > 0) {
     136                 :            :                 if (IS_ENABLED(CONFIG_SPARSE_IRQ)) {
     137                 :            :                         /* attempt to allocated irq_descs */
     138                 :          0 :                         int rc = irq_alloc_descs(first_irq, first_irq, size,
     139                 :            :                                                  of_node_to_nid(of_node));
     140         [ #  # ]:          0 :                         if (rc < 0)
     141                 :          0 :                                 pr_info("Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n",
     142                 :            :                                         first_irq);
     143                 :            :                 }
     144                 :            :                 irq_domain_associate_many(domain, first_irq, 0, size);
     145                 :            :         }
     146                 :            : 
     147                 :          0 :         return domain;
     148                 :            : }
     149                 :            : EXPORT_SYMBOL_GPL(irq_domain_add_simple);
     150                 :            : 
     151                 :            : /**
     152                 :            :  * irq_domain_add_legacy() - Allocate and register a legacy revmap irq_domain.
     153                 :            :  * @of_node: pointer to interrupt controller's device tree node.
     154                 :            :  * @size: total number of irqs in legacy mapping
     155                 :            :  * @first_irq: first number of irq block assigned to the domain
     156                 :            :  * @first_hwirq: first hwirq number to use for the translation. Should normally
     157                 :            :  *               be '0', but a positive integer can be used if the effective
     158                 :            :  *               hwirqs numbering does not begin at zero.
     159                 :            :  * @ops: map/unmap domain callbacks
     160                 :            :  * @host_data: Controller private data pointer
     161                 :            :  *
     162                 :            :  * Note: the map() callback will be called before this function returns
     163                 :            :  * for all legacy interrupts except 0 (which is always the invalid irq for
     164                 :            :  * a legacy controller).
     165                 :            :  */
     166                 :          0 : struct irq_domain *irq_domain_add_legacy(struct device_node *of_node,
     167                 :            :                                          unsigned int size,
     168                 :            :                                          unsigned int first_irq,
     169                 :            :                                          irq_hw_number_t first_hwirq,
     170                 :            :                                          const struct irq_domain_ops *ops,
     171                 :            :                                          void *host_data)
     172                 :            : {
     173                 :            :         struct irq_domain *domain;
     174                 :            : 
     175                 :          0 :         domain = __irq_domain_add(of_node, first_hwirq + size,
     176                 :            :                                   first_hwirq + size, 0, ops, host_data);
     177         [ #  # ]:          0 :         if (!domain)
     178                 :            :                 return NULL;
     179                 :            : 
     180                 :          0 :         irq_domain_associate_many(domain, first_irq, first_hwirq, size);
     181                 :            : 
     182                 :            :         return domain;
     183                 :            : }
     184                 :            : EXPORT_SYMBOL_GPL(irq_domain_add_legacy);
     185                 :            : 
     186                 :            : /**
     187                 :            :  * irq_find_host() - Locates a domain for a given device node
     188                 :            :  * @node: device-tree node of the interrupt controller
     189                 :            :  */
     190                 :          0 : struct irq_domain *irq_find_host(struct device_node *node)
     191                 :            : {
     192                 :            :         struct irq_domain *h, *found = NULL;
     193                 :            :         int rc;
     194                 :            : 
     195                 :            :         /* We might want to match the legacy controller last since
     196                 :            :          * it might potentially be set to match all interrupts in
     197                 :            :          * the absence of a device node. This isn't a problem so far
     198                 :            :          * yet though...
     199                 :            :          */
     200                 :          0 :         mutex_lock(&irq_domain_mutex);
     201         [ #  # ]:          0 :         list_for_each_entry(h, &irq_domain_list, link) {
     202         [ #  # ]:          0 :                 if (h->ops->match)
     203                 :          0 :                         rc = h->ops->match(h, node);
     204                 :            :                 else
     205 [ #  # ][ #  # ]:          0 :                         rc = (h->of_node != NULL) && (h->of_node == node);
     206                 :            : 
     207         [ #  # ]:          0 :                 if (rc) {
     208                 :            :                         found = h;
     209                 :            :                         break;
     210                 :            :                 }
     211                 :            :         }
     212                 :          0 :         mutex_unlock(&irq_domain_mutex);
     213                 :          0 :         return found;
     214                 :            : }
     215                 :            : EXPORT_SYMBOL_GPL(irq_find_host);
     216                 :            : 
     217                 :            : /**
     218                 :            :  * irq_set_default_host() - Set a "default" irq domain
     219                 :            :  * @domain: default domain pointer
     220                 :            :  *
     221                 :            :  * For convenience, it's possible to set a "default" domain that will be used
     222                 :            :  * whenever NULL is passed to irq_create_mapping(). It makes life easier for
     223                 :            :  * platforms that want to manipulate a few hard coded interrupt numbers that
     224                 :            :  * aren't properly represented in the device-tree.
     225                 :            :  */
     226                 :          0 : void irq_set_default_host(struct irq_domain *domain)
     227                 :            : {
     228                 :            :         pr_debug("Default domain set to @0x%p\n", domain);
     229                 :            : 
     230                 :          0 :         irq_default_domain = domain;
     231                 :          0 : }
     232                 :            : EXPORT_SYMBOL_GPL(irq_set_default_host);
     233                 :            : 
     234                 :          0 : static void irq_domain_disassociate(struct irq_domain *domain, unsigned int irq)
     235                 :            : {
     236                 :          0 :         struct irq_data *irq_data = irq_get_irq_data(irq);
     237                 :            :         irq_hw_number_t hwirq;
     238                 :            : 
     239 [ #  # ][ #  # ]:          0 :         if (WARN(!irq_data || irq_data->domain != domain,
         [ #  # ][ #  # ]
     240                 :            :                  "virq%i doesn't exist; cannot disassociate\n", irq))
     241                 :          0 :                 return;
     242                 :            : 
     243                 :          0 :         hwirq = irq_data->hwirq;
     244                 :            :         irq_set_status_flags(irq, IRQ_NOREQUEST);
     245                 :            : 
     246                 :            :         /* remove chip and handler */
     247                 :            :         irq_set_chip_and_handler(irq, NULL, NULL);
     248                 :            : 
     249                 :            :         /* Make sure it's completed */
     250                 :          0 :         synchronize_irq(irq);
     251                 :            : 
     252                 :            :         /* Tell the PIC about it */
     253         [ #  # ]:          0 :         if (domain->ops->unmap)
     254                 :          0 :                 domain->ops->unmap(domain, irq);
     255                 :          0 :         smp_mb();
     256                 :            : 
     257                 :          0 :         irq_data->domain = NULL;
     258                 :          0 :         irq_data->hwirq = 0;
     259                 :            : 
     260                 :            :         /* Clear reverse map for this hwirq */
     261         [ #  # ]:          0 :         if (hwirq < domain->revmap_size) {
     262                 :          0 :                 domain->linear_revmap[hwirq] = 0;
     263                 :            :         } else {
     264                 :          0 :                 mutex_lock(&revmap_trees_mutex);
     265                 :          0 :                 radix_tree_delete(&domain->revmap_tree, hwirq);
     266                 :          0 :                 mutex_unlock(&revmap_trees_mutex);
     267                 :            :         }
     268                 :            : }
     269                 :            : 
     270                 :          0 : int irq_domain_associate(struct irq_domain *domain, unsigned int virq,
     271                 :            :                          irq_hw_number_t hwirq)
     272                 :            : {
     273                 :          0 :         struct irq_data *irq_data = irq_get_irq_data(virq);
     274                 :            :         int ret;
     275                 :            : 
     276 [ #  # ][ #  # ]:          0 :         if (WARN(hwirq >= domain->hwirq_max,
     277                 :            :                  "error: hwirq 0x%x is too large for %s\n", (int)hwirq, domain->name))
     278                 :            :                 return -EINVAL;
     279 [ #  # ][ #  # ]:          0 :         if (WARN(!irq_data, "error: virq%i is not allocated", virq))
     280                 :            :                 return -EINVAL;
     281 [ #  # ][ #  # ]:          0 :         if (WARN(irq_data->domain, "error: virq%i is already associated", virq))
     282                 :            :                 return -EINVAL;
     283                 :            : 
     284                 :          0 :         mutex_lock(&irq_domain_mutex);
     285                 :          0 :         irq_data->hwirq = hwirq;
     286                 :          0 :         irq_data->domain = domain;
     287         [ #  # ]:          0 :         if (domain->ops->map) {
     288                 :          0 :                 ret = domain->ops->map(domain, virq, hwirq);
     289         [ #  # ]:          0 :                 if (ret != 0) {
     290                 :            :                         /*
     291                 :            :                          * If map() returns -EPERM, this interrupt is protected
     292                 :            :                          * by the firmware or some other service and shall not
     293                 :            :                          * be mapped. Don't bother telling the user about it.
     294                 :            :                          */
     295         [ #  # ]:          0 :                         if (ret != -EPERM) {
     296                 :          0 :                                 pr_info("%s didn't like hwirq-0x%lx to VIRQ%i mapping (rc=%d)\n",
     297                 :            :                                        domain->name, hwirq, virq, ret);
     298                 :            :                         }
     299                 :          0 :                         irq_data->domain = NULL;
     300                 :          0 :                         irq_data->hwirq = 0;
     301                 :          0 :                         mutex_unlock(&irq_domain_mutex);
     302                 :          0 :                         return ret;
     303                 :            :                 }
     304                 :            : 
     305                 :            :                 /* If not already assigned, give the domain the chip's name */
     306 [ #  # ][ #  # ]:          0 :                 if (!domain->name && irq_data->chip)
     307                 :          0 :                         domain->name = irq_data->chip->name;
     308                 :            :         }
     309                 :            : 
     310         [ #  # ]:          0 :         if (hwirq < domain->revmap_size) {
     311                 :          0 :                 domain->linear_revmap[hwirq] = virq;
     312                 :            :         } else {
     313                 :          0 :                 mutex_lock(&revmap_trees_mutex);
     314                 :          0 :                 radix_tree_insert(&domain->revmap_tree, hwirq, irq_data);
     315                 :          0 :                 mutex_unlock(&revmap_trees_mutex);
     316                 :            :         }
     317                 :          0 :         mutex_unlock(&irq_domain_mutex);
     318                 :            : 
     319                 :            :         irq_clear_status_flags(virq, IRQ_NOREQUEST);
     320                 :            : 
     321                 :          0 :         return 0;
     322                 :            : }
     323                 :            : EXPORT_SYMBOL_GPL(irq_domain_associate);
     324                 :            : 
     325                 :          0 : void irq_domain_associate_many(struct irq_domain *domain, unsigned int irq_base,
     326                 :            :                                irq_hw_number_t hwirq_base, int count)
     327                 :            : {
     328                 :            :         int i;
     329                 :            : 
     330                 :            :         pr_debug("%s(%s, irqbase=%i, hwbase=%i, count=%i)\n", __func__,
     331                 :            :                 of_node_full_name(domain->of_node), irq_base, (int)hwirq_base, count);
     332                 :            : 
     333 [ #  # ][ #  # ]:          0 :         for (i = 0; i < count; i++) {
         [ #  # ][ #  # ]
     334                 :          0 :                 irq_domain_associate(domain, irq_base + i, hwirq_base + i);
     335                 :            :         }
     336                 :          0 : }
     337                 :            : EXPORT_SYMBOL_GPL(irq_domain_associate_many);
     338                 :            : 
     339                 :            : /**
     340                 :            :  * irq_create_direct_mapping() - Allocate an irq for direct mapping
     341                 :            :  * @domain: domain to allocate the irq for or NULL for default domain
     342                 :            :  *
     343                 :            :  * This routine is used for irq controllers which can choose the hardware
     344                 :            :  * interrupt numbers they generate. In such a case it's simplest to use
     345                 :            :  * the linux irq as the hardware interrupt number. It still uses the linear
     346                 :            :  * or radix tree to store the mapping, but the irq controller can optimize
     347                 :            :  * the revmap path by using the hwirq directly.
     348                 :            :  */
     349                 :          0 : unsigned int irq_create_direct_mapping(struct irq_domain *domain)
     350                 :            : {
     351                 :            :         unsigned int virq;
     352                 :            : 
     353         [ #  # ]:          0 :         if (domain == NULL)
     354                 :          0 :                 domain = irq_default_domain;
     355                 :            : 
     356                 :          0 :         virq = irq_alloc_desc_from(1, of_node_to_nid(domain->of_node));
     357         [ #  # ]:          0 :         if (!virq) {
     358                 :            :                 pr_debug("create_direct virq allocation failed\n");
     359                 :            :                 return 0;
     360                 :            :         }
     361         [ #  # ]:          0 :         if (virq >= domain->revmap_direct_max_irq) {
     362                 :          0 :                 pr_err("ERROR: no free irqs available below %i maximum\n",
     363                 :            :                         domain->revmap_direct_max_irq);
     364                 :            :                 irq_free_desc(virq);
     365                 :          0 :                 return 0;
     366                 :            :         }
     367                 :            :         pr_debug("create_direct obtained virq %d\n", virq);
     368                 :            : 
     369         [ #  # ]:          0 :         if (irq_domain_associate(domain, virq, virq)) {
     370                 :            :                 irq_free_desc(virq);
     371                 :          0 :                 return 0;
     372                 :            :         }
     373                 :            : 
     374                 :            :         return virq;
     375                 :            : }
     376                 :            : EXPORT_SYMBOL_GPL(irq_create_direct_mapping);
     377                 :            : 
     378                 :            : /**
     379                 :            :  * irq_create_mapping() - Map a hardware interrupt into linux irq space
     380                 :            :  * @domain: domain owning this hardware interrupt or NULL for default domain
     381                 :            :  * @hwirq: hardware irq number in that domain space
     382                 :            :  *
     383                 :            :  * Only one mapping per hardware interrupt is permitted. Returns a linux
     384                 :            :  * irq number.
     385                 :            :  * If the sense/trigger is to be specified, set_irq_type() should be called
     386                 :            :  * on the number returned from that call.
     387                 :            :  */
     388                 :          0 : unsigned int irq_create_mapping(struct irq_domain *domain,
     389                 :            :                                 irq_hw_number_t hwirq)
     390                 :            : {
     391                 :            :         unsigned int hint;
     392                 :            :         int virq;
     393                 :            : 
     394                 :            :         pr_debug("irq_create_mapping(0x%p, 0x%lx)\n", domain, hwirq);
     395                 :            : 
     396                 :            :         /* Look for default domain if nececssary */
     397         [ #  # ]:          0 :         if (domain == NULL)
     398                 :          0 :                 domain = irq_default_domain;
     399         [ #  # ]:          0 :         if (domain == NULL) {
     400                 :          0 :                 WARN(1, "%s(, %lx) called with NULL domain\n", __func__, hwirq);
     401                 :          0 :                 return 0;
     402                 :            :         }
     403                 :            :         pr_debug("-> using domain @%p\n", domain);
     404                 :            : 
     405                 :            :         /* Check if mapping already exists */
     406                 :          0 :         virq = irq_find_mapping(domain, hwirq);
     407         [ #  # ]:          0 :         if (virq) {
     408                 :            :                 pr_debug("-> existing mapping on virq %d\n", virq);
     409                 :            :                 return virq;
     410                 :            :         }
     411                 :            : 
     412                 :            :         /* Allocate a virtual interrupt number */
     413                 :          0 :         hint = hwirq % nr_irqs;
     414         [ #  # ]:          0 :         if (hint == 0)
     415                 :          0 :                 hint++;
     416                 :          0 :         virq = irq_alloc_desc_from(hint, of_node_to_nid(domain->of_node));
     417         [ #  # ]:          0 :         if (virq <= 0)
     418                 :          0 :                 virq = irq_alloc_desc_from(1, of_node_to_nid(domain->of_node));
     419         [ #  # ]:          0 :         if (virq <= 0) {
     420                 :            :                 pr_debug("-> virq allocation failed\n");
     421                 :            :                 return 0;
     422                 :            :         }
     423                 :            : 
     424         [ #  # ]:          0 :         if (irq_domain_associate(domain, virq, hwirq)) {
     425                 :            :                 irq_free_desc(virq);
     426                 :          0 :                 return 0;
     427                 :            :         }
     428                 :            : 
     429                 :            :         pr_debug("irq %lu on domain %s mapped to virtual irq %u\n",
     430                 :            :                 hwirq, of_node_full_name(domain->of_node), virq);
     431                 :            : 
     432                 :            :         return virq;
     433                 :            : }
     434                 :            : EXPORT_SYMBOL_GPL(irq_create_mapping);
     435                 :            : 
     436                 :            : /**
     437                 :            :  * irq_create_strict_mappings() - Map a range of hw irqs to fixed linux irqs
     438                 :            :  * @domain: domain owning the interrupt range
     439                 :            :  * @irq_base: beginning of linux IRQ range
     440                 :            :  * @hwirq_base: beginning of hardware IRQ range
     441                 :            :  * @count: Number of interrupts to map
     442                 :            :  *
     443                 :            :  * This routine is used for allocating and mapping a range of hardware
     444                 :            :  * irqs to linux irqs where the linux irq numbers are at pre-defined
     445                 :            :  * locations. For use by controllers that already have static mappings
     446                 :            :  * to insert in to the domain.
     447                 :            :  *
     448                 :            :  * Non-linear users can use irq_create_identity_mapping() for IRQ-at-a-time
     449                 :            :  * domain insertion.
     450                 :            :  *
     451                 :            :  * 0 is returned upon success, while any failure to establish a static
     452                 :            :  * mapping is treated as an error.
     453                 :            :  */
     454                 :          0 : int irq_create_strict_mappings(struct irq_domain *domain, unsigned int irq_base,
     455                 :            :                                irq_hw_number_t hwirq_base, int count)
     456                 :            : {
     457                 :            :         int ret;
     458                 :            : 
     459                 :          0 :         ret = irq_alloc_descs(irq_base, irq_base, count,
     460                 :            :                               of_node_to_nid(domain->of_node));
     461         [ #  # ]:          0 :         if (unlikely(ret < 0))
     462                 :            :                 return ret;
     463                 :            : 
     464                 :            :         irq_domain_associate_many(domain, irq_base, hwirq_base, count);
     465                 :            :         return 0;
     466                 :            : }
     467                 :            : EXPORT_SYMBOL_GPL(irq_create_strict_mappings);
     468                 :            : 
     469                 :          0 : unsigned int irq_create_of_mapping(struct of_phandle_args *irq_data)
     470                 :            : {
     471                 :            :         struct irq_domain *domain;
     472                 :            :         irq_hw_number_t hwirq;
     473                 :          0 :         unsigned int type = IRQ_TYPE_NONE;
     474                 :            :         unsigned int virq;
     475                 :            : 
     476         [ #  # ]:          0 :         domain = irq_data->np ? irq_find_host(irq_data->np) : irq_default_domain;
     477         [ #  # ]:          0 :         if (!domain) {
     478                 :          0 :                 pr_warn("no irq domain found for %s !\n",
     479                 :            :                         of_node_full_name(irq_data->np));
     480                 :          0 :                 return 0;
     481                 :            :         }
     482                 :            : 
     483                 :            :         /* If domain has no translation, then we assume interrupt line */
     484         [ #  # ]:          0 :         if (domain->ops->xlate == NULL)
     485                 :          0 :                 hwirq = irq_data->args[0];
     486                 :            :         else {
     487         [ #  # ]:          0 :                 if (domain->ops->xlate(domain, irq_data->np, irq_data->args,
     488                 :          0 :                                         irq_data->args_count, &hwirq, &type))
     489                 :            :                         return 0;
     490                 :            :         }
     491                 :            : 
     492                 :            :         /* Create mapping */
     493                 :          0 :         virq = irq_create_mapping(domain, hwirq);
     494         [ #  # ]:          0 :         if (!virq)
     495                 :            :                 return virq;
     496                 :            : 
     497                 :            :         /* Set type if specified and different than the current one */
     498 [ #  # ][ #  # ]:          0 :         if (type != IRQ_TYPE_NONE &&
     499                 :          0 :             type != irq_get_trigger_type(virq))
     500                 :          0 :                 irq_set_irq_type(virq, type);
     501                 :          0 :         return virq;
     502                 :            : }
     503                 :            : EXPORT_SYMBOL_GPL(irq_create_of_mapping);
     504                 :            : 
     505                 :            : /**
     506                 :            :  * irq_dispose_mapping() - Unmap an interrupt
     507                 :            :  * @virq: linux irq number of the interrupt to unmap
     508                 :            :  */
     509                 :          0 : void irq_dispose_mapping(unsigned int virq)
     510                 :            : {
     511                 :          0 :         struct irq_data *irq_data = irq_get_irq_data(virq);
     512                 :            :         struct irq_domain *domain;
     513                 :            : 
     514         [ #  # ]:          0 :         if (!virq || !irq_data)
     515                 :            :                 return;
     516                 :            : 
     517                 :          0 :         domain = irq_data->domain;
     518 [ #  # ][ #  # ]:          0 :         if (WARN_ON(domain == NULL))
     519                 :            :                 return;
     520                 :            : 
     521                 :          0 :         irq_domain_disassociate(domain, virq);
     522                 :            :         irq_free_desc(virq);
     523                 :            : }
     524                 :            : EXPORT_SYMBOL_GPL(irq_dispose_mapping);
     525                 :            : 
     526                 :            : /**
     527                 :            :  * irq_find_mapping() - Find a linux irq from an hw irq number.
     528                 :            :  * @domain: domain owning this hardware interrupt
     529                 :            :  * @hwirq: hardware irq number in that domain space
     530                 :            :  */
     531                 :          0 : unsigned int irq_find_mapping(struct irq_domain *domain,
     532                 :            :                               irq_hw_number_t hwirq)
     533                 :            : {
     534                 :            :         struct irq_data *data;
     535                 :            : 
     536                 :            :         /* Look for default domain if nececssary */
     537         [ -  + ]:    5523056 :         if (domain == NULL)
     538                 :          0 :                 domain = irq_default_domain;
     539            [ + ]:    5523056 :         if (domain == NULL)
     540                 :            :                 return 0;
     541                 :            : 
     542         [ -  + ]:    5622928 :         if (hwirq < domain->revmap_direct_max_irq) {
     543                 :          0 :                 data = irq_get_irq_data(hwirq);
     544 [ #  # ][ #  # ]:          0 :                 if (data && (data->domain == domain) && (data->hwirq == hwirq))
                 [ #  # ]
     545                 :            :                         return hwirq;
     546                 :            :         }
     547                 :            : 
     548                 :            :         /* Check if the hwirq is in the linear revmap. */
     549         [ +  - ]:    5595443 :         if (hwirq < domain->revmap_size)
     550                 :    5595443 :                 return domain->linear_revmap[hwirq];
     551                 :            : 
     552                 :            :         rcu_read_lock();
     553                 :          0 :         data = radix_tree_lookup(&domain->revmap_tree, hwirq);
     554                 :            :         rcu_read_unlock();
     555         [ #  # ]:          0 :         return data ? data->irq : 0;
     556                 :            : }
     557                 :            : EXPORT_SYMBOL_GPL(irq_find_mapping);
     558                 :            : 
     559                 :            : #ifdef CONFIG_IRQ_DOMAIN_DEBUG
     560                 :            : static int virq_debug_show(struct seq_file *m, void *private)
     561                 :            : {
     562                 :            :         unsigned long flags;
     563                 :            :         struct irq_desc *desc;
     564                 :            :         struct irq_domain *domain;
     565                 :            :         struct radix_tree_iter iter;
     566                 :            :         void *data, **slot;
     567                 :            :         int i;
     568                 :            : 
     569                 :            :         seq_printf(m, " %-16s  %-6s  %-10s  %-10s  %s\n",
     570                 :            :                    "name", "mapped", "linear-max", "direct-max", "devtree-node");
     571                 :            :         mutex_lock(&irq_domain_mutex);
     572                 :            :         list_for_each_entry(domain, &irq_domain_list, link) {
     573                 :            :                 int count = 0;
     574                 :            :                 radix_tree_for_each_slot(slot, &domain->revmap_tree, &iter, 0)
     575                 :            :                         count++;
     576                 :            :                 seq_printf(m, "%c%-16s  %6u  %10u  %10u  %s\n",
     577                 :            :                            domain == irq_default_domain ? '*' : ' ', domain->name,
     578                 :            :                            domain->revmap_size + count, domain->revmap_size,
     579                 :            :                            domain->revmap_direct_max_irq,
     580                 :            :                            domain->of_node ? of_node_full_name(domain->of_node) : "");
     581                 :            :         }
     582                 :            :         mutex_unlock(&irq_domain_mutex);
     583                 :            : 
     584                 :            :         seq_printf(m, "%-5s  %-7s  %-15s  %-*s  %6s  %-14s  %s\n", "irq", "hwirq",
     585                 :            :                       "chip name", (int)(2 * sizeof(void *) + 2), "chip data",
     586                 :            :                       "active", "type", "domain");
     587                 :            : 
     588                 :            :         for (i = 1; i < nr_irqs; i++) {
     589                 :            :                 desc = irq_to_desc(i);
     590                 :            :                 if (!desc)
     591                 :            :                         continue;
     592                 :            : 
     593                 :            :                 raw_spin_lock_irqsave(&desc->lock, flags);
     594                 :            :                 domain = desc->irq_data.domain;
     595                 :            : 
     596                 :            :                 if (domain) {
     597                 :            :                         struct irq_chip *chip;
     598                 :            :                         int hwirq = desc->irq_data.hwirq;
     599                 :            :                         bool direct;
     600                 :            : 
     601                 :            :                         seq_printf(m, "%5d  ", i);
     602                 :            :                         seq_printf(m, "0x%05x  ", hwirq);
     603                 :            : 
     604                 :            :                         chip = irq_desc_get_chip(desc);
     605                 :            :                         seq_printf(m, "%-15s  ", (chip && chip->name) ? chip->name : "none");
     606                 :            : 
     607                 :            :                         data = irq_desc_get_chip_data(desc);
     608                 :            :                         seq_printf(m, data ? "0x%p  " : "  %p  ", data);
     609                 :            : 
     610                 :            :                         seq_printf(m, "   %c    ", (desc->action && desc->action->handler) ? '*' : ' ');
     611                 :            :                         direct = (i == hwirq) && (i < domain->revmap_direct_max_irq);
     612                 :            :                         seq_printf(m, "%6s%-8s  ",
     613                 :            :                                    (hwirq < domain->revmap_size) ? "LINEAR" : "RADIX",
     614                 :            :                                    direct ? "(DIRECT)" : "");
     615                 :            :                         seq_printf(m, "%s\n", desc->irq_data.domain->name);
     616                 :            :                 }
     617                 :            : 
     618                 :            :                 raw_spin_unlock_irqrestore(&desc->lock, flags);
     619                 :            :         }
     620                 :            : 
     621                 :            :         return 0;
     622                 :            : }
     623                 :            : 
     624                 :            : static int virq_debug_open(struct inode *inode, struct file *file)
     625                 :            : {
     626                 :            :         return single_open(file, virq_debug_show, inode->i_private);
     627                 :            : }
     628                 :            : 
     629                 :            : static const struct file_operations virq_debug_fops = {
     630                 :            :         .open = virq_debug_open,
     631                 :            :         .read = seq_read,
     632                 :            :         .llseek = seq_lseek,
     633                 :            :         .release = single_release,
     634                 :            : };
     635                 :            : 
     636                 :            : static int __init irq_debugfs_init(void)
     637                 :            : {
     638                 :            :         if (debugfs_create_file("irq_domain_mapping", S_IRUGO, NULL,
     639                 :            :                                  NULL, &virq_debug_fops) == NULL)
     640                 :            :                 return -ENOMEM;
     641                 :            : 
     642                 :            :         return 0;
     643                 :            : }
     644                 :            : __initcall(irq_debugfs_init);
     645                 :            : #endif /* CONFIG_IRQ_DOMAIN_DEBUG */
     646                 :            : 
     647                 :            : /**
     648                 :            :  * irq_domain_xlate_onecell() - Generic xlate for direct one cell bindings
     649                 :            :  *
     650                 :            :  * Device Tree IRQ specifier translation function which works with one cell
     651                 :            :  * bindings where the cell value maps directly to the hwirq number.
     652                 :            :  */
     653                 :          0 : int irq_domain_xlate_onecell(struct irq_domain *d, struct device_node *ctrlr,
     654                 :            :                              const u32 *intspec, unsigned int intsize,
     655                 :            :                              unsigned long *out_hwirq, unsigned int *out_type)
     656                 :            : {
     657 [ #  # ][ #  # ]:          0 :         if (WARN_ON(intsize < 1))
     658                 :            :                 return -EINVAL;
     659                 :          0 :         *out_hwirq = intspec[0];
     660                 :          0 :         *out_type = IRQ_TYPE_NONE;
     661                 :          0 :         return 0;
     662                 :            : }
     663                 :            : EXPORT_SYMBOL_GPL(irq_domain_xlate_onecell);
     664                 :            : 
     665                 :            : /**
     666                 :            :  * irq_domain_xlate_twocell() - Generic xlate for direct two cell bindings
     667                 :            :  *
     668                 :            :  * Device Tree IRQ specifier translation function which works with two cell
     669                 :            :  * bindings where the cell values map directly to the hwirq number
     670                 :            :  * and linux irq flags.
     671                 :            :  */
     672                 :          0 : int irq_domain_xlate_twocell(struct irq_domain *d, struct device_node *ctrlr,
     673                 :            :                         const u32 *intspec, unsigned int intsize,
     674                 :            :                         irq_hw_number_t *out_hwirq, unsigned int *out_type)
     675                 :            : {
     676 [ #  # ][ #  # ]:          0 :         if (WARN_ON(intsize < 2))
     677                 :            :                 return -EINVAL;
     678                 :          0 :         *out_hwirq = intspec[0];
     679                 :          0 :         *out_type = intspec[1] & IRQ_TYPE_SENSE_MASK;
     680                 :          0 :         return 0;
     681                 :            : }
     682                 :            : EXPORT_SYMBOL_GPL(irq_domain_xlate_twocell);
     683                 :            : 
     684                 :            : /**
     685                 :            :  * irq_domain_xlate_onetwocell() - Generic xlate for one or two cell bindings
     686                 :            :  *
     687                 :            :  * Device Tree IRQ specifier translation function which works with either one
     688                 :            :  * or two cell bindings where the cell values map directly to the hwirq number
     689                 :            :  * and linux irq flags.
     690                 :            :  *
     691                 :            :  * Note: don't use this function unless your interrupt controller explicitly
     692                 :            :  * supports both one and two cell bindings.  For the majority of controllers
     693                 :            :  * the _onecell() or _twocell() variants above should be used.
     694                 :            :  */
     695                 :          0 : int irq_domain_xlate_onetwocell(struct irq_domain *d,
     696                 :            :                                 struct device_node *ctrlr,
     697                 :            :                                 const u32 *intspec, unsigned int intsize,
     698                 :            :                                 unsigned long *out_hwirq, unsigned int *out_type)
     699                 :            : {
     700 [ #  # ][ #  # ]:          0 :         if (WARN_ON(intsize < 1))
     701                 :            :                 return -EINVAL;
     702                 :          0 :         *out_hwirq = intspec[0];
     703         [ #  # ]:          0 :         *out_type = (intsize > 1) ? intspec[1] : IRQ_TYPE_NONE;
     704                 :          0 :         return 0;
     705                 :            : }
     706                 :            : EXPORT_SYMBOL_GPL(irq_domain_xlate_onetwocell);
     707                 :            : 
     708                 :            : const struct irq_domain_ops irq_domain_simple_ops = {
     709                 :            :         .xlate = irq_domain_xlate_onetwocell,
     710                 :            : };
     711                 :            : EXPORT_SYMBOL_GPL(irq_domain_simple_ops);

Generated by: LCOV version 1.9