@@ -1449,6 +1449,175 @@ int __irq_domain_alloc_irqs(struct irq_domain *domain, int irq_base,
14491449 return ret ;
14501450}
14511451
1452+ /* The irq_data was moved, fix the revmap to refer to the new location */
1453+ static void irq_domain_fix_revmap (struct irq_data * d )
1454+ {
1455+ void * * slot ;
1456+
1457+ if (d -> hwirq < d -> domain -> revmap_size )
1458+ return ; /* Not using radix tree. */
1459+
1460+ /* Fix up the revmap. */
1461+ mutex_lock (& revmap_trees_mutex );
1462+ slot = radix_tree_lookup_slot (& d -> domain -> revmap_tree , d -> hwirq );
1463+ if (slot )
1464+ radix_tree_replace_slot (& d -> domain -> revmap_tree , slot , d );
1465+ mutex_unlock (& revmap_trees_mutex );
1466+ }
1467+
1468+ /**
1469+ * irq_domain_push_irq() - Push a domain in to the top of a hierarchy.
1470+ * @domain: Domain to push.
1471+ * @virq: Irq to push the domain in to.
1472+ * @arg: Passed to the irq_domain_ops alloc() function.
1473+ *
1474+ * For an already existing irqdomain hierarchy, as might be obtained
1475+ * via a call to pci_enable_msix(), add an additional domain to the
1476+ * head of the processing chain. Must be called before request_irq()
1477+ * has been called.
1478+ */
1479+ int irq_domain_push_irq (struct irq_domain * domain , int virq , void * arg )
1480+ {
1481+ struct irq_data * child_irq_data ;
1482+ struct irq_data * root_irq_data = irq_get_irq_data (virq );
1483+ struct irq_desc * desc ;
1484+ int rv = 0 ;
1485+
1486+ /*
1487+ * Check that no action has been set, which indicates the virq
1488+ * is in a state where this function doesn't have to deal with
1489+ * races between interrupt handling and maintaining the
1490+ * hierarchy. This will catch gross misuse. Attempting to
1491+ * make the check race free would require holding locks across
1492+ * calls to struct irq_domain_ops->alloc(), which could lead
1493+ * to deadlock, so we just do a simple check before starting.
1494+ */
1495+ desc = irq_to_desc (virq );
1496+ if (!desc )
1497+ return - EINVAL ;
1498+ if (WARN_ON (desc -> action ))
1499+ return - EBUSY ;
1500+
1501+ if (domain == NULL )
1502+ return - EINVAL ;
1503+
1504+ if (WARN_ON (!irq_domain_is_hierarchy (domain )))
1505+ return - EINVAL ;
1506+
1507+ if (domain -> parent != root_irq_data -> domain )
1508+ return - EINVAL ;
1509+
1510+ if (!root_irq_data )
1511+ return - EINVAL ;
1512+
1513+ child_irq_data = kzalloc_node (sizeof (* child_irq_data ), GFP_KERNEL ,
1514+ irq_data_get_node (root_irq_data ));
1515+ if (!child_irq_data )
1516+ return - ENOMEM ;
1517+
1518+ mutex_lock (& irq_domain_mutex );
1519+
1520+ /* Copy the original irq_data. */
1521+ * child_irq_data = * root_irq_data ;
1522+
1523+ /*
1524+ * Overwrite the root_irq_data, which is embedded in struct
1525+ * irq_desc, with values for this domain.
1526+ */
1527+ root_irq_data -> parent_data = child_irq_data ;
1528+ root_irq_data -> domain = domain ;
1529+ root_irq_data -> mask = 0 ;
1530+ root_irq_data -> hwirq = 0 ;
1531+ root_irq_data -> chip = NULL ;
1532+ root_irq_data -> chip_data = NULL ;
1533+
1534+ /* May (probably does) set hwirq, chip, etc. */
1535+ rv = irq_domain_alloc_irqs_hierarchy (domain , virq , 1 , arg );
1536+ if (rv ) {
1537+ /* Restore the original irq_data. */
1538+ * root_irq_data = * child_irq_data ;
1539+ goto error ;
1540+ }
1541+
1542+ irq_domain_fix_revmap (child_irq_data );
1543+ irq_domain_set_mapping (domain , root_irq_data -> hwirq , root_irq_data );
1544+
1545+ error :
1546+ mutex_unlock (& irq_domain_mutex );
1547+
1548+ return rv ;
1549+ }
1550+ EXPORT_SYMBOL_GPL (irq_domain_push_irq );
1551+
1552+ /**
1553+ * irq_domain_pop_irq() - Remove a domain from the top of a hierarchy.
1554+ * @domain: Domain to remove.
1555+ * @virq: Irq to remove the domain from.
1556+ *
1557+ * Undo the effects of a call to irq_domain_push_irq(). Must be
1558+ * called either before request_irq() or after free_irq().
1559+ */
1560+ int irq_domain_pop_irq (struct irq_domain * domain , int virq )
1561+ {
1562+ struct irq_data * root_irq_data = irq_get_irq_data (virq );
1563+ struct irq_data * child_irq_data ;
1564+ struct irq_data * tmp_irq_data ;
1565+ struct irq_desc * desc ;
1566+
1567+ /*
1568+ * Check that no action is set, which indicates the virq is in
1569+ * a state where this function doesn't have to deal with races
1570+ * between interrupt handling and maintaining the hierarchy.
1571+ * This will catch gross misuse. Attempting to make the check
1572+ * race free would require holding locks across calls to
1573+ * struct irq_domain_ops->free(), which could lead to
1574+ * deadlock, so we just do a simple check before starting.
1575+ */
1576+ desc = irq_to_desc (virq );
1577+ if (!desc )
1578+ return - EINVAL ;
1579+ if (WARN_ON (desc -> action ))
1580+ return - EBUSY ;
1581+
1582+ if (domain == NULL )
1583+ return - EINVAL ;
1584+
1585+ if (!root_irq_data )
1586+ return - EINVAL ;
1587+
1588+ tmp_irq_data = irq_domain_get_irq_data (domain , virq );
1589+
1590+ /* We can only "pop" if this domain is at the top of the list */
1591+ if (WARN_ON (root_irq_data != tmp_irq_data ))
1592+ return - EINVAL ;
1593+
1594+ if (WARN_ON (root_irq_data -> domain != domain ))
1595+ return - EINVAL ;
1596+
1597+ child_irq_data = root_irq_data -> parent_data ;
1598+ if (WARN_ON (!child_irq_data ))
1599+ return - EINVAL ;
1600+
1601+ mutex_lock (& irq_domain_mutex );
1602+
1603+ root_irq_data -> parent_data = NULL ;
1604+
1605+ irq_domain_clear_mapping (domain , root_irq_data -> hwirq );
1606+ irq_domain_free_irqs_hierarchy (domain , virq , 1 );
1607+
1608+ /* Restore the original irq_data. */
1609+ * root_irq_data = * child_irq_data ;
1610+
1611+ irq_domain_fix_revmap (root_irq_data );
1612+
1613+ mutex_unlock (& irq_domain_mutex );
1614+
1615+ kfree (child_irq_data );
1616+
1617+ return 0 ;
1618+ }
1619+ EXPORT_SYMBOL_GPL (irq_domain_pop_irq );
1620+
14521621/**
14531622 * irq_domain_free_irqs - Free IRQ number and associated data structures
14541623 * @virq: base IRQ number
0 commit comments