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-02-18 Functions: 1 18 5.6 %
Branches: 5 144 3.5 %

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

Generated by: LCOV version 1.9