在mbigen_device_probe->mbigen_acpi_create_domain->platform_msi_create_device_domain
domain = platform_msi_create_device_domain(&pdev->dev, num_msis,
mbigen_write_msg,
&mbigen_domain_ops,
mgn_chip);
注意在调用platform_msi_create_device_domain 的时候会传递一个mbigen_domain_ops
static struct irq_domain_ops mbigen_domain_ops = {
.translate = mbigen_domain_translate,
.alloc = mbigen_irq_domain_alloc,
.free = irq_domain_free_irqs_common,
};
随后platform_msi_create_device_domain->irq_domain_create_hierarchy->irq_domain_create_linear->__irq_domain_add
struct irq_domain *__irq_domain_add(struct fwnode_handle *fwnode, int size,
irq_hw_number_t hwirq_max, int direct_max,
const struct irq_domain_ops *ops,
void *host_data)
{
struct device_node *of_node = to_of_node(fwnode);
struct irq_domain *domain;
domain = kzalloc_node(sizeof(*domain) + (sizeof(unsigned int) * size),
GFP_KERNEL, of_node_to_nid(of_node));
if (WARN_ON(!domain))
return NULL;
of_node_get(of_node);
/* Fill structure */
INIT_RADIX_TREE(&domain->revmap_tree, GFP_KERNEL);
domain->ops = ops;
domain->host_data = host_data;
domain->fwnode = fwnode;
domain->hwirq_max = hwirq_max;
domain->revmap_size = size;
domain->revmap_direct_max_irq = direct_max;
irq_domain_check_hierarchy(domain);
mutex_lock(&irq_domain_mutex);
list_add(&domain->link, &irq_domain_list);
mutex_unlock(&irq_domain_mutex);
pr_debug("Added domain %s\n", domain->name);
return domain;
}
在__irq_domain_add 中我们会初始化一个irq_domain *domain,并将其添加到irq_domain_list,而irq_domain_list是一个全局的静态list.总结一下mbigen 这个模块走的最重要的事情就是初始化了一个irq_domain而已
那irq_domain_list 中应该包含很多domain,设备具体要用哪一个domain是在哪里决定的呢?
以下面的函数为例
int acpi_register_gsi(struct device *dev, u32 gsi, int trigger,
int polarity)
{
struct irq_fwspec fwspec;
struct acpi_device *adev = dev ? to_acpi_device(dev) : NULL;
if (adev && is_acpi_device_node(&adev->fwnode) &&
adev->interrupt_producer)
/* devices in DSDT connecting to spefic interrupt producer */
fwspec.fwnode = adev->interrupt_producer;
else if (acpi_gsi_domain_id)
/* devices connecting to gicd in default */
fwspec.fwnode = acpi_gsi_domain_id;
else {
pr_warn("GSI: No registered irqchip, giving up\n");
return -EINVAL;
}
fwspec.param[0] = gsi;
fwspec.param[1] = acpi_dev_get_irq_type(trigger, polarity);
fwspec.param_count = 2;
return irq_create_fwspec_mapping(&fwspec);
}
acpi_register_gsi 中初始化了一个irq_fwspec。
unsigned int irq_create_fwspec_mapping(struct irq_fwspec *fwspec)
{
struct irq_domain *domain;
struct irq_data *irq_data;
irq_hw_number_t hwirq;
unsigned int type = IRQ_TYPE_NONE;
int virq;
if (fwspec->fwnode) {
domain = irq_find_matching_fwspec(fwspec, DOMAIN_BUS_WIRED);
if (!domain)
domain = irq_find_matching_fwspec(fwspec, DOMAIN_BUS_ANY);
} else {
domain = irq_default_domain;
}
}
由于fwspec->fwnode 肯定不为NULL,因此调用irq_find_matching_fwspec
struct irq_domain *irq_find_matching_fwspec(struct irq_fwspec *fwspec,
enum irq_domain_bus_token bus_token)
{
struct irq_domain *h, *found = NULL;
struct fwnode_handle *fwnode = fwspec->fwnode;
int rc;
/* We might want to match the legacy controller last since
* it might potentially be set to match all interrupts in
* the absence of a device node. This isn't a problem so far
* yet though...
*
* bus_token == DOMAIN_BUS_ANY matches any domain, any other
* values must generate an exact match for the domain to be
* selected.
*/
mutex_lock(&irq_domain_mutex);
list_for_each_entry(h, &irq_domain_list, link) {
if (h->ops->select && fwspec->param_count)
rc = h->ops->select(h, fwspec, bus_token);
else if (h->ops->match)
rc = h->ops->match(h, to_of_node(fwnode), bus_token);
else
rc = ((fwnode != NULL) && (h->fwnode == fwnode) &&
((bus_token == DOMAIN_BUS_ANY) ||
(h->bus_token == bus_token)));
if (rc) {
found = h;
break;
}
}
mutex_unlock(&irq_domain_mutex);
return found;
}
在irq_find_matching_fwspec 中我们以mbigen的struct irq_domain_ops mbigen_domain_ops为例,由于mbigen_domain_ops为例的select和match函数为NULL,因此在irq_find_matching_fwspec走最后的else。由于在mbigen中初始化domain的时候并没有定义bus_token,因此h->bus_token=0,而irq_create_fwspec_mapping 中bus_token==DOMAIN_BUS_WIRED,因此else的条件也就不满足。因此如果要使用mbigen这个domain除了硬件要挂在mbigen下面外,其bus_token 应该要等于DOMAIN_BUS_ANY
domain = platform_msi_create_device_domain(&pdev->dev, num_msis,
mbigen_write_msg,
&mbigen_domain_ops,
mgn_chip);
注意在调用platform_msi_create_device_domain 的时候会传递一个mbigen_domain_ops
static struct irq_domain_ops mbigen_domain_ops = {
.translate = mbigen_domain_translate,
.alloc = mbigen_irq_domain_alloc,
.free = irq_domain_free_irqs_common,
};
随后platform_msi_create_device_domain->irq_domain_create_hierarchy->irq_domain_create_linear->__irq_domain_add
struct irq_domain *__irq_domain_add(struct fwnode_handle *fwnode, int size,
irq_hw_number_t hwirq_max, int direct_max,
const struct irq_domain_ops *ops,
void *host_data)
{
struct device_node *of_node = to_of_node(fwnode);
struct irq_domain *domain;
domain = kzalloc_node(sizeof(*domain) + (sizeof(unsigned int) * size),
GFP_KERNEL, of_node_to_nid(of_node));
if (WARN_ON(!domain))
return NULL;
of_node_get(of_node);
/* Fill structure */
INIT_RADIX_TREE(&domain->revmap_tree, GFP_KERNEL);
domain->ops = ops;
domain->host_data = host_data;
domain->fwnode = fwnode;
domain->hwirq_max = hwirq_max;
domain->revmap_size = size;
domain->revmap_direct_max_irq = direct_max;
irq_domain_check_hierarchy(domain);
mutex_lock(&irq_domain_mutex);
list_add(&domain->link, &irq_domain_list);
mutex_unlock(&irq_domain_mutex);
pr_debug("Added domain %s\n", domain->name);
return domain;
}
在__irq_domain_add 中我们会初始化一个irq_domain *domain,并将其添加到irq_domain_list,而irq_domain_list是一个全局的静态list.总结一下mbigen 这个模块走的最重要的事情就是初始化了一个irq_domain而已
那irq_domain_list 中应该包含很多domain,设备具体要用哪一个domain是在哪里决定的呢?
以下面的函数为例
int acpi_register_gsi(struct device *dev, u32 gsi, int trigger,
int polarity)
{
struct irq_fwspec fwspec;
struct acpi_device *adev = dev ? to_acpi_device(dev) : NULL;
if (adev && is_acpi_device_node(&adev->fwnode) &&
adev->interrupt_producer)
/* devices in DSDT connecting to spefic interrupt producer */
fwspec.fwnode = adev->interrupt_producer;
else if (acpi_gsi_domain_id)
/* devices connecting to gicd in default */
fwspec.fwnode = acpi_gsi_domain_id;
else {
pr_warn("GSI: No registered irqchip, giving up\n");
return -EINVAL;
}
fwspec.param[0] = gsi;
fwspec.param[1] = acpi_dev_get_irq_type(trigger, polarity);
fwspec.param_count = 2;
return irq_create_fwspec_mapping(&fwspec);
}
acpi_register_gsi 中初始化了一个irq_fwspec。
unsigned int irq_create_fwspec_mapping(struct irq_fwspec *fwspec)
{
struct irq_domain *domain;
struct irq_data *irq_data;
irq_hw_number_t hwirq;
unsigned int type = IRQ_TYPE_NONE;
int virq;
if (fwspec->fwnode) {
domain = irq_find_matching_fwspec(fwspec, DOMAIN_BUS_WIRED);
if (!domain)
domain = irq_find_matching_fwspec(fwspec, DOMAIN_BUS_ANY);
} else {
domain = irq_default_domain;
}
}
由于fwspec->fwnode 肯定不为NULL,因此调用irq_find_matching_fwspec
struct irq_domain *irq_find_matching_fwspec(struct irq_fwspec *fwspec,
enum irq_domain_bus_token bus_token)
{
struct irq_domain *h, *found = NULL;
struct fwnode_handle *fwnode = fwspec->fwnode;
int rc;
/* We might want to match the legacy controller last since
* it might potentially be set to match all interrupts in
* the absence of a device node. This isn't a problem so far
* yet though...
*
* bus_token == DOMAIN_BUS_ANY matches any domain, any other
* values must generate an exact match for the domain to be
* selected.
*/
mutex_lock(&irq_domain_mutex);
list_for_each_entry(h, &irq_domain_list, link) {
if (h->ops->select && fwspec->param_count)
rc = h->ops->select(h, fwspec, bus_token);
else if (h->ops->match)
rc = h->ops->match(h, to_of_node(fwnode), bus_token);
else
rc = ((fwnode != NULL) && (h->fwnode == fwnode) &&
((bus_token == DOMAIN_BUS_ANY) ||
(h->bus_token == bus_token)));
if (rc) {
found = h;
break;
}
}
mutex_unlock(&irq_domain_mutex);
return found;
}
在irq_find_matching_fwspec 中我们以mbigen的struct irq_domain_ops mbigen_domain_ops为例,由于mbigen_domain_ops为例的select和match函数为NULL,因此在irq_find_matching_fwspec走最后的else。由于在mbigen中初始化domain的时候并没有定义bus_token,因此h->bus_token=0,而irq_create_fwspec_mapping 中bus_token==DOMAIN_BUS_WIRED,因此else的条件也就不满足。因此如果要使用mbigen这个domain除了硬件要挂在mbigen下面外,其bus_token 应该要等于DOMAIN_BUS_ANY