mbigen

    xiaoxiao2021-03-25  64

    在acpi bus scan的时候会为name为Hisilicon MBIGEN-V2建立platform_device.因此在mbigen的初始化中只要调用platform_driver_register 即可。code如下: static __init int mbigen_init(void) {     return platform_driver_register(&mbigen_platform_driver); } arch_initcall(mbigen_init); static struct platform_driver mbigen_platform_driver = {     .driver = {         .name        = "Hisilicon MBIGEN-V2",         .of_match_table    = mbigen_of_match,         .acpi_match_table = ACPI_PTR(mbigen_acpi_match),     },     .probe            = mbigen_device_probe, }; mbigen_platform_driver 中定义了devicetree和acpi的match table,这两个table是同一个,这里可知这个driver同时support device tree和 acpi。同时也可以知道一个driver要同事support device和acpi,就要分别定义of_match_table 和 acpi_match_table. 如果match了,就调用mbigen_device_probe static int mbigen_device_probe(struct platform_device *pdev) {     struct mbigen_device *mgn_chip;     struct resource *res;     int err; //申请mbigen_device 结构体     mgn_chip = devm_kzalloc(&pdev->dev, sizeof(*mgn_chip), GFP_KERNEL);     if (!mgn_chip)         return -ENOMEM;     mgn_chip->pdev = pdev; //从dev的资源中找到类型是IORESOURCE_MEM。找到后调用devm_ioremap,就将物理地址转成虚拟地址了     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);     mgn_chip->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));     if (IS_ERR(mgn_chip->base))         return PTR_ERR(mgn_chip->base); //判断当前是采用device tree还是acpi     if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node)         err = mbigen_of_create_domain(pdev, mgn_chip);     else if (ACPI_COMPANION(&pdev->dev))         err = mbigen_acpi_create_domain(pdev, mgn_chip);     else         err = -EINVAL;     if (err) {         dev_err(&pdev->dev, "Failed to create mbi-gen@%p irqdomain", mgn_chip->base);         return err;     }     platform_set_drvdata(pdev, mgn_chip);     return 0; } 我们这里以acpi为主,就调用mbigen_acpi_create_domain static int mbigen_acpi_create_domain(struct platform_device *pdev,                      struct mbigen_device *mgn_chip) {     struct irq_domain *domain;     u32 num_msis = 0;     acpi_status status;     status = acpi_walk_resources(ACPI_HANDLE(&pdev->dev), METHOD_NAME__PRS,                      mbigen_acpi_process_resource, &num_msis);         if (ACPI_FAILURE(status) || num_msis == 0)         return -EINVAL;     domain = platform_msi_create_device_domain(&pdev->dev, num_msis,                            mbigen_write_msg,                            &mbigen_domain_ops,                            mgn_chip);     if (!domain)         return -ENOMEM;     return 0; } 在mbigen_acpi_create_domain 中调用acpi_walk_resources 遍历#define METHOD_NAME__PRS        "_PRS"。如果找到就调用 static acpi_status mbigen_acpi_process_resource(struct acpi_resource *ares,                          void *context) {     struct acpi_resource_extended_irq *ext_irq;     u32 *num_irqs = context;     switch (ares->type) {     case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:         ext_irq = &ares->data.extended_irq;         *num_irqs += ext_irq->interrupt_count;         break;     default:         break;     }     return AE_OK; } 这个函数的第二个形参context,就是acpi_walk_resources 中的num_msis。因此这里主要判断统计ACPI_RESOURCE_TYPE_EXTENDED_IRQ 类型的中断,将结果保存在num_msis中。 然后调用platform_msi_create_device_domain 来创建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, }; struct irq_domain * platform_msi_create_device_domain(struct device *dev,                   unsigned int nvec,                   irq_write_msi_msg_t write_msi_msg,                   const struct irq_domain_ops *ops,                   void *host_data) {     struct platform_msi_priv_data *data;     struct irq_domain *domain;     int err;     data = platform_msi_alloc_priv_data(dev, nvec, write_msi_msg);     if (IS_ERR(data))         return NULL; //保存host data到platform_msi_priv_data 中,这里的host data是指mgn_chip     data->host_data = host_data;     domain = irq_domain_create_hierarchy(dev->msi_domain, 0, nvec,                          dev->fwnode, ops, data);     if (!domain)         goto free_priv;     err = msi_domain_prepare_irqs(domain->parent, dev, nvec, &data->arg);     if (err)         goto free_domain;     return domain; } 在platform_msi_create_device_domain 中首先调用platform_msi_alloc_priv_data,来申请platform_msi_priv_data *data static struct platform_msi_priv_data * platform_msi_alloc_priv_data(struct device *dev, unsigned int nvec,                  irq_write_msi_msg_t write_msi_msg) {     struct platform_msi_priv_data *datap;     datap = kzalloc(sizeof(*datap), GFP_KERNEL);     if (!datap)         return ERR_PTR(-ENOMEM);     datap->devid = ida_simple_get(&platform_msi_devid_ida,                       0, 1 << DEV_ID_SHIFT, GFP_KERNEL);     if (datap->devid < 0) {         int err = datap->devid;         kfree(datap);         return ERR_PTR(err);     }     datap->write_msg = write_msi_msg;     datap->dev = dev;     return datap; } 在platform_msi_alloc_priv_data 中是要是申请platform_msi_priv_data 结构体,然后给write_msg/devid/dev 赋值. 回到platform_msi_create_device_domain然后调用 struct irq_domain *irq_domain_create_hierarchy(struct irq_domain *parent,                         unsigned int flags,                         unsigned int size,                         struct fwnode_handle *fwnode,                         const struct irq_domain_ops *ops,                         void *host_data) {     struct irq_domain *domain;     if (size)         domain = irq_domain_create_linear(fwnode, size, ops, host_data);     else         domain = irq_domain_create_tree(fwnode, ops, host_data);     if (domain) {         domain->parent = parent;         domain->flags |= flags;     }     return domain; } 这里的size就是前面的num_msis,肯定不为0.因此走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; } 这里主要是给domain 赋值,然后降到irq_domain_list中,可见所有的domain 都会在irq_domain_list。最后会打印Added domain log。可以从开机log中就可以看到有多少domain 添加到irq_domain_list 回到platform_msi_create_device_domain中继续调用msi_domain_prepare_irqs int msi_domain_prepare_irqs(struct irq_domain *domain, struct device *dev,                 int nvec, msi_alloc_info_t *arg) {     struct msi_domain_info *info = domain->host_data;     struct msi_domain_ops *ops = info->ops;     int ret;     ret = ops->msi_check(domain, info, dev);     if (ret == 0)         ret = ops->msi_prepare(domain, dev, nvec, arg);     return ret; } 这个主要调用msi_domain_ops的msi_check和msi_prepare 方法,这里的ops注意是host_data 中的,而host_data 是在platform_msi_create_device_domain中保存到data->host_data = host_data; 而host_data 中的ops是在its_pmsi_init->platform_msi_create_irq_domain->msi_create_irq_domain->msi_domain_update_dom_ops 中赋值的 static void msi_domain_update_dom_ops(struct msi_domain_info *info) {     struct msi_domain_ops *ops = info->ops;     if (ops == NULL) {         info->ops = &msi_domain_ops_default;         return;     }     if (ops->get_hwirq == NULL)         ops->get_hwirq = msi_domain_ops_default.get_hwirq;     if (ops->msi_init == NULL)         ops->msi_init = msi_domain_ops_default.msi_init;     if (ops->msi_check == NULL)         ops->msi_check = msi_domain_ops_default.msi_check;     if (ops->msi_prepare == NULL)         ops->msi_prepare = msi_domain_ops_default.msi_prepare;     if (ops->set_desc == NULL)         ops->set_desc = msi_domain_ops_default.set_desc; } 因此在msi_domain_prepare_irqs 中调用的msi_check和msi_prepare 就是调用msi_domain_ops_default 中的方法 static int msi_domain_ops_check(struct irq_domain *domain,                 struct msi_domain_info *info,                 struct device *dev) {     return 0; } 直接返回0,因此也不用调用msi_prepare了.
    转载请注明原文地址: https://ju.6miu.com/read-38783.html

    最新回复(0)